package middleware

import (
	"compress/gzip"
	"strings"

	"github.com/gin-gonic/gin"

	"security-center-backend/internal/config"
)

type gzipWriter struct {
	gin.ResponseWriter
	writer *gzip.Writer
}

func (w *gzipWriter) Write(data []byte) (int, error) {
	return w.writer.Write(data)
}

func (w *gzipWriter) WriteString(s string) (int, error) {
	return w.writer.Write([]byte(s))
}

// Gzip enables gzip compression for clients that send Accept-Encoding: gzip.
//
// Note: we keep this intentionally simple (no streaming optimizations); it targets JSON-heavy endpoints.
func Gzip(cfg config.HTTPConfig) gin.HandlerFunc {
	if !cfg.GzipEnabled {
		return func(c *gin.Context) { c.Next() }
	}

	level := cfg.GzipLevel
	if level < gzip.HuffmanOnly || level > gzip.BestCompression {
		level = 5
	}

	return func(c *gin.Context) {
		// Skip methods where compression is unlikely to help.
		switch c.Request.Method {
		case "HEAD", "OPTIONS":
			c.Next()
			return
		}

		accept := c.GetHeader("Accept-Encoding")
		if !strings.Contains(accept, "gzip") {
			c.Next()
			return
		}
		// Skip upgraded connections (e.g., websockets).
		if strings.Contains(strings.ToLower(c.GetHeader("Connection")), "upgrade") {
			c.Next()
			return
		}

		gzw, err := gzip.NewWriterLevel(c.Writer, level)
		if err != nil {
			c.Next()
			return
		}
		defer func() {
			_ = gzw.Close()
		}()

		c.Header("Content-Encoding", "gzip")
		c.Header("Vary", "Accept-Encoding")
		c.Writer.Header().Del("Content-Length")

		c.Writer = &gzipWriter{ResponseWriter: c.Writer, writer: gzw}
		c.Next()
	}
}
