package config

import (
	"fmt"
	"os"
)

// SecretsProvider définit l'interface pour les fournisseurs de secrets (T0037)
type SecretsProvider interface {
	GetSecret(name string) (string, error)
	IsSecret(name string) bool
}

// EnvSecretsProvider récupère les secrets depuis les variables d'environnement (T0037)
type EnvSecretsProvider struct {
	secretKeys map[string]bool
}

// NewEnvSecretsProvider crée un nouveau fournisseur de secrets depuis l'environnement
func NewEnvSecretsProvider(secretKeys []string) *EnvSecretsProvider {
	keysMap := make(map[string]bool)
	for _, key := range secretKeys {
		keysMap[key] = true
	}
	return &EnvSecretsProvider{secretKeys: keysMap}
}

// GetSecret récupère un secret depuis les variables d'environnement (T0037)
func (p *EnvSecretsProvider) GetSecret(name string) (string, error) {
	value := os.Getenv(name)
	if value == "" {
		return "", fmt.Errorf("secret %s not found", name)
	}
	return value, nil
}

// IsSecret vérifie si une clé est un secret (T0037)
func (p *EnvSecretsProvider) IsSecret(name string) bool {
	return p.secretKeys[name]
}

// MaskSecret masque un secret pour l'affichage dans les logs (T0037)
// Masque les 4 premiers et 4 derniers caractères, remplace le reste par "****"
func MaskSecret(secret string) string {
	if secret == "" {
		return ""
	}
	if len(secret) <= 8 {
		return "****"
	}
	return secret[:4] + "****" + secret[len(secret)-4:]
}

// MaskConfigValue masque une valeur si c'est un secret (T0037)
func MaskConfigValue(key, value string, provider SecretsProvider) string {
	if provider != nil && provider.IsSecret(key) {
		return MaskSecret(value)
	}
	return value
}

// DefaultSecretKeys retourne la liste des clés considérées comme secrets (T0037)
// MOD-P0-002: Always mask secrets in logs, even in DEBUG mode
// BE-SEC-014: Comprehensive list of all secret keys
func DefaultSecretKeys() []string {
	return []string{
		"JWT_SECRET",
		"CHAT_JWT_SECRET",
		"DB_PASSWORD",
		"DATABASE_PASSWORD",
		"DATABASE_URL", // Contains password in connection string
		"REDIS_PASSWORD",
		"REDIS_URL",    // May contain password in connection string
		"RABBITMQ_URL", // May contain password in connection string
		"AWS_SECRET_ACCESS_KEY",
		"AWS_ACCESS_KEY_ID",
		"STRIPE_SECRET_KEY",
		"STRIPE_WEBHOOK_SECRET",
		"SMTP_PASSWORD",
		"OAUTH_CLIENT_SECRET",
		"SENTRY_DSN", // May contain sensitive information
	}
}

// RequiredSecretKeys retourne la liste des secrets requis en production (BE-SEC-014)
func RequiredSecretKeys() []string {
	return []string{
		"JWT_SECRET",
		"DATABASE_URL",
	}
}

// ValidateRequiredSecrets valide que tous les secrets requis sont présents (BE-SEC-014)
func ValidateRequiredSecrets(env string) error {
	requiredSecrets := RequiredSecretKeys()
	var missingSecrets []string

	for _, secretKey := range requiredSecrets {
		value := os.Getenv(secretKey)
		if value == "" {
			missingSecrets = append(missingSecrets, secretKey)
		}
	}

	if len(missingSecrets) > 0 {
		return fmt.Errorf("required secrets are missing: %v", missingSecrets)
	}

	// BE-SEC-014: In production, also validate RabbitMQ URL if RabbitMQ is enabled
	if env == "production" || env == "prod" {
		rabbitMQEnable := os.Getenv("RABBITMQ_ENABLE")
		if rabbitMQEnable != "false" {
			rabbitMQURL := os.Getenv("RABBITMQ_URL")
			if rabbitMQURL == "" {
				return fmt.Errorf("RABBITMQ_URL is required in production when RabbitMQ is enabled")
			}
		}
	}

	return nil
}
