/**
 * 素材匹配相关的 Tauri 命令
 * 遵循 Tauri 开发规范的 API 设计原则
 */

use tauri::{command, State};
use std::sync::Arc;

use crate::business::services::material_matching_service::{
    MaterialMatchingService, MaterialMatchingRequest, MaterialMatchingResult,
    BatchMatchingRequest, BatchMatchingResult,
};
use crate::business::services::template_service::TemplateService;
use crate::business::services::template_matching_result_service::TemplateMatchingResultService;
use crate::data::repositories::{
    material_repository::MaterialRepository,
    video_classification_repository::VideoClassificationRepository,
    template_matching_result_repository::TemplateMatchingResultRepository,
};
use crate::data::models::template_matching_result::TemplateMatchingResult;
use crate::infrastructure::database::Database;

/// 执行素材匹配
#[command]
pub async fn execute_material_matching(
    request: MaterialMatchingRequest,
    database: State<'_, Arc<Database>>,
) -> Result<MaterialMatchingResult, String> {
    // 创建服务实例
    let material_repo = Arc::new(
        MaterialRepository::new(database.inner().clone())
            .map_err(|e| format!("创建素材仓库失败: {}", e))?
    );
    
    let template_service = Arc::new(TemplateService::new(database.inner().clone()));
    
    let video_classification_repo = Arc::new(
        VideoClassificationRepository::new(database.inner().clone())
    );

    let material_usage_repo = Arc::new(
        crate::data::repositories::material_usage_repository::MaterialUsageRepository::new(database.inner().clone())
    );

    let ai_classification_repo = Arc::new(
        crate::data::repositories::ai_classification_repository::AiClassificationRepository::new(database.inner().clone())
    );
    let ai_classification_service = Arc::new(
        crate::business::services::ai_classification_service::AiClassificationService::new(ai_classification_repo)
    );

    let matching_service = MaterialMatchingService::new(
        material_repo,
        material_usage_repo,
        template_service,
        video_classification_repo,
        ai_classification_service,
    );

    // 执行匹配
    matching_service.match_materials(request)
        .await
        .map_err(|e| e.to_string())
}

/// 执行素材匹配并自动保存结果
#[command]
pub async fn execute_material_matching_with_save(
    request: MaterialMatchingRequest,
    result_name: String,
    description: Option<String>,
    database: State<'_, Arc<Database>>,
) -> Result<(MaterialMatchingResult, Option<TemplateMatchingResult>), String> {
    // 创建服务实例
    let material_repo = Arc::new(
        MaterialRepository::new(database.inner().clone())
            .map_err(|e| format!("创建素材仓库失败: {}", e))?
    );

    let template_service = Arc::new(TemplateService::new(database.inner().clone()));

    let video_classification_repo = Arc::new(
        VideoClassificationRepository::new(database.inner().clone())
    );

    // 创建匹配结果服务
    let material_usage_repo = Arc::new(
        crate::data::repositories::material_usage_repository::MaterialUsageRepository::new(database.inner().clone())
    );
    let matching_result_repo = Arc::new(TemplateMatchingResultRepository::new(database.inner().clone()));
    let matching_result_service = Arc::new(TemplateMatchingResultService::new(matching_result_repo));

    let ai_classification_repo = Arc::new(
        crate::data::repositories::ai_classification_repository::AiClassificationRepository::new(database.inner().clone())
    );
    let ai_classification_service = Arc::new(
        crate::business::services::ai_classification_service::AiClassificationService::new(ai_classification_repo)
    );

    let matching_service = MaterialMatchingService::new_with_result_service(
        material_repo,
        material_usage_repo,
        template_service,
        video_classification_repo,
        ai_classification_service,
        matching_result_service,
    );

    // 执行匹配并保存结果
    matching_service.match_materials_and_save(request, result_name, description)
        .await
        .map_err(|e| e.to_string())
}

/// 获取项目的可用素材统计信息
#[command]
pub async fn get_project_material_stats_for_matching(
    project_id: String,
    database: State<'_, Arc<Database>>,
) -> Result<ProjectMaterialMatchingStats, String> {
    let material_repo = MaterialRepository::new(database.inner().clone())
        .map_err(|e| format!("创建素材仓库失败: {}", e))?;
    
    let video_classification_repo = VideoClassificationRepository::new(database.inner().clone());

    // 获取项目的所有素材
    let materials = material_repo.get_by_project_id(&project_id)
        .map_err(|e| format!("获取项目素材失败: {}", e))?;

    let mut total_segments = 0;
    let mut classified_segments = 0;
    let mut available_models = std::collections::HashSet::new();
    let mut available_categories = std::collections::HashSet::new();

    for material in &materials {
        total_segments += material.segments.len();
        
        // 获取分类记录
        let classification_records = video_classification_repo.get_by_material_id(&material.id)
            .await
            .map_err(|e| format!("获取分类记录失败: {}", e))?;

        // 统计已分类的片段
        for segment in &material.segments {
            if classification_records.iter().any(|r| r.segment_id == segment.id) {
                classified_segments += 1;
                
                // 记录分类类别
                if let Some(record) = classification_records.iter().find(|r| r.segment_id == segment.id) {
                    available_categories.insert(record.category.clone());
                }
            }
        }

        // 记录模特
        if let Some(model_id) = &material.model_id {
            available_models.insert(model_id.clone());
        }
    }

    Ok(ProjectMaterialMatchingStats {
        project_id,
        total_materials: materials.len() as u32,
        total_segments: total_segments as u32,
        classified_segments: classified_segments as u32,
        available_models: available_models.len() as u32,
        available_categories: available_categories.into_iter().collect(),
        classification_rate: if total_segments > 0 {
            classified_segments as f64 / total_segments as f64
        } else {
            0.0
        },
    })
}

/// 验证模板绑定是否可以进行素材匹配
#[command]
pub async fn validate_template_binding_for_matching(
    binding_id: String,
    database: State<'_, Arc<Database>>,
) -> Result<TemplateBindingMatchingValidation, String> {
    use crate::data::repositories::project_template_binding_repository::ProjectTemplateBindingRepository;
    use crate::business::services::template_service::TemplateService;

    let mut validation_errors = Vec::new();
    let mut total_segments = 0;
    let mut matchable_segments = 0;

    // 获取模板绑定信息
    let binding_repo = ProjectTemplateBindingRepository::new(database.inner().clone());

    let binding = match binding_repo.get_by_id(&binding_id) {
        Ok(Some(binding)) => binding,
        Ok(None) => {
            validation_errors.push("模板绑定不存在".to_string());
            return Ok(TemplateBindingMatchingValidation {
                binding_id,
                is_valid: false,
                validation_errors,
                total_segments: 0,
                matchable_segments: 0,
            });
        }
        Err(e) => {
            validation_errors.push(format!("获取模板绑定失败: {}", e));
            return Ok(TemplateBindingMatchingValidation {
                binding_id,
                is_valid: false,
                validation_errors,
                total_segments: 0,
                matchable_segments: 0,
            });
        }
    };

    // 检查绑定是否激活
    if !binding.is_active {
        validation_errors.push("模板绑定未激活".to_string());
    }

    // 获取模板信息并统计片段
    let template_service = TemplateService::new(database.inner().clone());
    match template_service.get_template_by_id(&binding.template_id).await {
        Ok(Some(template)) => {
            // 统计所有轨道片段
            for track in &template.tracks {
                total_segments += track.segments.len() as u32;

                // 统计可匹配的片段（非固定素材）
                for segment in &track.segments {
                    if !segment.matching_rule.is_fixed_material() {
                        matchable_segments += 1;
                    }
                }
            }
        }
        Ok(None) => {
            validation_errors.push("关联的模板不存在".to_string());
        }
        Err(e) => {
            validation_errors.push(format!("获取模板信息失败: {}", e));
        }
    }

    let is_valid = validation_errors.is_empty();

    Ok(TemplateBindingMatchingValidation {
        binding_id,
        is_valid,
        validation_errors,
        total_segments,
        matchable_segments,
    })
}

/// 项目素材匹配统计信息
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct ProjectMaterialMatchingStats {
    pub project_id: String,
    pub total_materials: u32,
    pub total_segments: u32,
    pub classified_segments: u32,
    pub available_models: u32,
    pub available_categories: Vec<String>,
    pub classification_rate: f64,
}

/// 模板绑定匹配验证结果
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct TemplateBindingMatchingValidation {
    pub binding_id: String,
    pub is_valid: bool,
    pub validation_errors: Vec<String>,
    pub total_segments: u32,
    pub matchable_segments: u32,
}

/// 一键匹配所有模板
/// 遍历项目的所有活跃模板绑定并逐一执行匹配
#[tauri::command]
pub async fn batch_match_all_templates(
    request: BatchMatchingRequest,
    state: State<'_, crate::app_state::AppState>,
    app_handle: tauri::AppHandle,
) -> Result<BatchMatchingResult, String> {
    let database = state.get_database();

    // 创建所需的仓储实例
    let material_repo = Arc::new(
        MaterialRepository::new(database.clone())
            .map_err(|e| format!("创建素材仓储失败: {}", e))?
    );

    let template_service = Arc::new(TemplateService::new(database.clone()));

    let video_classification_repo = Arc::new(
        VideoClassificationRepository::new(database.clone())
    );

    // 创建匹配结果服务
    let material_usage_repo = Arc::new(
        crate::data::repositories::material_usage_repository::MaterialUsageRepository::new(database.clone())
    );
    let matching_result_repo = Arc::new(TemplateMatchingResultRepository::new(database.clone()));
    let matching_result_service = Arc::new(TemplateMatchingResultService::new(matching_result_repo));

    let ai_classification_repo = Arc::new(
        crate::data::repositories::ai_classification_repository::AiClassificationRepository::new(database.clone())
    );
    let ai_classification_service = Arc::new(
        crate::business::services::ai_classification_service::AiClassificationService::new(ai_classification_repo)
    );

    let matching_service = MaterialMatchingService::new_with_result_service(
        material_repo,
        material_usage_repo,
        template_service,
        video_classification_repo,
        ai_classification_service,
        matching_result_service,
    );

    // 执行一键匹配（带事件发送）
    matching_service.batch_match_all_templates_with_events(request, database, Some(app_handle))
        .await
        .map_err(|e| e.to_string())
}
