// Сжатие данных: gzip из стандартной библиотеки
// Запуск: go run compress_demo.go

package main

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"math"
	"strings"
)

func main() {
	fmt.Println("=== Go: сжатие данных ===")
	fmt.Println()

	// 1. Энтропия Шеннона
	fmt.Println("--- 1. Энтропия Шеннона ---")
	texts := []struct {
		s     string
		label string
	}{
		{"aaaaaaaaaa", "aaa...a"},
		{"abcdefghij", "abcdefghij"},
		{"hello world", "hello world"},
		{"aababcabcd", "aababcabcd"},
	}
	for _, t := range texts {
		h := shannonEntropy([]byte(t.s))
		fmt.Printf("  %-14s H = %.3f бит/символ\n", t.label, h)
	}
	fmt.Println()

	// 2. compress/gzip
	fmt.Println("--- 2. compress/gzip ---")
	testData := []struct {
		name string
		data string
	}{
		{"повторы", strings.Repeat("ABCD", 1000)},
		{"псевдослучайный", pseudoRandomText(4000)},
		{"нули", strings.Repeat("\x00", 4000)},
	}
	for _, td := range testData {
		original := []byte(td.data)
		compressed := gzipCompress(original)
		ratio := float64(len(compressed)) / float64(len(original)) * 100
		fmt.Printf("  %-18s: %5d -> %5d байт (%.1f%%)\n",
			td.name, len(original), len(compressed), ratio)
	}
	fmt.Println()

	// 3. Уровни сжатия
	fmt.Println("--- 3. Уровни сжатия ---")
	data := []byte(strings.Repeat("Hello, World! ", 500))
	levels := []struct {
		name  string
		level int
	}{
		{"BestSpeed (1)", gzip.BestSpeed},
		{"Default (6)", gzip.DefaultCompression},
		{"BestCompression (9)", gzip.BestCompression},
	}
	for _, l := range levels {
		compressed := gzipCompressLevel(data, l.level)
		ratio := float64(len(compressed)) / float64(len(data)) * 100
		fmt.Printf("  %-22s: %d -> %d (%.1f%%)\n",
			l.name, len(data), len(compressed), ratio)
	}
	fmt.Println()

	// 4. Алгоритмы
	fmt.Println("--- 4. Алгоритмы ---")
	fmt.Println("  DEFLATE (1996): LZ77 + Huffman. Основа gzip, ZIP, PNG.")
	fmt.Println("  zstd (2016):    3-5x быстрее gzip при лучшем сжатии.")
	fmt.Println("  Brotli (2015):  для веба, статический словарь HTML/CSS/JS.")
	fmt.Println("  LZ4 (2011):     декомпрессия ~4 ГБ/с. Для real-time.")

	fmt.Println("\n--- 5. Go stdlib ---")
	fmt.Println("  compress/gzip, compress/zlib, compress/flate")
	fmt.Println("  compress/lzw (для GIF, TIFF)")
	fmt.Println("  Для zstd и brotli — сторонние пакеты.")

	fmt.Println("\n--- Итог ---")
	fmt.Println("Энтропия — теоретический предел сжатия")
	fmt.Println("gzip (DEFLATE) — стандарт уже 30 лет")
	fmt.Println("zstd — замена gzip: быстрее при лучшем сжатии")
}

func shannonEntropy(data []byte) float64 {
	var freq [256]int
	for _, b := range data {
		freq[b]++
	}
	n := float64(len(data))
	h := 0.0
	for _, f := range freq {
		if f > 0 {
			p := float64(f) / n
			h -= p * math.Log2(p)
		}
	}
	return h
}

func gzipCompress(data []byte) []byte {
	var buf bytes.Buffer
	w := gzip.NewWriter(&buf)
	w.Write(data)
	w.Close()
	return buf.Bytes()
}

func gzipCompressLevel(data []byte, level int) []byte {
	var buf bytes.Buffer
	w, _ := gzip.NewWriterLevel(&buf, level)
	w.Write(data)
	w.Close()
	return buf.Bytes()
}

func pseudoRandomText(n int) string {
	var b strings.Builder
	for i := 0; i < n; i++ {
		b.WriteByte(byte(33 + (i*7+13)%94))
	}
	return b.String()
}
