use crate::core::time::FrameTime;
use serde::{Deserialize, Serialize};

// ==================== ChunkType ====================
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum ChunkType {
    TimeBased,
    Sentence,
    Cut,
    Trace,
    Story,
    Visual, // 視覺分片 (Phase 2.1)
}

impl ChunkType {
    pub fn as_str(&self) -> &'static str {
        match self {
            ChunkType::TimeBased => "time",
            ChunkType::Sentence => "sentence",
            ChunkType::Cut => "cut",
            ChunkType::Trace => "trace",
            ChunkType::Story => "story",
            ChunkType::Visual => "visual",
        }
    }
}

// ==================== ChunkRule ====================
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum ChunkRule {
    Rule1, // 直接轉換
    Rule2, // 集合內容
}

impl ChunkRule {
    pub fn as_str(&self) -> &'static str {
        match self {
            ChunkRule::Rule1 => "rule_1",
            ChunkRule::Rule2 => "rule_2",
        }
    }
}

// ==================== 視覺分片相關結構 (Phase 2.1) ====================
/// 邊界框
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BoundingBox {
    pub x: i32,
    pub y: i32,
    pub width: i32,
    pub height: i32,
}

/// 檢測到的物件
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DetectedObject {
    /// 物件類別名稱
    pub class_name: String,
    /// 物件類別 ID
    pub class_id: u32,
    /// 信心值 (0.0-1.0)
    pub confidence: f32,
    /// 邊界框
    pub bbox: Option<BoundingBox>,
    /// 出現次數 (在分片內)
    pub occurrence: u32,
}

/// 關鍵幀的物件列表
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KeyframeObjects {
    /// 關鍵幀時間 (秒) - 僅供參考，主要使用 frame_number
    pub timestamp: f64,
    /// 關鍵幀幀號 - 主要時間標示
    pub frame_number: u64,
    /// 檢測到的物件
    pub objects: Vec<DetectedObject>,
}

/// 視覺元數據
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VisualMetadata {
    /// 總物件數量
    pub object_count: u32,
    /// 唯一物件類別列表
    pub unique_classes: Vec<String>,
    /// 最高信心值
    pub max_confidence: f32,
    /// 平均信心值
    pub avg_confidence: f32,
    /// 空間密度（每幀平均物件數）
    pub spatial_density: f32,
}

/// 視覺分片內容
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VisualChunkContent {
    /// 關鍵幀物件列表，每個關鍵幀包含 frame_number
    pub keyframe_objects: Vec<KeyframeObjects>,
    /// 主要物件標籤（出現在大多數幀中的物件）
    pub dominant_objects: Vec<String>,
    /// 物件關係 (object1, relationship, object2) - 可選
    pub object_relationships: Vec<(String, String, String)>,
    /// 場景描述 - 可選
    pub scene_description: Option<String>,
    /// 視覺元數據
    pub metadata: VisualMetadata,
}

// ==================== Chunk 主結構 ====================
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Chunk {
    pub file_id: i32,
    pub uuid: String,
    pub chunk_id: String,
    pub chunk_index: u32,
    pub chunk_type: ChunkType,
    pub rule: ChunkRule,
    /// Frames per second (can be fractional, e.g., 29.97, 23.976)
    pub fps: f64,
    /// Start frame (0-based) - 主要時間標示
    pub start_frame: i64,
    /// End frame (exclusive) - 主要時間標示
    pub end_frame: i64,
    pub text_content: Option<String>,
    pub content: serde_json::Value,
    pub metadata: Option<serde_json::Value>,
    pub vector_id: Option<String>,
    pub frame_count: i32,
    pub pre_chunk_ids: Vec<i32>,
    pub parent_chunk_id: Option<String>, // For parent-child chunk hierarchy
    pub child_chunk_ids: Vec<String>,    // Child chunk IDs (for parent chunks)
    pub visual_stats: Option<serde_json::Value>,
}

impl Chunk {
    /// 創建新分片
    pub fn new(
        file_id: i32,
        uuid: String,
        chunk_index: u32,
        chunk_type: ChunkType,
        rule: ChunkRule,
        start_frame: i64,
        end_frame: i64,
        fps: f64,
        content: serde_json::Value,
    ) -> Self {
        let frame_count = (end_frame - start_frame) as i32;
        let chunk_id = format!("{}_{}", uuid, chunk_index);

        Self {
            file_id,
            uuid,
            chunk_id,
            chunk_index,
            chunk_type,
            rule,
            fps,
            start_frame,
            end_frame,
            text_content: None,
            content,
            metadata: None,
            vector_id: None,
            frame_count,
            pre_chunk_ids: vec![],
            parent_chunk_id: None,
            child_chunk_ids: vec![],
            visual_stats: None,
        }
    }

    /// 創建視覺分片 (Phase 2.1)
    pub fn new_visual(
        file_id: i32,
        uuid: String,
        chunk_index: u32,
        start_frame: i64,
        end_frame: i64,
        fps: f64,
        visual_content: VisualChunkContent,
    ) -> Self {
        let content = serde_json::to_value(&visual_content)
            .unwrap_or_else(|_| serde_json::json!({"error": "Failed to serialize visual content"}));

        Self::new(
            file_id,
            uuid,
            chunk_index,
            ChunkType::Visual,
            ChunkRule::Rule2,
            start_frame,
            end_frame,
            fps,
            content,
        )
    }

    /// 從 YOLO 幀創建視覺分片 (Phase 2.1)
    pub fn from_yolo_frames(
        file_id: i32,
        uuid: String,
        chunk_index: u32,
        start_frame: i64,
        end_frame: i64,
        fps: f64,
        yolo_frames: Vec<crate::core::processor::yolo::YoloFrame>,
    ) -> Self {
        // 將 YOLO 幀轉換為關鍵幀物件
        let keyframe_objects: Vec<KeyframeObjects> = yolo_frames
            .iter()
            .map(|frame| {
                let objects: Vec<DetectedObject> = frame
                    .objects
                    .iter()
                    .map(|obj| DetectedObject {
                        class_name: obj.class_name.clone(),
                        class_id: obj.class_id,
                        confidence: obj.confidence,
                        bbox: Some(BoundingBox {
                            x: obj.x,
                            y: obj.y,
                            width: obj.width,
                            height: obj.height,
                        }),
                        occurrence: 1,
                    })
                    .collect();

                KeyframeObjects {
                    timestamp: frame.timestamp,
                    frame_number: frame.frame,
                    objects,
                }
            })
            .collect();

        // 計算物件統計
        let total_objects: u32 = yolo_frames.iter().map(|f| f.objects.len() as u32).sum();

        // 收集所有物件類別
        let all_classes: Vec<String> = yolo_frames
            .iter()
            .flat_map(|f| f.objects.iter().map(|o| o.class_name.clone()))
            .collect();

        // 獲取唯一類別
        let unique_classes: Vec<String> = all_classes
            .iter()
            .cloned()
            .collect::<std::collections::HashSet<_>>()
            .into_iter()
            .collect();

        // 計算信心值統計
        let confidences: Vec<f32> = yolo_frames
            .iter()
            .flat_map(|f| f.objects.iter().map(|o| o.confidence))
            .collect();

        let max_confidence = confidences.iter().copied().fold(0.0f32, f32::max);
        let avg_confidence = if !confidences.is_empty() {
            confidences.iter().sum::<f32>() / confidences.len() as f32
        } else {
            0.0
        };

        // 計算主要物件（出現在大多數幀中的物件）
        let mut object_counts = std::collections::HashMap::new();
        for frame in &yolo_frames {
            let frame_classes: std::collections::HashSet<_> =
                frame.objects.iter().map(|o| o.class_name.clone()).collect();
            for class in frame_classes {
                *object_counts.entry(class).or_insert(0) += 1;
            }
        }

        let mut dominant_objects: Vec<String> = object_counts
            .into_iter()
            .filter(|(_, count)| *count as f32 / yolo_frames.len() as f32 > 0.5)
            .map(|(class, _)| class)
            .collect();
        dominant_objects.sort();

        // 創建視覺內容
        let visual_content = VisualChunkContent {
            keyframe_objects,
            dominant_objects,
            object_relationships: vec![], // 可選：後期添加關係檢測
            scene_description: None,      // 可選：後期添加 LLM 生成的場景描述
            metadata: VisualMetadata {
                object_count: total_objects,
                unique_classes,
                max_confidence,
                avg_confidence,
                spatial_density: if yolo_frames.len() > 0 {
                    total_objects as f32 / yolo_frames.len() as f32
                } else {
                    0.0
                },
            },
        };

        Self::new_visual(
            file_id,
            uuid,
            chunk_index,
            start_frame,
            end_frame,
            fps,
            visual_content,
        )
    }

    /// 將分片轉換為幀時間
    pub fn to_frame_time(&self) -> FrameTime {
        // 使用第一個幀作為參考點
        FrameTime::from_frames(self.start_frame, self.fps)
    }

    /// 檢查是否是父分片
    pub fn is_parent(&self) -> bool {
        self.parent_chunk_id.is_some()
    }

    /// 從秒數創建新分片（舊版轉換）
    ///
    /// 這對於從存儲時間為秒的舊系統遷移很有用。
    /// 幀數通過舍入 `seconds * fps` 計算。
    #[allow(clippy::too_many_arguments)]
    pub fn from_seconds(
        file_id: i32,
        uuid: String,
        chunk_index: u32,
        chunk_type: ChunkType,
        rule: ChunkRule,
        start_time: f64,
        end_time: f64,
        fps: f64,
        content: serde_json::Value,
    ) -> Self {
        let start_frame = (start_time * fps).round() as i64;
        let end_frame = (end_time * fps).round() as i64;
        Self::new(
            file_id,
            uuid,
            chunk_index,
            chunk_type,
            rule,
            start_frame,
            end_frame,
            fps,
            content,
        )
    }

    /// 返回開始時間為 `FrameTime`
    pub fn start_time(&self) -> FrameTime {
        FrameTime::from_frames(self.start_frame, self.fps)
    }

    /// 返回結束時間為 `FrameTime`
    pub fn end_time(&self) -> FrameTime {
        FrameTime::from_frames(self.end_frame, self.fps)
    }

    /// 返回持續時間的幀數
    pub fn duration_frames(&self) -> i64 {
        self.end_frame - self.start_frame
    }

    /// 返回持續時間的秒數
    pub fn duration_seconds(&self) -> f64 {
        self.duration_frames() as f64 / self.fps
    }

    /// 將開始時間格式化為 "seconds.frame" (例如："123.04")
    pub fn format_start_sec_frame(&self) -> String {
        self.start_time().format_sec_frame()
    }

    /// 將結束時間格式化為 "seconds.frame" (例如："456.15")
    pub fn format_end_sec_frame(&self) -> String {
        self.end_time().format_sec_frame()
    }

    /// 將開始時間格式化為 "HH:MM:SS"
    pub fn format_start_hms(&self) -> String {
        self.start_time().format_hms()
    }

    /// 將結束時間格式化為 "HH:MM:SS"
    pub fn format_end_hms(&self) -> String {
        self.end_time().format_hms()
    }

    /// 將開始時間格式化為 "HH:MM:SS.FF"
    pub fn format_start_hms_frame(&self) -> String {
        self.start_time().format_hms_frame()
    }

    /// 將結束時間格式化為 "HH:MM:SS.FF"
    pub fn format_end_hms_frame(&self) -> String {
        self.end_time().format_hms_frame()
    }

    /// 返回 (start_seconds, end_seconds) 元組用於兼容性
    ///
    /// 這在遷移期間提供向後兼容性。
    /// 建議使用 `start_time()` 和 `end_time()` 方法。
    pub fn time_range_seconds(&self) -> (f64, f64) {
        (self.start_time().seconds(), self.end_time().seconds())
    }

    /// 添加元數據
    pub fn with_metadata(mut self, metadata: serde_json::Value) -> Self {
        self.metadata = Some(metadata);
        self
    }

    /// 添加向量 ID
    pub fn with_vector_id(mut self, vector_id: String) -> Self {
        self.vector_id = Some(vector_id);
        self
    }

    /// 添加文本內容
    pub fn with_text_content(mut self, text: String) -> Self {
        self.text_content = Some(text);
        self
    }

    /// 設置幀數
    pub fn with_frame_count(mut self, count: i32) -> Self {
        self.frame_count = count;
        self
    }

    /// 設置前一個分片 ID
    pub fn with_pre_chunk_ids(mut self, ids: Vec<i32>) -> Self {
        self.pre_chunk_ids = ids;
        self
    }

    /// 設置父分片 ID
    pub fn with_parent_chunk_id(mut self, parent_id: String) -> Self {
        self.parent_chunk_id = Some(parent_id);
        self
    }

    /// 設置子分片 ID
    pub fn with_child_chunk_ids(mut self, child_ids: Vec<String>) -> Self {
        self.child_chunk_ids = child_ids;
        self
    }
}

// ==================== VisualChunkContent 輔助方法 ====================
impl VisualChunkContent {
    /// 計算兩個 YOLO 幀之間的相似度（基於物件組成）
    pub fn frame_similarity(
        frame1: &crate::core::processor::yolo::YoloFrame,
        frame2: &crate::core::processor::yolo::YoloFrame,
    ) -> f32 {
        if frame1.objects.is_empty() && frame2.objects.is_empty() {
            return 1.0; // 兩個空幀完全相似
        }

        if frame1.objects.is_empty() || frame2.objects.is_empty() {
            return 0.0; // 一個空一個非空，不相似
        }

        // 創建物件類別名稱集合
        let set1: std::collections::HashSet<String> = frame1
            .objects
            .iter()
            .map(|o| o.class_name.clone())
            .collect();
        let set2: std::collections::HashSet<String> = frame2
            .objects
            .iter()
            .map(|o| o.class_name.clone())
            .collect();

        // 計算 Jaccard 相似度
        let intersection: Vec<_> = set1.intersection(&set2).collect();
        let union: Vec<_> = set1.union(&set2).collect();

        if union.is_empty() {
            0.0
        } else {
            intersection.len() as f32 / union.len() as f32
        }
    }

    /// 獲取視覺分片的摘要（使用關鍵幀的 frame_number）
    pub fn summary(&self, fps: f64) -> String {
        if self.keyframe_objects.is_empty() {
            return "Empty visual chunk".to_string();
        }

        let first_frame = self.keyframe_objects.first().unwrap().frame_number;
        let last_frame = self.keyframe_objects.last().unwrap().frame_number;

        // 計算時間（僅供參考）
        let start_time = if fps > 0.0 {
            first_frame as f64 / fps
        } else {
            0.0
        };
        let end_time = if fps > 0.0 {
            last_frame as f64 / fps
        } else {
            0.0
        };
        let duration = end_time - start_time;
        let frame_count = self.keyframe_objects.len();

        format!(
            "Visual chunk: frames {} to {} (duration: {:.1}s, {} frames). Objects: {} total, {} unique. Dominant: {}",
            first_frame,
            last_frame,
            duration,
            frame_count,
            self.metadata.object_count,
            self.metadata.unique_classes.len(),
            if self.dominant_objects.is_empty() {
                "none".to_string()
            } else {
                self.dominant_objects.join(", ")
            }
        )
    }

    /// 檢查是否包含特定物件類別
    pub fn contains_object(&self, class_name: &str) -> bool {
        self.keyframe_objects
            .iter()
            .any(|ko| ko.objects.iter().any(|obj| obj.class_name == class_name))
    }

    /// 獲取信心值高於閾值的所有物件
    pub fn high_confidence_objects(&self, threshold: f32) -> Vec<&DetectedObject> {
        self.keyframe_objects
            .iter()
            .flat_map(|ko| ko.objects.iter())
            .filter(|obj| obj.confidence >= threshold)
            .collect()
    }
}
