use super::job::{TranscodingJob, JobStatus};
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use uuid::Uuid;

/// Gestionnaire de jobs de transcodage
/// Stocke l'état des jobs en mémoire et permet de les récupérer
pub struct JobManager {
    jobs: Arc<RwLock<HashMap<Uuid, TranscodingJob>>>,
}

impl JobManager {
    /// Crée un nouveau JobManager
    pub fn new() -> Self {
        Self {
            jobs: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    /// Enregistre un nouveau job
    pub async fn enqueue(&self, job: TranscodingJob) -> Uuid {
        let job_id = job.id;
        let mut jobs = self.jobs.write().await;
        jobs.insert(job_id, job);
        tracing::info!(job_id = %job_id, "Job enqueued in JobManager");
        job_id
    }

    /// Récupère l'état d'un job
    pub async fn get_status(&self, job_id: Uuid) -> Option<TranscodingJob> {
        let jobs = self.jobs.read().await;
        jobs.get(&job_id).cloned()
    }

    /// Met à jour l'état d'un job
    pub async fn update_status(&self, job_id: Uuid, new_status: JobStatus) -> Result<(), String> {
        let mut jobs = self.jobs.write().await;
        if let Some(job) = jobs.get_mut(&job_id) {
            job.status = new_status.clone();
            tracing::debug!(job_id = %job_id, status = ?new_status, "Job status updated");
            Ok(())
        } else {
            Err(format!("Job {} not found", job_id))
        }
    }

    /// Met à jour un job complet
    pub async fn update_job(&self, job: TranscodingJob) -> Result<(), String> {
        let job_id = job.id;
        let mut jobs = self.jobs.write().await;
        if jobs.contains_key(&job_id) {
            jobs.insert(job_id, job);
            tracing::debug!(job_id = %job_id, "Job updated in JobManager");
            Ok(())
        } else {
            Err(format!("Job {} not found", job_id))
        }
    }

    /// Liste tous les jobs (pour debug/admin)
    pub async fn list_jobs(&self) -> Vec<TranscodingJob> {
        let jobs = self.jobs.read().await;
        jobs.values().cloned().collect()
    }

    /// Supprime un job (cleanup)
    pub async fn remove_job(&self, job_id: Uuid) -> bool {
        let mut jobs = self.jobs.write().await;
        jobs.remove(&job_id).is_some()
    }
}

impl Default for JobManager {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::transcoding::codecs::profiles::QualityProfile;
    use crate::transcoding::pipeline::job::JobPriority;
    use std::path::PathBuf;

    #[tokio::test]
    async fn test_job_manager_enqueue() {
        let manager = JobManager::new();
        let job = TranscodingJob::new(
            "test_track".to_string(),
            PathBuf::from("/tmp/input.wav"),
            PathBuf::from("/tmp/output"),
            QualityProfile::high(),
            JobPriority::Normal,
        );

        let job_id = manager.enqueue(job).await;
        assert!(manager.get_status(job_id).await.is_some());
    }

    #[tokio::test]
    async fn test_job_manager_update_status() {
        let manager = JobManager::new();
        let job = TranscodingJob::new(
            "test_track".to_string(),
            PathBuf::from("/tmp/input.wav"),
            PathBuf::from("/tmp/output"),
            QualityProfile::high(),
            JobPriority::Normal,
        );

        let job_id = manager.enqueue(job).await;
        manager
            .update_status(job_id, JobStatus::Processing)
            .await
            .unwrap();

        let updated_job = manager.get_status(job_id).await.unwrap();
        assert!(matches!(updated_job.status, JobStatus::Processing));
    }
}

