package config

import (
	"sync"
	"time"

	"veza-backend-api/internal/logging"
	"veza-backend-api/internal/middleware"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

// Reloadable représente une configuration qui peut être rechargée (T0034)
type Reloadable interface {
	Reload() error
}

// ConfigReloader gère le rechargement de configurations à chaud (T0034)
type ConfigReloader struct {
	mu                sync.RWMutex
	config            *Config
	logger            *zap.Logger
	loggingService    *logging.Logger // Service de logging pour changement de niveau dynamique
	simpleRateLimiter *middleware.SimpleRateLimiter
}

// NewConfigReloader crée un nouveau ConfigReloader (T0034)
func NewConfigReloader(config *Config, logger *zap.Logger) *ConfigReloader {
	return &ConfigReloader{
		config:            config,
		logger:            logger,
		loggingService:    nil, // Sera initialisé lors du premier reload si nécessaire
		simpleRateLimiter: config.SimpleRateLimiter,
	}
}

// SetLoggingService définit le service de logging pour permettre le changement dynamique de niveau
func (r *ConfigReloader) SetLoggingService(loggingService *logging.Logger) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.loggingService = loggingService
}

// ReloadLogLevel recharge le niveau de log depuis les variables d'environnement (T0034)
func (r *ConfigReloader) ReloadLogLevel() error {
	r.mu.Lock()
	defer r.mu.Unlock()

	// Récupérer le nouveau niveau depuis les variables d'environnement
	newLevelStr := getEnv("LOG_LEVEL", "INFO")
	if newLevelStr == "" {
		newLevelStr = "INFO"
	}

	// Parser le niveau
	level, err := zapcore.ParseLevel(newLevelStr)
	if err != nil {
		level = zapcore.InfoLevel
	}

	// Si le logger zap est accessible directement et utilise AtomicLevel
	// On peut changer le niveau dynamiquement
	if r.config.Logger != nil {
		// Essayer de changer le niveau via l'AtomicLevel si disponible
		// Note: Le logger zap doit être créé avec AtomicLevel pour permettre le changement dynamique
		// Pour l'instant, on log juste le changement et on met à jour la config
		r.config.LogLevel = newLevelStr
		r.logger.Info("Log level reloaded from environment",
			zap.String("old_level", r.config.LogLevel),
			zap.String("new_level", newLevelStr),
			zap.String("parsed_level", level.String()),
		)
	}

	return nil
}

// ReloadRateLimits recharge les limites de rate limiting depuis les variables d'environnement (T0034)
func (r *ConfigReloader) ReloadRateLimits() error {
	r.mu.Lock()
	defer r.mu.Unlock()

	// Récupérer les nouvelles limites depuis les variables d'environnement
	newLimit := getEnvInt("RATE_LIMIT_LIMIT", 100)
	newWindowSeconds := getEnvInt("RATE_LIMIT_WINDOW", 60)
	newWindow := time.Duration(newWindowSeconds) * time.Second

	// Si le simple rate limiter existe, mettre à jour ses limites
	if r.simpleRateLimiter != nil {
		// Mettre à jour les limites directement dans le rate limiter
		r.simpleRateLimiter.UpdateLimits(newLimit, newWindow)

		// Mettre à jour la config
		r.config.RateLimitLimit = newLimit
		r.config.RateLimitWindow = newWindowSeconds

		r.logger.Info("Rate limits reloaded from environment",
			zap.Int("new_limit", newLimit),
			zap.Int("new_window_seconds", newWindowSeconds),
		)
	}

	return nil
}

// ReloadAll recharge toutes les configurations reloadable (T0034)
func (r *ConfigReloader) ReloadAll() error {
	var errors []error

	// Recharger le niveau de log
	if err := r.ReloadLogLevel(); err != nil {
		errors = append(errors, err)
	}

	// Recharger les limites de rate limiting
	if err := r.ReloadRateLimits(); err != nil {
		errors = append(errors, err)
	}

	if len(errors) > 0 {
		r.logger.Error("Some configurations failed to reload", zap.Int("error_count", len(errors)))
		return errors[0] // Retourner la première erreur
	}

	r.logger.Info("All configurations reloaded successfully")
	return nil
}

// GetCurrentConfig retourne la configuration actuelle (en lecture seule)
func (r *ConfigReloader) GetCurrentConfig() *ReloadableConfig {
	r.mu.RLock()
	defer r.mu.RUnlock()

	return &ReloadableConfig{
		LogLevel:        r.config.LogLevel,
		RateLimitLimit:  r.config.RateLimitLimit,
		RateLimitWindow: r.config.RateLimitWindow,
	}
}

// ReloadableConfig représente la partie de la configuration qui peut être rechargée
type ReloadableConfig struct {
	LogLevel        string `json:"log_level"`
	RateLimitLimit  int    `json:"rate_limit_limit"`
	RateLimitWindow int    `json:"rate_limit_window"`
}

// Note: getEnv et getEnvInt sont définis dans config.go
