package services

import (
	"context"
	"sync"
	"time"

	"go.uber.org/zap"
)

// BandwidthDetectionService gère la détection de bande passante réseau
// T0347: Create Network Bandwidth Detection Service
type BandwidthDetectionService struct {
	samples    []int64
	maxSamples int
	mutex      sync.RWMutex
	logger     *zap.Logger
}

// NewBandwidthDetectionService crée un nouveau service de détection de bande passante
func NewBandwidthDetectionService(logger *zap.Logger) *BandwidthDetectionService {
	if logger == nil {
		logger = zap.NewNop()
	}
	return &BandwidthDetectionService{
		samples:    make([]int64, 0, 10),
		maxSamples: 10,
		logger:     logger,
	}
}

// MeasureBandwidth mesure la bande passante en bps (bits per second)
// bytesTransferred: nombre d'octets transférés
// duration: durée du transfert
// Retourne la moyenne de bande passante en bps
func (s *BandwidthDetectionService) MeasureBandwidth(ctx context.Context, bytesTransferred int64, duration time.Duration) int64 {
	if duration <= 0 {
		s.logger.Warn("Invalid duration for bandwidth measurement", zap.Duration("duration", duration))
		return 0
	}

	if bytesTransferred < 0 {
		s.logger.Warn("Invalid bytes transferred for bandwidth measurement", zap.Int64("bytes", bytesTransferred))
		return 0
	}

	// Calculer la bande passante en bps (bits per second)
	// bytesTransferred * 8 pour convertir en bits
	// duration.Seconds() pour obtenir la durée en secondes
	seconds := duration.Seconds()
	if seconds <= 0 {
		return 0
	}

	// Utiliser float64 pour éviter les problèmes de précision avec les durées très courtes
	bandwidth := int64((float64(bytesTransferred) * 8.0) / seconds)

	s.mutex.Lock()
	defer s.mutex.Unlock()

	// Ajouter l'échantillon
	s.samples = append(s.samples, bandwidth)

	// Limiter le nombre d'échantillons
	if len(s.samples) > s.maxSamples {
		s.samples = s.samples[1:]
	}

	// Calculer et retourner la moyenne
	return s.calculateAverage()
}

// calculateAverage calcule la moyenne des échantillons de bande passante
func (s *BandwidthDetectionService) calculateAverage() int64 {
	if len(s.samples) == 0 {
		return 0
	}

	var sum int64
	for _, sample := range s.samples {
		sum += sample
	}

	return sum / int64(len(s.samples))
}

// GetAverageBandwidth retourne la moyenne actuelle de bande passante sans ajouter de nouvel échantillon
func (s *BandwidthDetectionService) GetAverageBandwidth() int64 {
	s.mutex.RLock()
	defer s.mutex.RUnlock()
	return s.calculateAverage()
}

// RecommendBitrate recommande un bitrate optimal en kbps basé sur la bande passante disponible
// bandwidth: bande passante en bps (bits per second)
// Retourne le bitrate recommandé en kbps
func (s *BandwidthDetectionService) RecommendBitrate(bandwidth int64) int {
	if bandwidth <= 0 {
		// Par défaut, retourner le bitrate le plus bas
		return 128
	}

	// Réserver 20% de buffer pour éviter les problèmes de réseau
	available := float64(bandwidth) * 0.8

	// Convertir en kbps pour la comparaison
	availableKbps := available / 1000.0

	// Recommander le bitrate le plus élevé possible selon la bande passante disponible
	// Les bitrates standards sont: 128, 192, 320 kbps
	if availableKbps >= 320 {
		return 320
	} else if availableKbps >= 192 {
		return 192
	} else if availableKbps >= 128 {
		return 128
	}

	// Si la bande passante est très faible, retourner quand même 128 kbps
	// (le client devra gérer la mise en buffer)
	return 128
}

// ClearSamples efface tous les échantillons de bande passante
func (s *BandwidthDetectionService) ClearSamples() {
	s.mutex.Lock()
	defer s.mutex.Unlock()
	s.samples = make([]int64, 0, s.maxSamples)
}

// GetSampleCount retourne le nombre d'échantillons actuels
func (s *BandwidthDetectionService) GetSampleCount() int {
	s.mutex.RLock()
	defer s.mutex.RUnlock()
	return len(s.samples)
}
