package middleware

import (
	"fmt"
	"strings"

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

// ValidateCORSConfiguration valide la configuration CORS pour éviter les problèmes de sécurité
// INT-018: Amélioration de la validation CORS pour la production
// - En production: retourne une erreur si wildcard est utilisé ou si CORS est vide
// - En développement: log un warning mais ne bloque pas
func ValidateCORSConfiguration(allowedOrigins []string, environment string, logger *zap.Logger) error {
	hasWildcard := false
	weakOrigins := []string{}

	for _, origin := range allowedOrigins {
		// Détecter les wildcards
		if origin == "*" || strings.Contains(origin, "*") {
			hasWildcard = true
			weakOrigins = append(weakOrigins, origin)
		}
	}

	// INT-018: Validation stricte en production
	if environment == "production" {
		// 1. CORS ne doit pas être vide en production
		if len(allowedOrigins) == 0 {
			errMsg := "CORS_ALLOWED_ORIGINS is required in production environment. Empty CORS origins will reject all CORS requests, making the service inaccessible from frontend"
			if logger != nil {
				logger.Error(errMsg,
					zap.String("environment", environment),
					zap.String("recommendation", "Set CORS_ALLOWED_ORIGINS with explicit origins (e.g., CORS_ALLOWED_ORIGINS=https://app.veza.com,https://www.veza.com)"),
				)
			}
			return fmt.Errorf("%s. Please set CORS_ALLOWED_ORIGINS with explicit origins", errMsg)
		}

		// 2. CORS ne doit pas contenir de wildcard en production
		// CORS spec: credentials=true ne peut pas être utilisé avec Access-Control-Allow-Origin: *
		// C'est une faille de sécurité car cela permettrait à n'importe quel site d'accéder aux credentials
		if hasWildcard {
			errMsg := fmt.Sprintf(
				"CORS wildcard origins (%v) are not allowed in production environment with credentials=true. "+
					"This violates CORS specification and is a security risk. "+
					"Use specific origins instead of wildcards.",
				weakOrigins,
			)

			if logger != nil {
				logger.Error(errMsg,
					zap.Strings("weak_origins", weakOrigins),
					zap.String("environment", environment),
					zap.String("recommendation", "Use specific origins instead of wildcards (e.g., CORS_ALLOWED_ORIGINS=https://app.veza.com,https://www.veza.com)"),
				)
			}

			return fmt.Errorf("%s", errMsg)
		}
	} else {
		// INT-018: En développement/staging, log un warning mais ne bloque pas
		if hasWildcard {
			warningMsg := fmt.Sprintf(
				"SECURITY WARNING: CORS configuration allows wildcard origins (%v) with credentials=true. "+
					"This is insecure and violates CORS specification. "+
					"Use specific origins instead of wildcards when credentials=true. "+
					"This will cause startup failure in production.",
				weakOrigins,
			)

			if logger != nil {
				logger.Warn(warningMsg,
					zap.Strings("weak_origins", weakOrigins),
					zap.String("environment", environment),
					zap.String("recommendation", "Use specific origins instead of wildcards for production"),
				)
			} else {
				// Fallback si logger n'est pas disponible
				fmt.Printf("⚠️  %s\n", warningMsg)
			}
		}
	}

	return nil
}

// CORS middleware pour gérer les en-têtes CORS avec whitelist d'origins configurable
// allowedOrigins: liste des origines autorisées (ex: []string{"http://localhost:3000", "https://example.com"})
// Si "*" est dans la liste, toutes les origines sont autorisées
// ATTENTION: L'utilisation de "*" avec credentials=true est interdite par la spec CORS
func CORS(allowedOrigins []string) gin.HandlerFunc {
	return func(c *gin.Context) {
		origin := c.GetHeader("Origin")

		// Vérifier si l'origine est autorisée
		if isAllowedOrigin(origin, allowedOrigins) {
			c.Header("Access-Control-Allow-Origin", origin)
		}

		c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
		c.Header("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Requested-With, X-CSRF-Token")
		c.Header("Access-Control-Allow-Credentials", "true")
		c.Header("Access-Control-Expose-Headers", "X-CSRF-Token, X-Request-ID, Content-Range")
		c.Header("Access-Control-Max-Age", "86400") // Cache preflight pour 24h

		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(204)
			return
		}

		c.Next()
	}
}

// isAllowedOrigin vérifie si une origine est dans la liste des origines autorisées
func isAllowedOrigin(origin string, allowed []string) bool {
	// Sécurité par défaut : si liste vide, on rejette tout
	if len(allowed) == 0 {
		return false
	}

	for _, o := range allowed {
		// Permettre toutes les origines si "*" est dans la liste
		// ATTENTION: À utiliser seulement en dev
		if o == "*" {
			return true
		}
		if o == origin {
			return true
		}
	}
	return false
}

// CORSDefault crée un middleware CORS avec une whitelist par défaut
// Utile pour compatibilité avec le code existant
func CORSDefault() gin.HandlerFunc {
	return CORS([]string{"*"})
}
