//! FFmpeg management and execution

use std::path::{Path, PathBuf};
use std::process::Command;
use crate::core::TvaiError;

/// Manages FFmpeg installations and execution
#[derive(Debug, Clone)]
pub struct FfmpegManager {
    topaz_path: Option<PathBuf>,
    system_path: Option<PathBuf>,
    force_topaz: bool,
}

impl FfmpegManager {
    /// Create a new FFmpeg manager
    pub fn new(topaz_base_path: Option<&Path>, force_topaz: bool) -> Self {
        let topaz_path = topaz_base_path.map(|p| p.join("ffmpeg.exe"));
        let system_path = Self::find_system_ffmpeg();
        
        Self {
            topaz_path,
            system_path,
            force_topaz,
        }
    }
    
    /// Find system FFmpeg installation
    fn find_system_ffmpeg() -> Option<PathBuf> {
        // Try PATH environment variable
        if let Ok(paths) = std::env::var("PATH") {
            for path in std::env::split_paths(&paths) {
                let ffmpeg_path = if cfg!(windows) {
                    path.join("ffmpeg.exe")
                } else {
                    path.join("ffmpeg")
                };
                
                if ffmpeg_path.exists() && ffmpeg_path.is_file() {
                    return Some(ffmpeg_path);
                }
            }
        }
        
        // Try common Windows locations
        if cfg!(windows) {
            let common_locations = [
                r"C:\Program Files\FFmpeg\bin\ffmpeg.exe",
                r"C:\Program Files (x86)\FFmpeg\bin\ffmpeg.exe",
                r"C:\FFmpeg\bin\ffmpeg.exe",
            ];
            
            for location in &common_locations {
                let path = PathBuf::from(location);
                if path.exists() && path.is_file() {
                    return Some(path);
                }
            }
        }
        
        // Try running ffmpeg command directly
        if Command::new("ffmpeg")
            .arg("-version")
            .output()
            .map(|output| output.status.success())
            .unwrap_or(false)
        {
            return Some(PathBuf::from("ffmpeg"));
        }
        
        None
    }
    
    /// Get the appropriate FFmpeg path for general use
    pub fn get_ffmpeg_path(&self) -> Result<PathBuf, TvaiError> {
        if self.force_topaz {
            self.get_topaz_ffmpeg_path()
        } else {
            // Try system FFmpeg first, fallback to Topaz
            if let Some(ref system_path) = self.system_path {
                Ok(system_path.clone())
            } else {
                self.get_topaz_ffmpeg_path()
            }
        }
    }
    
    /// Get Topaz FFmpeg path (required for AI filters)
    pub fn get_topaz_ffmpeg_path(&self) -> Result<PathBuf, TvaiError> {
        match &self.topaz_path {
            Some(path) if path.exists() => Ok(path.clone()),
            Some(path) => Err(TvaiError::TopazNotFound(path.display().to_string())),
            None => Err(TvaiError::TopazNotFound("No Topaz path configured".to_string())),
        }
    }
    
    /// Check if Topaz FFmpeg is available
    pub fn is_topaz_available(&self) -> bool {
        self.topaz_path
            .as_ref()
            .map(|p| p.exists())
            .unwrap_or(false)
    }
    
    /// Check if system FFmpeg is available
    pub fn is_system_available(&self) -> bool {
        self.system_path.is_some()
    }
    
    /// Execute FFmpeg command
    pub async fn execute_command(&self, args: &[&str], for_topaz: bool) -> Result<std::process::Output, TvaiError> {
        let ffmpeg_path = if for_topaz {
            self.get_topaz_ffmpeg_path()?
        } else {
            self.get_ffmpeg_path()?
        };
        
        let mut command = tokio::process::Command::new(&ffmpeg_path);
        command.args(args);

        // 如果使用 Topaz FFmpeg，设置工作目录为 Topaz 安装目录
        // 这对模型文件查找很重要
        if for_topaz {
            if let Some(topaz_dir) = ffmpeg_path.parent() {
                command.current_dir(topaz_dir);

                // 添加调试信息
                #[cfg(debug_assertions)]
                {
                    eprintln!("DEBUG: Setting working directory to: {}", topaz_dir.display());
                    eprintln!("DEBUG: FFmpeg path: {}", ffmpeg_path.display());
                }
            }
        }

        let output = command
            .output()
            .await
            .map_err(|e| TvaiError::FfmpegError(format!("Failed to execute FFmpeg: {}", e)))?;
        
        if !output.status.success() {
            let stderr = String::from_utf8_lossy(&output.stderr);
            return Err(TvaiError::FfmpegError(format!("FFmpeg failed: {}", stderr)));
        }
        
        Ok(output)
    }
    
    /// Get FFmpeg version information
    pub async fn get_version(&self, for_topaz: bool) -> Result<String, TvaiError> {
        let output = self.execute_command(&["-version"], for_topaz).await?;
        let stdout = String::from_utf8_lossy(&output.stdout);
        
        // Extract version from first line
        if let Some(first_line) = stdout.lines().next() {
            Ok(first_line.to_string())
        } else {
            Ok("Unknown version".to_string())
        }
    }
}
