use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::time::Duration;

use super::executor::PythonExecutor;

const CAPTION_TIMEOUT: Duration = Duration::from_secs(7200);

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CaptionResult {
    pub video_path: String,
    pub total_frames: usize,
    pub captions: Vec<FrameCaption>,
    pub summary: CaptionSummary,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct FrameCaption {
    pub index: u32,
    pub timestamp: f64,
    pub caption: String,
    pub source: String,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CaptionSummary {
    pub avg_caption_length: f64,
    pub gpt4v_count: usize,
    pub llava_count: usize,
    pub metadata_count: usize,
}

pub async fn process_caption(
    video_path: &str,
    output_path: &str,
    uuid: Option<&str>,
) -> Result<CaptionResult> {
    let executor = PythonExecutor::new()?;
    let script_path = executor.script_path("caption_processor.py");

    tracing::info!("[CAPTION] Starting caption generation: {}", video_path);

    if !script_path.exists() {
        tracing::warn!("[CAPTION] Script not found, returning empty result");
        return Ok(CaptionResult {
            video_path: video_path.to_string(),
            total_frames: 0,
            captions: vec![],
            summary: CaptionSummary {
                avg_caption_length: 0.0,
                gpt4v_count: 0,
                llava_count: 0,
                metadata_count: 0,
            },
        });
    }

    executor
        .run(
            "caption_processor.py",
            &[video_path, output_path],
            uuid,
            "CAPTION",
            Some(CAPTION_TIMEOUT),
        )
        .await
        .with_context(|| format!("Failed to run {:?}", script_path))?;

    let json_str = std::fs::read_to_string(output_path).context("Failed to read CAPTION output")?;

    let result: CaptionResult =
        serde_json::from_str(&json_str).context("Failed to parse CAPTION output")?;

    tracing::info!("[CAPTION] Result: {} frames captioned", result.total_frames);

    Ok(result)
}
