//! Video upscaling implementation

use std::path::Path;
use std::time::Instant;
use crate::core::{TvaiError, TvaiProcessor, ProcessResult, ProgressCallback};
use crate::video::VideoUpscaleParams;

/// Video upscaling implementation
impl TvaiProcessor {
    /// Upscale a video using Topaz AI models
    pub async fn upscale_video(
        &mut self,
        input_path: &Path,
        output_path: &Path,
        params: VideoUpscaleParams,
        progress_callback: Option<&ProgressCallback>,
    ) -> Result<ProcessResult, TvaiError> {
        let start_time = Instant::now();

        // Validate inputs
        self.validate_input_file(input_path)?;
        self.validate_output_path(output_path)?;

        // Validate parameters
        self.validate_upscale_params(&params)?;

        let operation_id = self.generate_operation_id();

        if let Some(callback) = progress_callback {
            callback(0.0);
        }

        // Build Topaz upscaling filter
        let upscale_filter = self.build_upscale_filter(&params)?;

        if let Some(callback) = progress_callback {
            callback(0.1);
        }

        // Build FFmpeg command with Topaz filters
        let mut args = vec![
            "-y", "-hide_banner", "-nostdin", "-strict", "2",
            "-hwaccel", "auto",
            "-i", input_path.to_str().unwrap(),
            "-vf", &upscale_filter,
        ];

        // 构建所有参数字符串
        let mut all_args = Vec::new();

        // 添加编码参数
        let encoding_args = self.build_encoding_args(&params)?;
        all_args.extend(encoding_args);

        // 添加音频参数
        let audio_args = self.build_audio_args(&params.audio_mode)?;
        all_args.extend(audio_args);

        // 添加元数据参数
        let metadata_args = self.build_metadata_args(&params)?;
        all_args.extend(metadata_args);

        // 转换为&str并添加到args
        for arg in &all_args {
            args.push(arg.as_str());
        }

        args.push(output_path.to_str().unwrap());

        if let Some(callback) = progress_callback {
            callback(0.2);
        }

        // Execute Topaz upscaling (requires Topaz FFmpeg)
        self.execute_ffmpeg_command(&args, true, progress_callback).await?;

        let processing_time = start_time.elapsed();

        // Get FFmpeg version for metadata
        let ffmpeg_version = self.get_ffmpeg_version(true).await.ok();

        // Create result metadata
        let mut metadata = self.create_metadata(
            operation_id,
            input_path,
            format!("upscale: model={}, scale={}, compression={}, blend={}",
                params.model.as_str(),
                params.scale_factor,
                params.compression,
                params.blend
            ),
        );
        metadata.ffmpeg_version = ffmpeg_version;

        if let Some(callback) = progress_callback {
            callback(1.0);
        }

        Ok(ProcessResult {
            output_path: output_path.to_path_buf(),
            processing_time,
            metadata,
        })
    }

    /// Validate upscaling parameters
    fn validate_upscale_params(&self, params: &VideoUpscaleParams) -> Result<(), TvaiError> {
        // 验证基础参数
        if params.scale_factor < 0.0 || params.scale_factor > 4.0 {
            return Err(TvaiError::InvalidParameter(
                format!("Scale factor must be between 0.0 and 4.0, got {}", params.scale_factor)
            ));
        }

        if params.compression < -1.0 || params.compression > 1.0 {
            return Err(TvaiError::InvalidParameter(
                format!("Compression must be between -1.0 and 1.0, got {}", params.compression)
            ));
        }

        if params.blend < 0.0 || params.blend > 1.0 {
            return Err(TvaiError::InvalidParameter(
                format!("Blend must be between 0.0 and 1.0, got {}", params.blend)
            ));
        }

        // 验证TVAI参数
        if params.preblur < 0.0 || params.preblur > 100.0 {
            return Err(TvaiError::InvalidParameter(
                format!("Preblur must be between 0.0 and 100.0, got {}", params.preblur)
            ));
        }

        if params.noise < 0.0 || params.noise > 100.0 {
            return Err(TvaiError::InvalidParameter(
                format!("Noise must be between 0.0 and 100.0, got {}", params.noise)
            ));
        }

        if params.details < 0.0 || params.details > 100.0 {
            return Err(TvaiError::InvalidParameter(
                format!("Details must be between 0.0 and 100.0, got {}", params.details)
            ));
        }

        if params.halo < 0.0 || params.halo > 100.0 {
            return Err(TvaiError::InvalidParameter(
                format!("Halo must be between 0.0 and 100.0, got {}", params.halo)
            ));
        }

        if params.blur < 0.0 || params.blur > 100.0 {
            return Err(TvaiError::InvalidParameter(
                format!("Blur must be between 0.0 and 100.0, got {}", params.blur)
            ));
        }

        if params.estimate < 1 || params.estimate > 20 {
            return Err(TvaiError::InvalidParameter(
                format!("Estimate must be between 1 and 20, got {}", params.estimate)
            ));
        }

        if params.instances < 1 || params.instances > 4 {
            return Err(TvaiError::InvalidParameter(
                format!("Instances must be between 1 and 4, got {}", params.instances)
            ));
        }

        // 验证编码参数
        if params.quality_param > 51 {
            return Err(TvaiError::InvalidParameter(
                format!("Quality parameter must be <= 51, got {}", params.quality_param)
            ));
        }

        if params.aq_strength > 15 {
            return Err(TvaiError::InvalidParameter(
                format!("AQ strength must be <= 15, got {}", params.aq_strength)
            ));
        }

        // Check if model forces a specific scale
        if let Some(forced_scale) = params.model.forces_scale() {
            if params.scale_factor > 0.0 && (params.scale_factor - forced_scale).abs() > 0.01 {
                return Err(TvaiError::InvalidParameter(
                    format!("Model {} forces scale factor {}, but {} was requested",
                        params.model.as_str(), forced_scale, params.scale_factor)
                ));
            }
        }

        Ok(())
    }

    /// Build Topaz upscaling filter string
    fn build_upscale_filter(&self, params: &VideoUpscaleParams) -> Result<String, TvaiError> {
        let mut filter_parts = Vec::new();

        // 构建TVAI upscale滤镜
        let mut tvai_params = vec![
            format!("model={}", params.model.as_str()),
            format!("scale={}", if params.scale_factor == 0.0 { 0 } else { params.scale_factor as u32 }),
            format!("preblur={}", params.preblur),
            format!("noise={}", params.noise),
            format!("details={}", params.details),
            format!("halo={}", params.halo),
            format!("blur={}", params.blur),
            format!("compression={}", params.compression),
            format!("estimate={}", params.estimate),
            format!("blend={}", params.blend),
            format!("device={}", params.device),
            format!("vram={}", params.vram),
            format!("instances={}", params.instances),
        ];

        // 如果指定了目标尺寸，添加宽高参数
        if let (Some(width), Some(height)) = (params.target_width, params.target_height) {
            tvai_params.push(format!("w={}", width));
            tvai_params.push(format!("h={}", height));
        }

        let tvai_filter = format!("tvai_up={}", tvai_params.join(":"));
        filter_parts.push(tvai_filter);

        // 如果需要额外的缩放和填充
        if let (Some(width), Some(height)) = (params.target_width, params.target_height) {
            if params.maintain_aspect {
                // 添加缩放滤镜保持宽高比
                let scale_filter = format!(
                    "scale=w={}:h={}:flags=lanczos:threads=0:force_original_aspect_ratio=decrease",
                    width, height
                );
                filter_parts.push(scale_filter);

                // 添加填充滤镜
                let pad_filter = format!(
                    "pad={}:{}:-1:-1:color={}",
                    width, height, params.pad_color
                );
                filter_parts.push(pad_filter);
            }
        }

        Ok(filter_parts.join(","))
    }

    /// Build encoding arguments
    fn build_encoding_args(&self, params: &VideoUpscaleParams) -> Result<Vec<String>, TvaiError> {
        let mut args = Vec::new();

        // 确定编码器
        let codec = params.codec.as_deref().unwrap_or_else(|| {
            if self.is_gpu_enabled() {
                "h264_nvenc"
            } else {
                "libx264"
            }
        });

        args.extend_from_slice(&["-c:v".to_string(), codec.to_string()]);

        // 添加编码配置文件
        if let Some(profile) = &params.profile {
            args.extend_from_slice(&["-profile:v".to_string(), profile.clone()]);
        }

        // 添加像素格式
        args.extend_from_slice(&["-pix_fmt".to_string(), params.pixel_format.clone()]);

        // 添加GOP大小
        args.extend_from_slice(&["-g".to_string(), params.gop_size.to_string()]);

        if codec.contains("nvenc") {
            // NVIDIA GPU编码器参数
            if let Some(preset) = &params.preset {
                args.extend_from_slice(&["-preset".to_string(), preset.clone()]);
            }
            if let Some(tune) = &params.tune {
                args.extend_from_slice(&["-tune".to_string(), tune.clone()]);
            }
            args.extend_from_slice(&["-rc".to_string(), params.rate_control.clone()]);
            args.extend_from_slice(&["-qp".to_string(), params.quality_param.to_string()]);
            args.extend_from_slice(&["-rc-lookahead".to_string(), params.lookahead.to_string()]);

            if params.spatial_aq {
                args.extend_from_slice(&["-spatial_aq".to_string(), "1".to_string()]);
                args.extend_from_slice(&["-aq-strength".to_string(), params.aq_strength.to_string()]);
            }

            if params.bitrate > 0 {
                args.extend_from_slice(&["-b:v".to_string(), params.bitrate.to_string()]);
            } else {
                args.extend_from_slice(&["-b:v".to_string(), "0".to_string()]);
            }

            if params.buffer_frames > 0 {
                args.extend_from_slice(&["-bf".to_string(), params.buffer_frames.to_string()]);
            } else {
                args.extend_from_slice(&["-bf".to_string(), "0".to_string()]);
            }
        } else {
            // CPU编码器参数
            if let Some(preset) = &params.preset {
                args.extend_from_slice(&["-preset".to_string(), preset.clone()]);
            }
            if let Some(tune) = &params.tune {
                args.extend_from_slice(&["-tune".to_string(), tune.clone()]);
            }
            args.extend_from_slice(&["-crf".to_string(), params.quality_param.to_string()]);
        }

        // 添加帧率模式
        args.extend_from_slice(&["-fps_mode:v".to_string(), "passthrough".to_string()]);

        // 添加MOV标志
        args.extend_from_slice(&[
            "-movflags".to_string(),
            "frag_keyframe+empty_moov+delay_moov+use_metadata_tags+write_colr".to_string()
        ]);

        Ok(args)
    }

    /// Build audio arguments
    fn build_audio_args(&self, audio_mode: &crate::video::AudioMode) -> Result<Vec<String>, TvaiError> {
        let mut args = Vec::new();

        match audio_mode {
            crate::video::AudioMode::Keep => {
                // 保留音频，复制流
                args.extend_from_slice(&["-c:a".to_string(), "copy".to_string()]);
            }
            crate::video::AudioMode::Remove => {
                // 移除音频
                args.push("-an".to_string());
            }
            crate::video::AudioMode::Reencode { codec, bitrate } => {
                // 重新编码音频
                args.extend_from_slice(&["-c:a".to_string(), codec.clone()]);
                args.extend_from_slice(&["-b:a".to_string(), format!("{}k", bitrate)]);
            }
        }
        Ok(args)
    }

    /// Build metadata arguments
    fn build_metadata_args(&self, params: &VideoUpscaleParams) -> Result<Vec<String>, TvaiError> {
        let mut args = Vec::new();

        if params.preserve_metadata {
            args.extend_from_slice(&["-map_metadata".to_string(), "0".to_string()]);
            args.extend_from_slice(&["-map_metadata:s:v".to_string(), "0:s:v".to_string()]);
        }

        // 添加自定义元数据
        if let Some(custom_metadata) = &params.custom_metadata {
            args.extend_from_slice(&["-metadata".to_string(), custom_metadata.clone()]);
        } else {
            // 添加默认的VideoAI元数据
            let metadata = format!(
                "videoai=Enhanced using {}; mode: auto; revert compression at {}; recover details at {}; sharpen at {}; reduce noise at {}; dehalo at {}; anti-alias/deblur at {}; focus fix Off; and recover original detail at {}. Changed resolution to {}x{}",
                params.model.as_str(),
                params.compression,
                params.details,
                params.blur,
                params.noise,
                params.halo,
                params.blur,
                params.blend * 100.0,
                params.target_width.unwrap_or(0),
                params.target_height.unwrap_or(0)
            );
            args.extend_from_slice(&["-metadata".to_string(), metadata]);
        }

        Ok(args)
    }
}
