//! Pipeline audio pour streaming
//!
//! Ce module fournit un pipeline complet de traitement audio :
//! - Décodage audio depuis différents formats
//! - Traitement audio (volume, EQ, effets)
//! - Encodage audio vers différents formats
//!
//! Le pipeline est conçu pour être utilisé dans un contexte de streaming
//! temps réel avec une latence minimale.

use crate::audio::effects::{AudioEffect, EffectsChain};
use crate::codecs::{AudioDecoder, AudioEncoder, DecodedAudio, DecoderInfo, EncoderInfo};
use crate::error::{AppError, Result as AppResult};
use std::sync::Arc;
// Note: Use tracing::info! macro directly instead of importing
use std::time::Duration;

/// Pipeline audio complet pour streaming
///
/// Le pipeline traite l'audio en trois étapes :
/// 1. Décodage : conversion des bytes encodés en échantillons audio
/// 2. Traitement : application d'effets (volume, EQ, etc.)
/// 3. Encodage : conversion des échantillons traités en bytes encodés
pub struct AudioPipeline {
    decoder: Box<dyn AudioDecoder>,
    processor: AudioPipelineProcessor,
    encoder: Box<dyn AudioEncoder>,
    sample_rate: u32,
    channels: u8,
}

/// Processeur de pipeline audio
///
/// Gère le traitement audio entre décodage et encodage :
/// - Ajustement du volume
/// - Application d'effets audio
/// - Normalisation
struct AudioPipelineProcessor {
    volume: f32,
    effects_chain: Option<EffectsChain>,
    normalize: bool,
}

impl AudioPipelineProcessor {
    /// Crée un nouveau processeur de pipeline
    fn new() -> Self {
        Self {
            volume: 1.0,
            effects_chain: None,
            normalize: false,
        }
    }

    /// Traite un buffer audio
    fn process(&mut self, samples: &mut [f32], sample_rate: u32, channels: u8) -> AppResult<()> {
        // Ajuster le volume
        if self.volume != 1.0 {
            for sample in samples.iter_mut() {
                *sample *= self.volume;
            }
        }

        // Appliquer les effets si configurés
        if let Some(ref mut effects) = self.effects_chain {
            // Utiliser la méthode process de EffectsChain
            effects.process(samples, sample_rate, channels)?;
            tracing::debug!(
                "Application d'effets audio sur {} échantillons",
                samples.len()
            );
        }

        // Normalisation si activée
        if self.normalize {
            self.normalize_samples(samples);
        }

        Ok(())
    }

    /// Normalise les échantillons pour éviter le clipping
    fn normalize_samples(&self, samples: &mut [f32]) {
        // Trouver le pic maximum
        let max_amplitude = samples
            .iter()
            .map(|s| s.abs())
            .fold(0.0f32, |a, b| a.max(b));

        // Si le pic est trop élevé (> 0.95), réduire le gain
        if max_amplitude > 0.95 {
            let gain = 0.95 / max_amplitude;
            for sample in samples.iter_mut() {
                *sample *= gain;
            }
        }
    }

    /// Définit le volume (0.0 à 1.0)
    fn set_volume(&mut self, volume: f32) {
        self.volume = volume.max(0.0).min(1.0);
    }

    /// Ajoute une chaîne d'effets
    fn set_effects_chain(&mut self, effects: EffectsChain) {
        self.effects_chain = Some(effects);
    }

    /// Active ou désactive la normalisation
    fn set_normalize(&mut self, normalize: bool) {
        self.normalize = normalize;
    }
}

impl AudioPipeline {
    /// Crée un nouveau pipeline audio
    ///
    /// # Arguments
    ///
    /// * `decoder` - Décodeur audio pour décoder les données d'entrée
    /// * `encoder` - Encodeur audio pour encoder les données de sortie
    /// * `sample_rate` - Taux d'échantillonnage (Hz)
    /// * `channels` - Nombre de canaux (1 = mono, 2 = stéréo)
    pub fn new(
        decoder: Box<dyn AudioDecoder>,
        encoder: Box<dyn AudioEncoder>,
        sample_rate: u32,
        channels: u8,
    ) -> Self {
        tracing::info!(
            "🎵 Création d'un pipeline audio: {} Hz, {} canaux",
            sample_rate,
            channels
        );

        Self {
            decoder,
            processor: AudioPipelineProcessor::new(),
            encoder,
            sample_rate,
            channels,
        }
    }

    /// Traite un buffer audio encodé
    ///
    /// Le pipeline effectue les opérations suivantes :
    /// 1. Décode les bytes d'entrée en échantillons audio
    /// 2. Traite les échantillons (volume, effets, normalisation)
    /// 3. Encode les échantillons traités en bytes de sortie
    ///
    /// # Arguments
    ///
    /// * `input` - Données audio encodées en entrée
    ///
    /// # Returns
    ///
    /// Données audio encodées en sortie après traitement
    pub async fn process(&mut self, input: &[u8]) -> AppResult<Vec<u8>> {
        if input.is_empty() {
            return Ok(Vec::new());
        }

        // Étape 1: Décodage
        let decoded = self.decoder.decode(input)?;
        tracing::debug!(
            "✅ Audio décodé: {} échantillons, {} Hz, {} canaux",
            decoded.samples.len(),
            decoded.sample_rate,
            decoded.channels
        );

        // Convertir les échantillons en Vec<f32> mutable pour le traitement
        let mut samples = decoded.samples;

        // Étape 2: Traitement
        self.processor
            .process(&mut samples, decoded.sample_rate, decoded.channels)?;
        tracing::debug!("✅ Audio traité: {} échantillons", samples.len());

        // Étape 3: Encodage
        let encoded = self
            .encoder
            .encode(&samples, decoded.sample_rate, decoded.channels)?;
        tracing::debug!("✅ Audio encodé: {} bytes", encoded.len());

        Ok(encoded)
    }

    /// Traite un stream audio complet
    ///
    /// Traite plusieurs buffers audio de manière séquentielle et retourne
    /// tous les buffers encodés concaténés.
    ///
    /// # Arguments
    ///
    /// * `input_chunks` - Iterator sur les chunks audio encodés
    ///
    /// # Returns
    ///
    /// Tous les buffers encodés concaténés
    pub async fn process_stream<I>(&mut self, input_chunks: I) -> AppResult<Vec<u8>>
    where
        I: Iterator<Item = Vec<u8>>,
    {
        let mut output = Vec::new();
        let mut chunk_count = 0;

        for chunk in input_chunks {
            let processed = self.process(&chunk).await?;
            output.extend_from_slice(&processed);
            chunk_count += 1;
        }

        // Finaliser l'encodage
        let final_bytes = self.encoder.finalize()?;
        output.extend_from_slice(&final_bytes);

        tracing::info!(
            "✅ Stream traité: {} chunks, {} bytes totaux",
            chunk_count,
            output.len()
        );

        Ok(output)
    }

    /// Définit le volume de traitement (0.0 à 1.0)
    pub fn set_volume(&mut self, volume: f32) {
        self.processor.set_volume(volume);
        tracing::debug!("🔊 Volume défini à {:.2}", volume);
    }

    /// Ajoute une chaîne d'effets audio
    pub fn set_effects_chain(&mut self, effects: EffectsChain) {
        self.processor.set_effects_chain(effects);
        tracing::info!("🎛️ Chaîne d'effets configurée");
    }

    /// Active ou désactive la normalisation
    pub fn set_normalize(&mut self, normalize: bool) {
        self.processor.set_normalize(normalize);
        tracing::debug!(
            "🎚️ Normalisation {}",
            if normalize {
                "activée"
            } else {
                "désactivée"
            }
        );
    }

    /// Obtient les informations du décodeur
    pub fn decoder_info(&self) -> DecoderInfo {
        self.decoder.info()
    }

    /// Obtient les informations de l'encodeur
    pub fn encoder_info(&self) -> EncoderInfo {
        self.encoder.info()
    }

    /// Réinitialise le pipeline
    ///
    /// Réinitialise le décodeur et l'encodeur pour un nouveau traitement
    pub fn reset(&mut self) -> AppResult<()> {
        self.decoder.reset()?;
        self.encoder.reset()?;
        tracing::info!("🔄 Pipeline réinitialisé");
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::codecs::{
        AudioDecoder, AudioEncoder, DecodedAudio, DecoderInfo, EncoderInfo, EncoderMetrics,
    };

    // Décodeur mock pour les tests
    #[derive(Debug)]
    struct MockDecoder {
        sample_rate: u32,
        channels: u8,
    }

    impl AudioDecoder for MockDecoder {
        fn decode(&mut self, _data: &[u8]) -> AppResult<DecodedAudio> {
            // Simuler le décodage avec des échantillons de test
            Ok(DecodedAudio {
                samples: vec![0.0, 0.5, 1.0, -0.5, 0.0],
                sample_rate: self.sample_rate,
                channels: self.channels,
                duration_ms: 100,
                format: crate::codecs::AudioSampleFormat::F32,
            })
        }

        fn reset(&mut self) -> AppResult<()> {
            Ok(())
        }

        fn info(&self) -> DecoderInfo {
            DecoderInfo {
                codec_name: "mock".to_string(),
                version: "1.0".to_string(),
                sample_rate: self.sample_rate,
                channels: self.channels,
                bit_depth: 32,
                frame_size: 1024,
            }
        }
    }

    // Encodeur mock pour les tests
    #[derive(Debug)]
    struct MockEncoder {
        sample_rate: u32,
        channels: u8,
    }

    impl AudioEncoder for MockEncoder {
        fn encode(
            &mut self,
            samples: &[f32],
            _sample_rate: u32,
            _channels: u8,
        ) -> AppResult<Vec<u8>> {
            // Simuler l'encodage
            Ok(samples.iter().map(|s| (*s * 127.0) as u8).collect())
        }

        fn finalize(&mut self) -> AppResult<Vec<u8>> {
            Ok(Vec::new())
        }

        fn reset(&mut self) -> AppResult<()> {
            Ok(())
        }

        fn set_bitrate(&mut self, _bitrate: u32) -> AppResult<()> {
            Ok(())
        }

        fn info(&self) -> EncoderInfo {
            EncoderInfo {
                codec_name: "mock".to_string(),
                version: "1.0".to_string(),
                bitrate: 128000,
                sample_rate: self.sample_rate,
                channels: self.channels,
                bit_depth: 32,
                frame_size: 1024,
                latency_ms: 0.0,
                quality_mode: "standard".to_string(),
            }
        }

        fn metrics(&self) -> EncoderMetrics {
            EncoderMetrics::default()
        }
    }

    #[tokio::test]
    async fn test_pipeline_creation() {
        let decoder = Box::new(MockDecoder {
            sample_rate: 44100,
            channels: 2,
        });
        let encoder = Box::new(MockEncoder {
            sample_rate: 44100,
            channels: 2,
        });

        let pipeline = AudioPipeline::new(decoder, encoder, 44100, 2);
        assert_eq!(pipeline.sample_rate, 44100);
        assert_eq!(pipeline.channels, 2);
    }

    #[tokio::test]
    async fn test_pipeline_process() {
        let decoder = Box::new(MockDecoder {
            sample_rate: 44100,
            channels: 2,
        });
        let encoder = Box::new(MockEncoder {
            sample_rate: 44100,
            channels: 2,
        });

        let mut pipeline = AudioPipeline::new(decoder, encoder, 44100, 2);

        // Test avec des données d'entrée
        let input = vec![0u8; 100];
        let result = pipeline.process(&input).await;

        assert!(result.is_ok());
        let output = result.unwrap();
        assert!(!output.is_empty());
    }

    #[tokio::test]
    async fn test_pipeline_volume() {
        let decoder = Box::new(MockDecoder {
            sample_rate: 44100,
            channels: 2,
        });
        let encoder = Box::new(MockEncoder {
            sample_rate: 44100,
            channels: 2,
        });

        let mut pipeline = AudioPipeline::new(decoder, encoder, 44100, 2);

        // Définir le volume à 0.5
        pipeline.set_volume(0.5);

        // Le volume devrait être appliqué lors du traitement
        let input = vec![0u8; 100];
        let result = pipeline.process(&input).await;
        assert!(result.is_ok());
    }

    #[tokio::test]
    async fn test_pipeline_normalize() {
        let decoder = Box::new(MockDecoder {
            sample_rate: 44100,
            channels: 2,
        });
        let encoder = Box::new(MockEncoder {
            sample_rate: 44100,
            channels: 2,
        });

        let mut pipeline = AudioPipeline::new(decoder, encoder, 44100, 2);

        // Activer la normalisation
        pipeline.set_normalize(true);

        let input = vec![0u8; 100];
        let result = pipeline.process(&input).await;
        assert!(result.is_ok());
    }

    #[tokio::test]
    async fn test_pipeline_reset() {
        let decoder = Box::new(MockDecoder {
            sample_rate: 44100,
            channels: 2,
        });
        let encoder = Box::new(MockEncoder {
            sample_rate: 44100,
            channels: 2,
        });

        let mut pipeline = AudioPipeline::new(decoder, encoder, 44100, 2);

        // Le reset devrait fonctionner
        let result = pipeline.reset();
        assert!(result.is_ok());
    }

    #[tokio::test]
    async fn test_pipeline_empty_input() {
        let decoder = Box::new(MockDecoder {
            sample_rate: 44100,
            channels: 2,
        });
        let encoder = Box::new(MockEncoder {
            sample_rate: 44100,
            channels: 2,
        });

        let mut pipeline = AudioPipeline::new(decoder, encoder, 44100, 2);

        // Test avec un input vide
        let input = vec![];
        let result = pipeline.process(&input).await;
        assert!(result.is_ok());
        assert!(result.unwrap().is_empty());
    }
}
