use anyhow::{Result, anyhow};
use std::path::Path;
use std::fs;
use std::time::Instant;
use std::sync::Arc;
use tokio::task;

use crate::data::models::material::{
    Material, MaterialType, ProcessingStatus, CreateMaterialRequest,
    MaterialImportResult, MaterialProcessingConfig
};
use crate::data::repositories::material_repository::MaterialRepository;
use crate::infrastructure::monitoring::PERFORMANCE_MONITOR;
use crate::infrastructure::event_bus::EventBusManager;
use crate::business::errors::error_utils;
use crate::business::services::material_service::MaterialService;
use tracing::{info, warn, error, debug};

/// 异步素材服务
/// 遵循 Tauri 开发规范的异步业务逻辑层设计
pub struct AsyncMaterialService;

impl AsyncMaterialService {
    /// 异步导入素材文件
    /// 提供实时进度反馈和非阻塞用户体验
    pub async fn import_materials_async(
        repository: Arc<MaterialRepository>,
        request: CreateMaterialRequest,
        config: MaterialProcessingConfig,
        event_bus: Arc<EventBusManager>,
    ) -> Result<MaterialImportResult> {
        let timer = PERFORMANCE_MONITOR.start_operation("async_import_materials");
        let start_time = Instant::now();

        info!(
            project_id = %request.project_id,
            file_count = request.file_paths.len(),
            "开始异步导入素材文件"
        );

        let mut result = MaterialImportResult {
            total_files: request.file_paths.len() as u32,
            processed_files: 0,
            skipped_files: 0,
            failed_files: 0,
            created_materials: Vec::new(),
            errors: Vec::new(),
            processing_time: 0.0,
        };

        // 发布开始导入事件
        let _ = event_bus.publish_material_import_progress(
            request.project_id.clone(),
            "准备导入...".to_string(),
            0,
            result.total_files,
            "正在准备导入文件".to_string(),
        ).await;

        // 异步处理每个文件
        for (index, file_path) in request.file_paths.iter().enumerate() {
            debug!(file_path = %file_path, "异步处理文件");

            // 发布当前文件处理进度
            let _ = event_bus.publish_material_import_progress(
                request.project_id.clone(),
                file_path.clone(),
                index as u32,
                result.total_files,
                format!("正在处理文件: {}", Path::new(file_path).file_name()
                    .and_then(|n| n.to_str()).unwrap_or("unknown")),
            ).await;

            // 在独立的任务中处理文件，避免阻塞
            let repository_clone = Arc::clone(&repository);
            let project_id_clone = request.project_id.clone();
            let file_path_clone = file_path.clone();
            let config_clone = config.clone();
            let event_bus_clone = Arc::clone(&event_bus);
            let model_id_clone = request.model_id.clone();

            match Self::process_single_file_async(
                repository_clone,
                &project_id_clone,
                &file_path_clone,
                &config_clone,
                event_bus_clone,
                model_id_clone,
            ).await {
                Ok(Some(material)) => {
                    info!(
                        file_path = %file_path,
                        material_id = %material.id,
                        "文件异步处理成功"
                    );
                    result.created_materials.push(material);
                    result.processed_files += 1;
                }
                Ok(None) => {
                    // 文件被跳过（重复）
                    warn!(file_path = %file_path, "文件被跳过（重复）");
                    result.skipped_files += 1;
                }
                Err(e) => {
                    error!(
                        file_path = %file_path,
                        error = %e,
                        "文件异步处理失败"
                    );
                    result.failed_files += 1;
                    result.errors.push(format!("处理文件 {} 失败: {}", file_path, e));
                }
            }

            // 让出控制权，避免长时间占用线程
            tokio::task::yield_now().await;
        }

        result.processing_time = start_time.elapsed().as_secs_f64();

        let success = result.failed_files == 0;
        timer.finish(success);

        info!(
            processed_files = result.processed_files,
            skipped_files = result.skipped_files,
            failed_files = result.failed_files,
            processing_time = result.processing_time,
            "异步素材导入完成"
        );

        PERFORMANCE_MONITOR.record_metric("async_import_files_per_second",
            result.total_files as f64 / result.processing_time);

        // 发布导入完成事件
        if success {
            let _ = event_bus.publish_material_import_completed(
                request.project_id.clone(),
                result.clone(),
            ).await;
        } else {
            let _ = event_bus.publish_material_import_failed(
                request.project_id.clone(),
                format!("导入失败，{} 个文件处理失败", result.failed_files),
            ).await;
        }

        Ok(result)
    }

    /// 异步处理单个文件
    async fn process_single_file_async(
        repository: Arc<MaterialRepository>,
        project_id: &str,
        file_path: &str,
        config: &MaterialProcessingConfig,
        event_bus: Arc<EventBusManager>,
        model_id: Option<String>,
    ) -> Result<Option<Material>> {
        let _timer = PERFORMANCE_MONITOR.start_operation("async_process_single_file");

        // 验证文件路径
        error_utils::validate_file_path(file_path)
            .map_err(|e| anyhow!("文件验证失败: {}", e))?;

        let path = Path::new(file_path);

        // 获取文件信息
        let metadata = fs::metadata(path)?;
        let file_size = metadata.len();
        
        // 计算MD5哈希（在独立任务中执行）
        let file_path_clone = file_path.to_string();
        let md5_hash = task::spawn_blocking(move || {
            MaterialService::calculate_md5(&file_path_clone)
        }).await??;
        
        // 检查是否已存在相同的文件
        if repository.exists_by_md5(project_id, &md5_hash)? {
            return Ok(None); // 跳过重复文件
        }

        // 获取文件名和扩展名
        let file_name = path.file_name()
            .and_then(|n| n.to_str())
            .unwrap_or("unknown")
            .to_string();
        
        let extension = path.extension()
            .and_then(|ext| ext.to_str())
            .unwrap_or("");
        
        // 确定素材类型
        let material_type = MaterialType::from_extension(extension);
        
        // 创建素材对象（带模特绑定）
        let material = Material::new_with_model(
            project_id.to_string(),
            file_name.clone(),
            file_path.to_string(),
            file_size,
            md5_hash,
            material_type,
            model_id,
        );

        // 保存到数据库
        repository.create(&material)?;

        // 如果启用自动处理，则异步开始处理
        if config.auto_process.unwrap_or(true) {
            // 异步处理素材（提取元数据、场景检测等）
            let repository_clone = Arc::clone(&repository);
            let material_id = material.id.clone();
            let config_clone = config.clone();
            let event_bus_clone = Arc::clone(&event_bus);
            let file_name_clone = file_name.clone();

            // 在后台任务中处理，不阻塞导入流程
            tokio::spawn(async move {
                match Self::process_material_async(
                    repository_clone,
                    &material_id,
                    &config_clone,
                    event_bus_clone,
                    &file_name_clone,
                ).await {
                    Ok(_) => {
                        debug!(material_id = %material_id, "素材异步处理完成");
                    }
                    Err(e) => {
                        error!(material_id = %material_id, error = %e, "素材异步处理失败");
                    }
                }
            });
        }

        Ok(Some(material))
    }

    /// 异步处理单个素材（提取元数据、场景检测等）
    async fn process_material_async(
        repository: Arc<MaterialRepository>,
        material_id: &str,
        config: &MaterialProcessingConfig,
        event_bus: Arc<EventBusManager>,
        file_name: &str,
    ) -> Result<()> {
        // 更新状态为处理中
        MaterialService::update_material_status(
            &repository,
            material_id,
            ProcessingStatus::Processing,
            None,
        )?;

        // 发布处理开始事件
        let _ = event_bus.publish_material_processing_progress(
            material_id.to_string(),
            file_name.to_string(),
            "开始处理".to_string(),
            0.0,
        ).await;

        // 获取素材信息
        let mut material = repository.get_by_id(material_id)?
            .ok_or_else(|| anyhow!("素材不存在: {}", material_id))?;

        // 1. 异步提取元数据
        let _ = event_bus.publish_material_processing_progress(
            material_id.to_string(),
            file_name.to_string(),
            "提取元数据".to_string(),
            25.0,
        ).await;

        let original_path = material.original_path.clone();
        let material_type = material.material_type.clone();
        
        match task::spawn_blocking(move || {
            MaterialService::extract_metadata(&original_path, &material_type)
        }).await? {
            Ok(metadata) => {
                material.set_metadata(metadata);
                repository.update(&material)?;
            }
            Err(e) => {
                MaterialService::update_material_status(
                    &repository,
                    material_id,
                    ProcessingStatus::Failed,
                    Some(format!("元数据提取失败: {}", e)),
                )?;
                return Err(e);
            }
        }

        // 2. 异步场景检测（如果是视频且启用了场景检测）
        if matches!(material.material_type, MaterialType::Video) && config.enable_scene_detection {
            let _ = event_bus.publish_material_processing_progress(
                material_id.to_string(),
                file_name.to_string(),
                "场景检测".to_string(),
                50.0,
            ).await;

            let original_path = material.original_path.clone();
            let threshold = config.scene_detection_threshold;
            let skip_start_ms = config.skip_start_ms;

            match task::spawn_blocking(move || {
                // 如果设置了跳过开头，先创建临时视频文件
                let detection_file_path = if let Some(skip_ms) = skip_start_ms {
                    if skip_ms > 0 {
                        println!("异步处理 - AI生成视频前置跳过: {}ms", skip_ms);
                        match crate::infrastructure::ffmpeg::FFmpegService::create_trimmed_video(&original_path, skip_ms) {
                            Ok(temp_path) => {
                                println!("异步处理 - 临时视频创建成功: {}", temp_path);
                                temp_path
                            }
                            Err(e) => {
                                eprintln!("异步处理 - 创建临时视频失败，使用原视频: {}", e);
                                original_path.clone()
                            }
                        }
                    } else {
                        original_path.clone()
                    }
                } else {
                    original_path.clone()
                };

                let result = MaterialService::detect_video_scenes(&detection_file_path, threshold);

                // 处理结果并调整时间戳
                let final_result = match result {
                    Ok(mut scene_detection) => {
                        // 如果使用了临时文件，需要调整场景时间戳
                        if let Some(skip_ms) = skip_start_ms {
                            if skip_ms > 0 && detection_file_path != original_path {
                                let skip_seconds = skip_ms as f64 / 1000.0;
                                println!("异步处理 - 调整场景时间戳，补偿跳过的{}秒", skip_seconds);
                                for scene in &mut scene_detection.scenes {
                                    scene.start_time += skip_seconds;
                                    scene.end_time += skip_seconds;
                                }
                            }
                        }
                        Ok(scene_detection)
                    }
                    Err(e) => Err(e),
                };

                // 清理临时文件
                if detection_file_path != original_path {
                    if let Err(e) = std::fs::remove_file(&detection_file_path) {
                        eprintln!("异步处理 - 清理临时文件失败: {}", e);
                    } else {
                        println!("异步处理 - 临时文件清理成功: {}", detection_file_path);
                    }
                }

                final_result
            }).await? {
                Ok(scene_detection) => {
                    info!("异步场景检测成功，发现 {} 个场景", scene_detection.scenes.len());
                    material.set_scene_detection(scene_detection);
                    repository.update(&material)?;
                }
                Err(e) => {
                    // 场景检测失败不应该导致整个处理失败
                    warn!("异步场景检测失败: {}", e);
                }
            }
        }

        // 3. 异步检查是否需要切分视频
        let should_segment = material.needs_segmentation(config.max_segment_duration) ||
                           (matches!(material.material_type, MaterialType::Video) && material.scene_detection.is_some());

        if should_segment {
            let _ = event_bus.publish_material_processing_progress(
                material_id.to_string(),
                file_name.to_string(),
                "视频切分".to_string(),
                75.0,
            ).await;

            let repository_clone = Arc::clone(&repository);
            let material_clone = material.clone();
            let config_clone = config.clone();
            
            match task::spawn_blocking(move || {
                MaterialService::segment_video(&repository_clone, &material_clone, &config_clone)
            }).await? {
                Ok(_) => {
                    info!("异步视频切分完成: {}", material.name);
                }
                Err(e) => {
                    MaterialService::update_material_status(
                        &repository,
                        material_id,
                        ProcessingStatus::Failed,
                        Some(format!("视频切分失败: {}", e)),
                    )?;
                    return Err(e);
                }
            }
        }

        // 标记为完成
        MaterialService::update_material_status(
            &repository,
            material_id,
            ProcessingStatus::Completed,
            None,
        )?;

        // 发布处理完成事件
        let _ = event_bus.publish_material_processing_progress(
            material_id.to_string(),
            file_name.to_string(),
            "处理完成".to_string(),
            100.0,
        ).await;

        Ok(())
    }
}
