use std::path::{Path, PathBuf};
use std::process::Command;
use std::fs;
use crate::types::Result;
use crate::utils::log::{success, info};
use super::commands::CutArgs;

fn parse_time_to_seconds(time: &str) -> Result<f64> {
    let parts: Vec<&str> = time.split(':').collect();
    match parts.len() {
        1 => {
            parts[0].parse::<f64>()
                .map_err(|_| format!("Invalid time format: {}", time).into())
        }
        2 => {
            let mins: f64 = parts[0].parse()
                .map_err(|_| format!("Invalid minutes in: {}", time))?;
            let secs: f64 = parts[1].parse()
                .map_err(|_| format!("Invalid seconds in: {}", time))?;
            Ok(mins * 60.0 + secs)
        }
        3 => {
            let hours: f64 = parts[0].parse()
                .map_err(|_| format!("Invalid hours in: {}", time))?;
            let mins: f64 = parts[1].parse()
                .map_err(|_| format!("Invalid minutes in: {}", time))?;
            let secs: f64 = parts[2].parse()
                .map_err(|_| format!("Invalid seconds in: {}", time))?;
            Ok(hours * 3600.0 + mins * 60.0 + secs)
        }
        _ => Err(format!("Invalid time format: {}. Use HH:MM:SS, MM:SS, or SS", time).into())
    }
}

fn format_time(seconds: f64) -> String {
    let hours = (seconds / 3600.0).floor() as u32;
    let mins = ((seconds % 3600.0) / 60.0).floor() as u32;
    let secs = seconds % 60.0;
    format!("{:02}:{:02}:{:06.3}", hours, mins, secs)
}

fn detect_extension(input: &Path) -> &str {
    input.extension()
        .and_then(|e| e.to_str())
        .unwrap_or("mp4")
}

fn build_output_path(input: &Path, output: Option<PathBuf>, start: &str, end: &str) -> PathBuf {
    if let Some(out) = output {
        return out;
    }
    
    let parent = input.parent().unwrap_or_else(|| Path::new("."));
    let stem = input.file_stem()
        .and_then(|s| s.to_str())
        .unwrap_or("video");
    let ext = detect_extension(input);
    
    let clean_start = start.replace(':', "-");
    let clean_end = end.replace(':', "-");
    
    parent.join(format!("{}_cut_{}_{}.{}", stem, clean_start, clean_end, ext))
}

pub async fn execute(args: CutArgs) -> Result<()> {
    let input = &args.input;
    
    if !input.exists() {
        return Err(format!("Input file not found: {}", input.display()).into());
    }
    
    let start_secs = parse_time_to_seconds(&args.start)?;
    let end_secs = parse_time_to_seconds(&args.end)?;
    
    if end_secs <= start_secs {
        return Err("End time must be greater than start time".into());
    }
    
    let duration = end_secs - start_secs;
    let start_formatted = format_time(start_secs);
    let end_formatted = format_time(end_secs);
    
    let output = build_output_path(input, args.output, &args.start, &args.end);
    
    if output.exists() {
        return Err(format!("Output file already exists: {}", output.display()).into());
    }
    
    if let Some(parent) = output.parent() {
        fs::create_dir_all(parent)?;
    }
    
    info(&format!("Cutting video from {} to {} ({:.2}s)", 
        start_formatted, end_formatted, duration));
    
    let status = Command::new("ffmpeg")
        .args(["-y", "-hide_banner", "-loglevel", "warning"])
        .args(["-i"])
        .arg(input)
        .args(["-ss", &start_formatted])
        .args(["-to", &end_formatted])
        .args(["-c", "copy"])
        .arg(&output)
        .status()?;
    
    if !status.success() {
        if output.exists() {
            let _ = fs::remove_file(&output);
        }
        return Err("FFmpeg cut operation failed".into());
    }
    
    let output_size = fs::metadata(&output)?.len();
    
    println!();
    success("Video cut complete!");
    println!("  Start:    {}", start_formatted);
    println!("  End:      {}", end_formatted);
    println!("  Duration: {:.2}s", duration);
    println!("  Output:   {}", output.display());
    println!("  Size:     {} bytes ({:.2} MB)", output_size, output_size as f64 / 1024.0 / 1024.0);
    
    Ok(())
}
