package middleware

import (
	"os"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

// RequestLogger middleware pour logger les requêtes HTTP avec contexte structuré
func RequestLogger(logger *zap.Logger) gin.HandlerFunc {
	return func(c *gin.Context) {
		// Début de la requête
		start := time.Now()
		path := c.Request.URL.Path
		query := c.Request.URL.RawQuery

		// Traiter la requête
		c.Next()

		// Calculer la durée
		latency := time.Since(start)

		// Récupérer le request ID si présent
		requestID, exists := c.Get("request_id")
		if !exists {
			requestID = ""
		}

		// Récupérer l'user ID si présent (après authentification)
		userID, exists := c.Get("user_id")
		if !exists {
			userID = nil
		}

		// Préparer les champs structurés
		fields := []zap.Field{
			zap.Int("status", c.Writer.Status()),
			zap.String("method", c.Request.Method),
			zap.String("path", path),
			zap.String("query", query),
			zap.String("ip", c.ClientIP()),
			zap.String("user_agent", c.Request.UserAgent()),
			zap.Duration("latency", latency),
			zap.Int("body_size", c.Writer.Size()),
		}

		// Ajouter request ID si présent
		if requestID != "" {
			fields = append(fields, zap.String("request_id", requestID.(string)))
		}

		// Ajouter user ID si présent
		if userID != nil {
			fields = append(fields, zap.Any("user_id", userID))
		}

		// Ajouter le trace_id au logger si disponible (T0025)
		if traceID := GetTraceID(c); traceID != "" {
			fields = append(fields, zap.String("trace_id", traceID))
		}

		// Ajouter le span_id au logger si disponible (T0025)
		if spanID := GetSpanID(c); spanID != "" {
			fields = append(fields, zap.String("span_id", spanID))
		}

		// Ajouter les erreurs s'il y en a
		if len(c.Errors) > 0 {
			fields = append(fields, zap.Strings("errors", c.Errors.Errors()))
		}

		// FIX #9: Détecter les requêtes lentes avec seuil configurable
		// Seuil par défaut: 1 seconde (configurable via SLOW_REQUEST_THRESHOLD_MS)
		slowThresholdMs := getEnvInt("SLOW_REQUEST_THRESHOLD_MS", 1000) // 1000ms = 1s par défaut
		slowThreshold := time.Duration(slowThresholdMs) * time.Millisecond
		isSlowRequest := latency > slowThreshold

		// Logger selon le status code et la latence
		if c.Writer.Status() >= 500 {
			// Erreurs serveur
			logger.Error("Request completed", fields...)
		} else if c.Writer.Status() >= 400 {
			// Erreurs client
			logger.Warn("Request completed with error", fields...)
		} else if isSlowRequest {
			// FIX #9: Requêtes lentes (succès mais > seuil)
			logger.Warn("Slow request detected",
				append(fields,
					zap.Duration("slow_threshold", slowThreshold),
					zap.Bool("is_slow", true),
				)...,
			)
		} else {
			// Succès normal
			logger.Info("Request completed", fields...)
		}
	}
}

// getEnvInt récupère une variable d'environnement entière avec une valeur par défaut
// FIX #9: Helper pour lire SLOW_REQUEST_THRESHOLD_MS
func getEnvInt(key string, defaultValue int) int {
	value := os.Getenv(key)
	if value == "" {
		return defaultValue
	}
	if intValue, err := strconv.Atoi(value); err == nil {
		return intValue
	}
	return defaultValue
}
