use super::job::{TranscodingJob, JobStatus};
use crate::transcoding::ffmpeg::command_builder::FfmpegCommandBuilder;
use std::time::Duration;
use tokio::time::timeout;

/// Temps maximum d'exécution d'un transcodage (5 minutes)
const JOB_TIMEOUT: Duration = Duration::from_secs(300);

pub struct TranscodingWorker {
    id: usize,
}

impl TranscodingWorker {
    pub fn new(id: usize) -> Self {
        Self { id }
    }

    /// Traite un job de bout en bout
    pub async fn process(&self, mut job: TranscodingJob) -> TranscodingJob {
        tracing::info!("Worker {} start job {} (Priority: {:?})", self.id, job.id, job.priority);
        
        job.mark_started();

        // 1. Construction de la commande
        // Le manifest HLS sera index.m3u8 dans le répertoire de sortie
        let manifest_path = job.output_dir.join("index.m3u8");
        
        let builder = FfmpegCommandBuilder::new()
            .input(&job.input_path)
            .output(&manifest_path)
            .audio_codec(job.target_profile.codec)
            .bitrate(job.target_profile.bitrate)
            .sample_rate(job.target_profile.sample_rate)
            .channels(job.target_profile.channels)
            .container(job.target_profile.container);
            
        // Add HLS specific config if needed
        let builder = if let Some(hls_time) = job.target_profile.hls_segment_time {
             builder.hls_time(hls_time)
        } else {
            builder.hls_time(6) // Default 6 seconds
        };

        // Créer le répertoire de sortie s'il n'existe pas
        if let Err(e) = tokio::fs::create_dir_all(&job.output_dir).await {
            tracing::error!("Worker {} failed to create output dir for job {}: {}", self.id, job.id, e);
            job.mark_failed(format!("Failed to create output directory: {}", e));
            return job;
        }

        let mut command = match builder.build() {
            Ok(cmd) => cmd,
            Err(e) => {
                tracing::error!("Worker {} failed to build command for job {}: {}", self.id, job.id, e);
                job.mark_failed(format!("Command build error: {}", e));
                return job;
            }
        };

        // 2. Exécution avec Timeout et gestion du kill
        // On utilise spawn() pour avoir accès au child process et pouvoir le tuer
        let mut child = match command.spawn() {
            Ok(child) => child,
            Err(e) => {
                let err_msg = format!("Failed to spawn FFmpeg process: {}", e);
                tracing::error!("Worker {} job {} spawn error: {}", self.id, job.id, err_msg);
                job.mark_failed(err_msg);
                return job;
            }
        };

        // Attendre la fin du processus avec timeout
        let result = timeout(JOB_TIMEOUT, child.wait()).await;

        match result {
            Ok(Ok(status)) => {
                if status.success() {
                    // Vérifier que le manifest HLS a été généré
                    let manifest_path = job.output_dir.join("index.m3u8");
                    if !manifest_path.exists() {
                        // Essayer avec playlist.m3u8 (nom alternatif)
                        let alt_manifest = job.output_dir.join("playlist.m3u8");
                        if alt_manifest.exists() {
                            // Renommer si nécessaire
                            if let Err(e) = tokio::fs::rename(&alt_manifest, &manifest_path).await {
                                tracing::warn!("Worker {} failed to rename playlist.m3u8 to index.m3u8: {}", self.id, e);
                            }
                        } else {
                            let err_msg = "HLS manifest not generated".to_string();
                            tracing::error!("Worker {} job {} failed: {}", self.id, job.id, err_msg);
                            job.mark_failed(err_msg);
                            return job;
                        }
                    }
                    tracing::info!("Worker {} completed job {}", self.id, job.id);
                    job.mark_completed();
                } else {
                    let err_msg = format!("FFmpeg exited with status: {}", status);
                    tracing::error!("Worker {} job {} failed: {}", self.id, job.id, err_msg);
                    job.mark_failed(err_msg);
                }
            }
            Ok(Err(e)) => {
                let err_msg = format!("IO Error execution: {}", e);
                tracing::error!("Worker {} job {} IO error: {}", self.id, job.id, err_msg);
                job.mark_failed(err_msg);
            }
            Err(_) => {
                // Timeout: tuer le processus FFmpeg
                tracing::warn!("Worker {} job {} timed out, killing FFmpeg process", self.id, job.id);
                let _ = child.kill().await;
                let err_msg = format!("Transcoding timed out after {} seconds", JOB_TIMEOUT.as_secs());
                tracing::error!("Worker {} job {} timed out", self.id, job.id);
                job.mark_failed(err_msg);
            }
        }

        // 3. Retry Logic (Simplified)
        if let JobStatus::Failed(_) = job.status {
            if job.can_retry(3) {
                tracing::warn!("Worker {} marking job {} for retry", self.id, job.id);
                job.retry_count += 1;
                job.status = JobStatus::Pending; // Caller should requeue
            }
        }

        job
    }
}
