package services

import (
	"go.uber.org/zap"
)

// BitrateStrategy représente une stratégie d'adaptation de bitrate
// T0361: Create Bitrate Adaptation Strategy Service
type BitrateStrategy string

const (
	// StrategyConservative est une stratégie conservatrice qui adapte le bitrate
	// seulement quand les conditions sont vraiment défavorables
	StrategyConservative BitrateStrategy = "conservative"

	// StrategyAggressive est une stratégie agressive qui adapte le bitrate
	// rapidement pour éviter les problèmes de streaming
	StrategyAggressive BitrateStrategy = "aggressive"

	// StrategyBalanced est une stratégie équilibrée entre conservative et aggressive
	StrategyBalanced BitrateStrategy = "balanced"
)

// StrategyThresholds représente les seuils pour une stratégie
type StrategyThresholds struct {
	BufferLevelThreshold    float64 // Seuil de niveau de buffer (0.0 à 1.0)
	BandwidthRatioThreshold float64 // Seuil de ratio de bande passante (0.0 à 1.0)
	UseOrCondition          bool    // Si true, utilise OR au lieu de AND
}

// BitrateStrategyService gère les stratégies d'adaptation de bitrate
type BitrateStrategyService struct {
	logger *zap.Logger
}

// NewBitrateStrategyService crée un nouveau service de stratégies d'adaptation
func NewBitrateStrategyService(logger *zap.Logger) *BitrateStrategyService {
	if logger == nil {
		logger = zap.NewNop()
	}
	return &BitrateStrategyService{
		logger: logger,
	}
}

// GetThresholds retourne les seuils pour une stratégie donnée
func (s *BitrateStrategyService) GetThresholds(strategy BitrateStrategy) StrategyThresholds {
	switch strategy {
	case StrategyConservative:
		// Conservative: adapte seulement si buffer ET bande passante sont faibles
		return StrategyThresholds{
			BufferLevelThreshold:    0.3,   // 30% de buffer
			BandwidthRatioThreshold: 0.7,   // 70% de la bande passante nécessaire
			UseOrCondition:          false, // Utilise AND
		}
	case StrategyAggressive:
		// Aggressive: adapte si buffer OU bande passante est faible
		return StrategyThresholds{
			BufferLevelThreshold:    0.15, // 15% de buffer
			BandwidthRatioThreshold: 0.5,  // 50% de la bande passante nécessaire
			UseOrCondition:          true, // Utilise OR
		}
	case StrategyBalanced:
		fallthrough
	default:
		// Balanced: adapte si buffer ET bande passante sont modérément faibles
		return StrategyThresholds{
			BufferLevelThreshold:    0.2,   // 20% de buffer
			BandwidthRatioThreshold: 0.6,   // 60% de la bande passante nécessaire
			UseOrCondition:          false, // Utilise AND
		}
	}
}

// ShouldAdapt détermine si une adaptation de bitrate est nécessaire
// selon la stratégie, le niveau de buffer et le ratio de bande passante
// bufferLevel: niveau de buffer (0.0 = vide, 1.0 = plein)
// bandwidthRatio: ratio de bande passante disponible / nécessaire (0.0 à 1.0+)
// Retourne true si une adaptation est nécessaire
func (s *BitrateStrategyService) ShouldAdapt(strategy BitrateStrategy, bufferLevel float64, bandwidthRatio float64) bool {
	thresholds := s.GetThresholds(strategy)

	// Valider les paramètres
	if bufferLevel < 0 || bufferLevel > 1 {
		s.logger.Warn("Invalid buffer level",
			zap.Float64("buffer_level", bufferLevel),
			zap.String("strategy", string(strategy)))
		return false
	}

	if bandwidthRatio < 0 {
		s.logger.Warn("Invalid bandwidth ratio",
			zap.Float64("bandwidth_ratio", bandwidthRatio),
			zap.String("strategy", string(strategy)))
		return false
	}

	// Vérifier si le buffer est faible
	bufferLow := bufferLevel < thresholds.BufferLevelThreshold

	// Vérifier si la bande passante est faible
	// bandwidthRatio < threshold signifie que la bande passante disponible
	// est inférieure au seuil requis
	bandwidthLow := bandwidthRatio < thresholds.BandwidthRatioThreshold

	// Appliquer la logique selon la stratégie
	if thresholds.UseOrCondition {
		// OR: adapter si buffer OU bande passante est faible
		return bufferLow || bandwidthLow
	} else {
		// AND: adapter seulement si buffer ET bande passante sont faibles
		return bufferLow && bandwidthLow
	}
}

// SelectStrategy sélectionne une stratégie selon le contexte
// networkStability: stabilité du réseau (0.0 = instable, 1.0 = stable)
// userPreference: préférence de l'utilisateur (peut être nil pour auto)
// Retourne la stratégie recommandée
func (s *BitrateStrategyService) SelectStrategy(networkStability float64, userPreference *BitrateStrategy) BitrateStrategy {
	// Si l'utilisateur a une préférence, l'utiliser
	if userPreference != nil {
		return *userPreference
	}

	// Sélectionner automatiquement selon la stabilité du réseau
	if networkStability < 0.3 {
		// Réseau instable: utiliser une stratégie conservative
		return StrategyConservative
	} else if networkStability > 0.7 {
		// Réseau stable: utiliser une stratégie aggressive pour meilleure qualité
		return StrategyAggressive
	} else {
		// Réseau modéré: utiliser une stratégie balanced
		return StrategyBalanced
	}
}

// IsValidStrategy vérifie si une stratégie est valide
func (s *BitrateStrategyService) IsValidStrategy(strategy BitrateStrategy) bool {
	return strategy == StrategyConservative ||
		strategy == StrategyAggressive ||
		strategy == StrategyBalanced
}
