package services

import (
	"context"
	"sync"

	"go.uber.org/zap"
)

// BufferMonitorService gère le monitoring du niveau de buffer
// T0353: Create Buffer Level Monitor Service
type BufferMonitorService struct {
	logger *zap.Logger
	// Seuils de buffer (configurables)
	lowThreshold  float64 // Seuil bas (défaut: 0.2)
	highThreshold float64 // Seuil haut (défaut: 0.8)
	mutex         sync.RWMutex
}

// NewBufferMonitorService crée un nouveau service de monitoring de buffer
func NewBufferMonitorService(logger *zap.Logger) *BufferMonitorService {
	if logger == nil {
		logger = zap.NewNop()
	}
	return &BufferMonitorService{
		logger:        logger,
		lowThreshold:  0.2, // 20% - buffer faible
		highThreshold: 0.8, // 80% - buffer élevé
	}
}

// SetThresholds configure les seuils de buffer
func (s *BufferMonitorService) SetThresholds(low, high float64) {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	if low >= 0 && low <= 1 {
		s.lowThreshold = low
	}
	if high >= 0 && high <= 1 && high > s.lowThreshold {
		s.highThreshold = high
	}
}

// GetThresholds retourne les seuils actuels
func (s *BufferMonitorService) GetThresholds() (low, high float64) {
	s.mutex.RLock()
	defer s.mutex.RUnlock()
	return s.lowThreshold, s.highThreshold
}

// CalculateBufferLevel calcule le niveau de buffer (0.0 à 1.0)
// buffered: temps de contenu buffered en secondes
// duration: durée totale du contenu en secondes
// Retourne le niveau de buffer (0.0 = vide, 1.0 = plein)
func (s *BufferMonitorService) CalculateBufferLevel(buffered, duration float64) float64 {
	if duration <= 0 {
		s.logger.Warn("Invalid duration for buffer calculation", zap.Float64("duration", duration))
		return 0.0
	}

	if buffered < 0 {
		s.logger.Warn("Invalid buffered time for buffer calculation", zap.Float64("buffered", buffered))
		return 0.0
	}

	// Calculer le niveau de buffer (ratio)
	level := buffered / duration

	// S'assurer que le niveau est entre 0.0 et 1.0
	if level > 1.0 {
		level = 1.0
	} else if level < 0.0 {
		level = 0.0
	}

	return level
}

// IsBufferLow vérifie si le buffer est faible
func (s *BufferMonitorService) IsBufferLow(bufferLevel float64) bool {
	s.mutex.RLock()
	defer s.mutex.RUnlock()
	return bufferLevel < s.lowThreshold
}

// IsBufferHigh vérifie si le buffer est élevé
func (s *BufferMonitorService) IsBufferHigh(bufferLevel float64) bool {
	s.mutex.RLock()
	defer s.mutex.RUnlock()
	return bufferLevel > s.highThreshold
}

// ShouldAdaptBuffer détermine si une adaptation est nécessaire
// Retourne true si le buffer est trop faible ou trop élevé
func (s *BufferMonitorService) ShouldAdaptBuffer(bufferLevel float64) bool {
	return s.IsBufferLow(bufferLevel) || s.IsBufferHigh(bufferLevel)
}

// GetBufferStatus retourne le statut du buffer
func (s *BufferMonitorService) GetBufferStatus(bufferLevel float64) string {
	if s.IsBufferLow(bufferLevel) {
		return "low"
	} else if s.IsBufferHigh(bufferLevel) {
		return "high"
	}
	return "normal"
}

// MonitorBuffer surveille le niveau de buffer et détermine si une adaptation est nécessaire
// buffered: temps de contenu buffered en secondes
// duration: durée totale du contenu en secondes
// Retourne le niveau de buffer calculé et si une adaptation est nécessaire
func (s *BufferMonitorService) MonitorBuffer(ctx context.Context, buffered, duration float64) (bufferLevel float64, shouldAdapt bool, status string) {
	bufferLevel = s.CalculateBufferLevel(buffered, duration)
	shouldAdapt = s.ShouldAdaptBuffer(bufferLevel)
	status = s.GetBufferStatus(bufferLevel)

	if shouldAdapt {
		s.logger.Debug("Buffer adaptation needed",
			zap.Float64("buffer_level", bufferLevel),
			zap.String("status", status),
			zap.Float64("buffered", buffered),
			zap.Float64("duration", duration))
	}

	return bufferLevel, shouldAdapt, status
}
