use clap::{Subcommand, Args, ValueEnum};
use std::path::PathBuf;
use std::process::Command;
use crate::types::Result;
use crate::utils::log::error;

#[derive(ValueEnum, Clone, Debug, Copy, PartialEq)]
#[clap(rename_all = "lower")]
pub enum VideoFormat {
    Mp4,
    Mkv,
    Webm,
    Mov,
    Avi,
}

impl VideoFormat {
    pub fn extension(&self) -> &'static str {
        match self {
            VideoFormat::Mp4 => "mp4",
            VideoFormat::Mkv => "mkv",
            VideoFormat::Webm => "webm",
            VideoFormat::Mov => "mov",
            VideoFormat::Avi => "avi",
        }
    }
}

#[derive(Args, Debug)]
pub struct CompressArgs {
    #[arg(help = "Input video file path")]
    pub input: PathBuf,

    #[arg(long, short = 'o', help = "Output file path")]
    pub output: Option<PathBuf>,

    #[arg(long, short = 'f', value_enum, help = "Output format (default: auto-select smallest)")]
    pub format: Option<VideoFormat>,
}

#[derive(Args, Debug)]
pub struct CutArgs {
    #[arg(help = "Input video file path")]
    pub input: PathBuf,

    #[arg(long, short = 's', help = "Start time (format: HH:MM:SS, MM:SS, or SS)")]
    pub start: String,

    #[arg(long, short = 'e', help = "End time (format: HH:MM:SS, MM:SS, or SS)")]
    pub end: String,

    #[arg(long, short = 'o', help = "Output file path")]
    pub output: Option<PathBuf>,
}

#[derive(Args, Debug)]
pub struct SplitArgs {
    #[arg(help = "Input video file path")]
    pub input: PathBuf,

    #[arg(long, short = 'i', help = "Interval per segment (e.g., 30s, 5m, 1h, or HH:MM:SS)")]
    pub interval: String,

    #[arg(long, short = 'o', help = "Output directory")]
    pub out_dir: Option<PathBuf>,
}

#[derive(Args, Debug)]
pub struct SpeedArgs {
    #[arg(help = "Input video file path")]
    pub input: PathBuf,

    #[arg(long, short = 's', help = "Speed multiplier (0.25 to 4.0, e.g., 2.0 for 2x speed, 0.5 for half speed)")]
    pub speed: f64,

    #[arg(long, short = 'o', help = "Output file path")]
    pub output: Option<PathBuf>,

    #[arg(long, short = 'a', help = "Keep audio (adjust tempo to match speed)", default_value_t = false)]
    pub keep_audio: bool,
}

#[derive(Args, Debug)]
pub struct RemoveAudioArgs {
    #[arg(help = "Input video file path")]
    pub input: PathBuf,

    #[arg(long, short = 'o', help = "Output file path")]
    pub output: Option<PathBuf>,
}

#[derive(Subcommand)]
pub enum FfmpegCommands {
    #[command(about = "Lossless video compression")]
    Compress(CompressArgs),

    #[command(about = "Cut video by time range")]
    Cut(CutArgs),

    #[command(about = "Split video into segments by fixed interval")]
    Split(SplitArgs),

    #[command(about = "Change video playback speed")]
    Speed(SpeedArgs),

    #[command(about = "Remove audio track from video")]
    RemoveAudio(RemoveAudioArgs),
}

pub fn check_ffmpeg_installed() -> bool {
    Command::new("ffmpeg")
        .arg("-version")
        .output()
        .map(|output| output.status.success())
        .unwrap_or(false)
}

pub fn prompt_install_ffmpeg() {
    error("FFmpeg is not installed on your system.");
    println!();
    println!("Please install FFmpeg using one of the following methods:");
    println!();
    println!("  macOS (Homebrew):");
    println!("    brew install ffmpeg");
    println!();
    println!("  Ubuntu/Debian:");
    println!("    sudo apt update && sudo apt install ffmpeg");
    println!();
    println!("  Windows (Chocolatey):");
    println!("    choco install ffmpeg");
    println!();
    println!("  Windows (Scoop):");
    println!("    scoop install ffmpeg");
    println!();
    println!("After installation, run this command again.");
}

pub async fn handle_ffmpeg_command(command: FfmpegCommands) -> Result<()> {
    if !check_ffmpeg_installed() {
        prompt_install_ffmpeg();
        std::process::exit(1);
    }

    match command {
        FfmpegCommands::Compress(args) => {
            crate::commands::ffmpeg::compress::execute(args).await
        }
        FfmpegCommands::Cut(args) => {
            crate::commands::ffmpeg::cut::execute(args).await
        }
        FfmpegCommands::Split(args) => {
            crate::commands::ffmpeg::split::execute(args).await
        }
        FfmpegCommands::Speed(args) => {
            crate::commands::ffmpeg::speed::execute(args).await
        }
        FfmpegCommands::RemoveAudio(args) => {
            crate::commands::ffmpeg::remove_audio::execute(args).await
        }
    }
}
