use anyhow::{Result, anyhow};
use std::path::{Path, PathBuf};
use std::sync::Arc;
use tracing::{info, error, warn};
use uuid::Uuid;

use crate::data::models::thumbnail::{
    ThumbnailConfig, ThumbnailSize, TimePoint, ImageFormat,
    TimelineConfig, ThumbnailGenerationResult, ThumbnailMetadata,
    VideoFile, SceneDetectionResult, SceneInfo, SceneDetectionMethod,
    ThumbnailGenerationOptions
};
use crate::infrastructure::ffmpeg::FFmpegService;
use crate::infrastructure::filename_utils::FilenameUtils;

/// 缩略图生成服务
/// 遵循 Tauri 开发规范的服务层设计原则
pub struct ThumbnailGeneratorService {
    ffmpeg_service: Arc<FFmpegService>,
    options: ThumbnailGenerationOptions,
}

impl ThumbnailGeneratorService {
    /// 创建新的缩略图生成服务实例
    pub fn new(options: ThumbnailGenerationOptions) -> Self {
        Self {
            ffmpeg_service: Arc::new(FFmpegService),
            options,
        }
    }

    /// 为单个视频生成缩略图
    pub async fn generate_thumbnail(
        &self,
        video_path: &str,
        config: &ThumbnailConfig,
    ) -> Result<ThumbnailGenerationResult> {
        let start_time = std::time::Instant::now();
        
        info!(
            video_path = %video_path,
            config = ?config,
            "开始生成视频缩略图"
        );

        // 验证输入文件
        self.validate_video_file(video_path)?;

        // 获取视频信息
        let video_info = FFmpegService::get_video_info(video_path)?;
        let video_duration = video_info.duration;
        let video_resolution = (
            video_info.width,
            video_info.height
        );

        // 计算实际时间戳
        let timestamps = self.calculate_timestamps(&config.time_points, video_duration)?;
        
        // 确保输出目录存在
        std::fs::create_dir_all(&config.output_dir)?;

        // 生成缩略图
        let mut output_paths = Vec::new();
        let mut total_file_size = 0u64;

        for (index, timestamp) in timestamps.iter().enumerate() {
            let output_path = self.generate_output_path(
                video_path,
                *timestamp,
                index,
                config
            )?;

            match self.generate_single_thumbnail(
                video_path,
                &output_path,
                *timestamp,
                &config.size,
                &config.format,
                config.quality,
            ).await {
                Ok(_) => {
                    if let Ok(metadata) = std::fs::metadata(&output_path) {
                        total_file_size += metadata.len();
                    }
                    output_paths.push(output_path);
                }
                Err(e) => {
                    error!(
                        video_path = %video_path,
                        timestamp = timestamp,
                        error = %e,
                        "单个缩略图生成失败"
                    );
                    if !self.options.enable_retry {
                        return Err(e);
                    }
                }
            }
        }

        let processing_time = start_time.elapsed().as_millis() as u64;

        let result = ThumbnailGenerationResult {
            video_path: video_path.to_string(),
            success: !output_paths.is_empty(),
            output_paths,
            timeline_path: None,
            processing_time_ms: processing_time,
            error_message: None,
            metadata: ThumbnailMetadata {
                video_duration,
                video_resolution,
                thumbnail_count: timestamps.len() as u32,
                total_file_size,
                timestamps_used: timestamps,
            },
        };

        info!(
            video_path = %video_path,
            thumbnail_count = result.metadata.thumbnail_count,
            processing_time_ms = processing_time,
            "缩略图生成完成"
        );

        Ok(result)
    }

    /// 生成时间轴缩略图条
    pub async fn generate_timeline_thumbnail(
        &self,
        video_path: &str,
        config: &TimelineConfig,
        thumbnail_config: &ThumbnailConfig,
    ) -> Result<String> {
        info!(
            video_path = %video_path,
            frame_count = config.frame_count,
            layout = ?config.layout,
            "开始生成时间轴缩略图"
        );

        // 获取视频信息
        let video_info = FFmpegService::get_video_info(video_path)?;
        let video_duration = video_info.duration;

        // 计算时间轴帧的时间戳
        let timestamps = self.calculate_timeline_timestamps(video_duration, config.frame_count)?;

        // 生成临时缩略图
        let mut temp_thumbnails = Vec::new();
        for (index, timestamp) in timestamps.iter().enumerate() {
            let temp_path = thumbnail_config.output_dir.join(format!(
                "temp_timeline_{}_{}.jpg",
                Uuid::new_v4().to_string(),
                index
            ));

            self.generate_single_thumbnail(
                video_path,
                &temp_path.to_string_lossy(),
                *timestamp,
                &thumbnail_config.size,
                &ImageFormat::Jpg,
                thumbnail_config.quality,
            ).await?;

            temp_thumbnails.push(temp_path);
        }

        // 合成时间轴缩略图
        let timeline_path = self.compose_timeline_thumbnail(
            &temp_thumbnails,
            config,
            thumbnail_config,
            video_path,
        ).await?;

        // 清理临时文件
        for temp_path in temp_thumbnails {
            let _ = std::fs::remove_file(temp_path);
        }

        info!(
            video_path = %video_path,
            timeline_path = %timeline_path,
            "时间轴缩略图生成完成"
        );

        Ok(timeline_path)
    }

    /// 智能场景检测
    pub async fn detect_best_frames(
        &self,
        video_path: &str,
        frame_count: u32,
    ) -> Result<SceneDetectionResult> {
        info!(
            video_path = %video_path,
            frame_count = frame_count,
            "开始智能场景检测"
        );

        // 获取视频信息
        let video_info = FFmpegService::get_video_info(video_path)?;
        let video_duration = video_info.duration;

        // 使用FFmpeg的场景检测功能
        let scenes = self.detect_scenes_with_ffmpeg(video_path, video_duration).await?;
        
        // 从场景中选择最佳帧
        let best_frames = self.select_best_frames_from_scenes(&scenes, frame_count);

        let result = SceneDetectionResult {
            video_path: video_path.to_string(),
            scenes,
            best_frames,
            detection_method: SceneDetectionMethod::ContentBased,
            confidence_scores: vec![0.8; frame_count as usize], // 简化的置信度
        };

        info!(
            video_path = %video_path,
            scene_count = result.scenes.len(),
            best_frame_count = result.best_frames.len(),
            "场景检测完成"
        );

        Ok(result)
    }

    /// 验证视频文件
    fn validate_video_file(&self, video_path: &str) -> Result<()> {
        if !Path::new(video_path).exists() {
            return Err(anyhow!("视频文件不存在: {}", video_path));
        }

        if !FilenameUtils::is_video_file(video_path) {
            return Err(anyhow!("不支持的视频格式: {}", video_path));
        }

        if self.options.enable_validation {
            let metadata = std::fs::metadata(video_path)?;
            if metadata.len() < self.options.min_file_size {
                return Err(anyhow!("视频文件太小: {} bytes", metadata.len()));
            }
        }

        Ok(())
    }

    /// 计算时间戳
    fn calculate_timestamps(&self, time_points: &[TimePoint], duration: f64) -> Result<Vec<f64>> {
        let mut timestamps = Vec::new();

        for time_point in time_points {
            match time_point {
                TimePoint::Fixed(seconds) => {
                    let timestamp = seconds.min(duration).max(0.0);
                    timestamps.push(timestamp);
                }
                TimePoint::Percentage(percentage) => {
                    let timestamp = duration * (*percentage as f64);
                    timestamps.push(timestamp.min(duration).max(0.0));
                }
                TimePoint::Multiple(points) => {
                    for point in points {
                        let timestamp = point.min(duration).max(0.0);
                        timestamps.push(timestamp);
                    }
                }
                TimePoint::SmartDetection(count) => {
                    // 这里应该调用智能检测，暂时使用均匀分布
                    for i in 0..*count {
                        let percentage = (i as f64 + 1.0) / (*count as f64 + 1.0);
                        let timestamp = duration * percentage;
                        timestamps.push(timestamp);
                    }
                }
            }
        }

        // 去重并排序
        timestamps.sort_by(|a, b| a.partial_cmp(b).unwrap());
        timestamps.dedup_by(|a, b| (*a - *b).abs() < 0.1); // 0.1秒内的时间戳视为重复

        Ok(timestamps)
    }

    /// 计算时间轴时间戳
    fn calculate_timeline_timestamps(&self, duration: f64, frame_count: u32) -> Result<Vec<f64>> {
        let mut timestamps = Vec::new();
        
        for i in 0..frame_count {
            let percentage = (i as f64 + 0.5) / frame_count as f64;
            let timestamp = duration * percentage;
            timestamps.push(timestamp);
        }

        Ok(timestamps)
    }

    /// 生成输出路径
    fn generate_output_path(
        &self,
        video_path: &str,
        timestamp: f64,
        index: usize,
        config: &ThumbnailConfig,
    ) -> Result<String> {
        let video_name = Path::new(video_path)
            .file_stem()
            .and_then(|s| s.to_str())
            .unwrap_or("video");

        let filename = config.naming_pattern
            .replace("{filename}", video_name)
            .replace("{timestamp}", &format!("{:.1}", timestamp))
            .replace("{index}", &index.to_string())
            .replace("{ext}", config.format.extension());

        let output_path = config.output_dir.join(filename);
        Ok(output_path.to_string_lossy().to_string())
    }

    /// 生成单个缩略图
    async fn generate_single_thumbnail(
        &self,
        video_path: &str,
        output_path: &str,
        timestamp: f64,
        size: &ThumbnailSize,
        _format: &ImageFormat,
        _quality: u8,
    ) -> Result<()> {
        let mut attempts = 0;
        let max_attempts = if self.options.enable_retry { self.options.max_retries + 1 } else { 1 };

        while attempts < max_attempts {
            match FFmpegService::generate_thumbnail(
                video_path,
                output_path,
                timestamp,
                size.width,
                size.height,
            ) {
                Ok(_) => {
                    // 验证生成的文件
                    if Path::new(output_path).exists() {
                        return Ok(());
                    } else {
                        return Err(anyhow!("缩略图文件生成失败"));
                    }
                }
                Err(e) => {
                    attempts += 1;
                    if attempts < max_attempts {
                        warn!(
                            video_path = %video_path,
                            timestamp = timestamp,
                            attempt = attempts,
                            error = %e,
                            "缩略图生成失败，正在重试"
                        );
                        tokio::time::sleep(tokio::time::Duration::from_millis(
                            self.options.retry_delay_ms
                        )).await;
                    } else {
                        return Err(e);
                    }
                }
            }
        }

        Err(anyhow!("缩略图生成失败，已达到最大重试次数"))
    }

    /// 使用FFmpeg进行场景检测
    async fn detect_scenes_with_ffmpeg(
        &self,
        _video_path: &str,
        duration: f64,
    ) -> Result<Vec<SceneInfo>> {
        // 简化的场景检测实现
        // 在实际应用中，这里应该使用FFmpeg的scene filter
        let scene_count = (duration / 30.0).ceil() as u32; // 每30秒一个场景
        let mut scenes = Vec::new();

        for i in 0..scene_count {
            let start_time = i as f64 * 30.0;
            let end_time = ((i + 1) as f64 * 30.0).min(duration);
            let scene_duration = end_time - start_time;

            scenes.push(SceneInfo {
                start_time,
                end_time,
                duration: scene_duration,
                confidence: 0.8, // 简化的置信度
                representative_frame: start_time + scene_duration / 2.0,
            });
        }

        Ok(scenes)
    }

    /// 从场景中选择最佳帧
    fn select_best_frames_from_scenes(
        &self,
        scenes: &[SceneInfo],
        frame_count: u32,
    ) -> Vec<f64> {
        let mut best_frames = Vec::new();

        if scenes.is_empty() {
            return best_frames;
        }

        // 如果请求的帧数少于或等于场景数，从每个场景选择代表帧
        if frame_count <= scenes.len() as u32 {
            let step = scenes.len() / frame_count as usize;
            for i in (0..scenes.len()).step_by(step.max(1)) {
                if best_frames.len() < frame_count as usize {
                    best_frames.push(scenes[i].representative_frame);
                }
            }
        } else {
            // 如果请求的帧数多于场景数，在每个场景内选择多个帧
            let frames_per_scene = frame_count / scenes.len() as u32;
            let extra_frames = frame_count % scenes.len() as u32;

            for (scene_index, scene) in scenes.iter().enumerate() {
                let mut scene_frame_count = frames_per_scene;
                if scene_index < extra_frames as usize {
                    scene_frame_count += 1;
                }

                for i in 0..scene_frame_count {
                    let progress = (i as f64 + 0.5) / scene_frame_count as f64;
                    let frame_time = scene.start_time + scene.duration * progress;
                    best_frames.push(frame_time);
                }
            }
        }

        best_frames.sort_by(|a, b| a.partial_cmp(b).unwrap());
        best_frames
    }

    /// 合成时间轴缩略图
    async fn compose_timeline_thumbnail(
        &self,
        temp_thumbnails: &[PathBuf],
        _config: &TimelineConfig,
        thumbnail_config: &ThumbnailConfig,
        video_path: &str,
    ) -> Result<String> {
        let video_name = Path::new(video_path)
            .file_stem()
            .and_then(|s| s.to_str())
            .unwrap_or("video");

        let timeline_filename = format!("{}_timeline.{}", video_name, thumbnail_config.format.extension());
        let timeline_path = thumbnail_config.output_dir.join(timeline_filename);

        // 这里应该使用图像处理库（如image crate）来合成时间轴
        // 为了简化，我们暂时复制第一个缩略图作为时间轴
        if let Some(first_thumbnail) = temp_thumbnails.first() {
            std::fs::copy(first_thumbnail, &timeline_path)?;
        }

        Ok(timeline_path.to_string_lossy().to_string())
    }

    /// 扫描文件夹中的视频文件
    pub fn scan_video_files(&self, folder_path: &str) -> Result<Vec<VideoFile>> {
        let mut video_files = Vec::new();
        let folder = Path::new(folder_path);

        if !folder.exists() || !folder.is_dir() {
            return Err(anyhow!("文件夹不存在或不是目录: {}", folder_path));
        }

        for entry in std::fs::read_dir(folder)? {
            let entry = entry?;
            let path = entry.path();

            if path.is_file() {
                let path_str = path.to_string_lossy().to_string();
                if FilenameUtils::is_video_file(&path_str) {
                    let video_file = self.create_video_file_info(&path)?;
                    video_files.push(video_file);
                }
            }
        }

        video_files.sort_by(|a, b| a.name.cmp(&b.name));
        Ok(video_files)
    }

    /// 创建视频文件信息
    fn create_video_file_info(&self, path: &Path) -> Result<VideoFile> {
        let metadata = std::fs::metadata(path)?;
        let name = path.file_name()
            .and_then(|s| s.to_str())
            .unwrap_or("unknown")
            .to_string();

        let path_str = path.to_string_lossy().to_string();

        // 尝试获取视频信息
        let (duration, resolution, format, is_valid) = match FFmpegService::get_video_info(&path_str) {
            Ok(info) => (
                Some(info.duration),
                Some((info.width, info.height)),
                Some(info.format),
                true
            ),
            Err(_) => (None, None, None, false),
        };

        Ok(VideoFile {
            path: path.to_path_buf(),
            name,
            size: metadata.len(),
            duration,
            resolution,
            format,
            is_valid,
        })
    }
}
