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

use super::executor::PythonExecutor;

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

/// 場景識別結果
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SceneClassificationResult {
    pub frame_count: u64,
    pub fps: f64,
    pub scenes: Vec<SceneSegment>,
}

/// 場景片段
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SceneSegment {
    pub start_time: f64,
    pub end_time: f64,
    pub scene_type: String,            // 場景類型英文 (如 "hospital_room")
    pub scene_type_zh: Option<String>, // 場景類型中文 (如 "醫院病房")
    pub confidence: f32,
    pub top_5: Vec<ScenePrediction>, // 前 5 個預測
}

/// 場景預測
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ScenePrediction {
    pub scene_type: String,
    pub confidence: f32,
}

/// 執行場景識別
pub async fn process_scene_classification(
    video_path: &str,
    output_path: &str,
    uuid: Option<&str>,
) -> Result<SceneClassificationResult> {
    let executor = PythonExecutor::new()?;
    let script_path = executor.script_path("scene_classifier.py");

    tracing::info!("[SCENE] Starting scene classification: {}", video_path);

    if !script_path.exists() {
        tracing::warn!("[SCENE] Script not found, returning empty result");
        return Ok(SceneClassificationResult {
            frame_count: 0,
            fps: 0.0,
            scenes: vec![],
        });
    }

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

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

    let result: SceneClassificationResult =
        serde_json::from_str(&json_str).context("Failed to parse scene classification output")?;

    tracing::info!("[SCENE] Result: {} scenes detected", result.scenes.len());

    Ok(result)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_scene_result_serialization() {
        let result = SceneClassificationResult {
            frame_count: 100,
            fps: 30.0,
            scenes: vec![SceneSegment {
                start_time: 0.0,
                end_time: 10.5,
                scene_type: "hospital_room".to_string(),
                scene_type_zh: Some("醫院病房".to_string()),
                confidence: 0.92,
                top_5: vec![
                    ScenePrediction {
                        scene_type: "hospital_room".to_string(),
                        confidence: 0.92,
                    },
                    ScenePrediction {
                        scene_type: "pharmacy".to_string(),
                        confidence: 0.05,
                    },
                ],
            }],
        };

        let json = serde_json::to_string(&result).unwrap();
        assert!(json.contains("hospital_room"));
        assert!(json.contains("醫院病房"));
        assert!(json.contains("\"confidence\":0.92"));
    }

    #[test]
    fn test_scene_result_deserialization() {
        let json = r#"{
            "frame_count": 50,
            "fps": 25.0,
            "scenes": [
                {
                    "start_time": 0.0,
                    "end_time": 5.5,
                    "scene_type": "basketball_court",
                    "scene_type_zh": "籃球場",
                    "confidence": 0.87,
                    "top_5": [
                        {"scene_type": "basketball_court", "confidence": 0.87},
                        {"scene_type": "gymnasium", "confidence": 0.08}
                    ]
                }
            ]
        }"#;

        let result: SceneClassificationResult = serde_json::from_str(json).unwrap();
        assert_eq!(result.frame_count, 50);
        assert_eq!(result.scenes.len(), 1);
        assert_eq!(result.scenes[0].scene_type, "basketball_court");
        assert_eq!(result.scenes[0].confidence, 0.87);
    }

    #[test]
    fn test_scene_result_empty() {
        let result = SceneClassificationResult {
            frame_count: 0,
            fps: 0.0,
            scenes: vec![],
        };
        assert!(result.scenes.is_empty());
    }

    #[test]
    fn test_scene_prediction() {
        let pred = ScenePrediction {
            scene_type: "classroom".to_string(),
            confidence: 0.95,
        };
        assert_eq!(pred.scene_type, "classroom");
        assert!(pred.confidence >= 0.0 && pred.confidence <= 1.0);
    }

    #[test]
    fn test_scene_segment_time() {
        let segment = SceneSegment {
            start_time: 10.0,
            end_time: 20.0,
            scene_type: "office".to_string(),
            scene_type_zh: None,
            confidence: 0.8,
            top_5: vec![],
        };
        assert!(segment.end_time > segment.start_time);
    }
}
