use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::process::Command;

#[derive(Debug, Serialize, Deserialize)]
pub struct ProbeResult {
    pub streams: Vec<StreamInfo>,
    pub format: FormatInfo,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct StreamInfo {
    pub index: u32,
    pub codec_name: Option<String>,
    pub codec_type: Option<String>,
    pub width: Option<u32>,
    pub height: Option<u32>,
    pub r_frame_rate: Option<String>,
    pub duration: Option<String>,
    pub sample_rate: Option<String>,
    pub channels: Option<u32>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct FormatInfo {
    pub filename: Option<String>,
    pub format_name: Option<String>,
    pub duration: Option<String>,
    pub size: Option<String>,
    pub bit_rate: Option<String>,
}

pub fn probe_video(video_path: &str) -> Result<ProbeResult> {
    let output = Command::new("ffprobe")
        .args([
            "-v",
            "quiet",
            "-print_format",
            "json",
            "-show_format",
            "-show_streams",
            video_path,
        ])
        .output()
        .context("Failed to run ffprobe")?;

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        anyhow::bail!("ffprobe failed: {}", stderr);
    }

    let json_str = String::from_utf8_lossy(&output.stdout);
    let json: serde_json::Value =
        serde_json::from_str(&json_str).context("Failed to parse ffprobe output")?;

    let streams: Vec<StreamInfo> = json["streams"]
        .as_array()
        .map(|arr| {
            arr.iter()
                .map(|s| StreamInfo {
                    index: s["index"].as_u64().unwrap_or(0) as u32,
                    codec_name: s["codec_name"].as_str().map(String::from),
                    codec_type: s["codec_type"].as_str().map(String::from),
                    width: s["width"].as_u64().map(|v| v as u32),
                    height: s["height"].as_u64().map(|v| v as u32),
                    r_frame_rate: s["r_frame_rate"].as_str().map(String::from),
                    duration: s["duration"].as_str().map(String::from),
                    sample_rate: s["sample_rate"].as_str().map(String::from),
                    channels: s["channels"].as_u64().map(|v| v as u32),
                })
                .collect()
        })
        .unwrap_or_default();

    let format = FormatInfo {
        filename: json["format"]["filename"].as_str().map(String::from),
        format_name: json["format"]["format_name"].as_str().map(String::from),
        duration: json["format"]["duration"].as_str().map(String::from),
        size: json["format"]["size"].as_str().map(String::from),
        bit_rate: json["format"]["bit_rate"].as_str().map(String::from),
    };

    Ok(ProbeResult { streams, format })
}
