//! Video format conversion utilities

use std::path::{Path, PathBuf};
use std::fs;
use crate::core::{TvaiError, TvaiProcessor, ProgressCallback};
use crate::config::QualityPreset;

/// Video conversion utilities
impl TvaiProcessor {
    /// Convert image sequence to video
    pub async fn images_to_video(
        &mut self,
        image_paths: &[PathBuf],
        output_path: &Path,
        fps: f32,
        quality_preset: QualityPreset,
        progress_callback: Option<&ProgressCallback>,
    ) -> Result<(), TvaiError> {
        self.validate_output_path(output_path)?;

        if image_paths.is_empty() {
            return Err(TvaiError::InvalidParameter("No input images provided".to_string()));
        }

        // Validate all input images exist
        for image_path in image_paths {
            self.validate_input_file(image_path)?;
        }

        let operation_id = self.generate_operation_id();

        // Create temporary directory for frame sequence
        let temp_dir = self.create_temp_dir(&operation_id)?;

        // Copy and rename images to sequential format
        if let Some(callback) = progress_callback {
            callback(0.1);
        }

        self.prepare_image_sequence(image_paths, &temp_dir, &operation_id).await?;

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

        // Build FFmpeg command
        let frame_pattern = temp_dir.join("frame_%05d.png");
        let (codec, preset) = quality_preset.get_encoding_settings(self.is_gpu_enabled());
        let quality = quality_preset.get_quality_value(self.is_gpu_enabled());

        let fps_str = fps.to_string();
        let mut args = vec![
            "-y", "-hide_banner", "-nostdin",
            "-r", &fps_str,
            "-i", frame_pattern.to_str().unwrap(),
            "-c:v", codec,
        ];

        if self.is_gpu_enabled() {
            args.extend_from_slice(&["-preset", preset, "-global_quality", quality]);
        } else {
            args.extend_from_slice(&["-preset", preset, "-crf", quality]);
        }

        args.extend_from_slice(&["-pix_fmt", "yuv420p"]);
        args.push(output_path.to_str().unwrap());

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

        // Execute FFmpeg command
        self.execute_ffmpeg_command(&args, false, progress_callback).await?;

        // Cleanup temporary files
        self.cleanup_temp_files(&operation_id)?;

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

        Ok(())
    }

    /// Convert video to image sequence
    pub async fn video_to_images(
        &mut self,
        input_path: &Path,
        output_dir: &Path,
        image_format: &str,
        quality: u8,
        progress_callback: Option<&ProgressCallback>,
    ) -> Result<Vec<PathBuf>, TvaiError> {
        self.validate_input_file(input_path)?;

        // Create output directory if it doesn't exist
        fs::create_dir_all(output_dir)?;

        let _operation_id = self.generate_operation_id();
        let output_pattern = output_dir.join(format!("frame_%05d.{}", image_format));

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

        // Build FFmpeg command for extraction
        let mut args = vec![
            "-y", "-hide_banner", "-nostdin",
            "-i", input_path.to_str().unwrap(),
            "-vsync", "0",
        ];

        // Add quality settings based on format
        let quality_str = (101 - quality).to_string();
        match image_format.to_lowercase().as_str() {
            "png" => {
                args.extend_from_slice(&["-compression_level", "6"]);
            }
            "jpg" | "jpeg" => {
                args.extend_from_slice(&["-q:v", &quality_str]);
            }
            _ => {}
        }

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

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

        // Execute FFmpeg command
        self.execute_ffmpeg_command(&args, false, progress_callback).await?;

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

        // Collect generated image paths
        let mut image_paths = Vec::new();
        if let Ok(entries) = fs::read_dir(output_dir) {
            for entry in entries.flatten() {
                let path = entry.path();
                if let Some(extension) = path.extension() {
                    if extension.to_string_lossy().to_lowercase() == image_format.to_lowercase() {
                        image_paths.push(path);
                    }
                }
            }
        }

        // Sort paths to ensure correct order
        image_paths.sort();

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

        Ok(image_paths)
    }

    /// Prepare image sequence with proper naming
    async fn prepare_image_sequence(
        &self,
        image_paths: &[PathBuf],
        temp_dir: &Path,
        _operation_id: &str,
    ) -> Result<(), TvaiError> {
        for (index, image_path) in image_paths.iter().enumerate() {
            let target_name = format!("frame_{:05}.png", index + 1);
            let target_path = temp_dir.join(target_name);

            // Copy image to temp directory with sequential naming
            fs::copy(image_path, target_path)?;
        }

        Ok(())
    }
}
