use serde::{Deserialize, Serialize};

use crate::operations::*;
use crate::pipeline::ProcessingJob;
use crate::types::*;

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct Preset {
    pub name: String,
    pub description: String,
    pub icon: String,
    pub icon_color: String,
    pub is_custom: bool,
    pub resize: Option<ResizeConfig>,
    pub rotation: Option<Rotation>,
    pub flip: Option<Flip>,
    pub convert: Option<ConvertConfig>,
    pub compress: Option<CompressConfig>,
    pub metadata: Option<MetadataConfig>,
    pub watermark: Option<WatermarkConfig>,
    pub rename: Option<RenameConfig>,
}

impl Default for Preset {
    fn default() -> Self {
        Self {
            name: String::new(),
            description: String::new(),
            icon: "image-x-generic-symbolic".into(),
            icon_color: String::new(),
            is_custom: true,
            resize: None,
            rotation: None,
            flip: None,
            convert: None,
            compress: None,
            metadata: None,
            watermark: None,
            rename: None,
        }
    }
}

impl Preset {
    pub fn to_job(
        &self,
        input_dir: impl Into<std::path::PathBuf>,
        output_dir: impl Into<std::path::PathBuf>,
    ) -> ProcessingJob {
        ProcessingJob {
            input_dir: input_dir.into(),
            output_dir: output_dir.into(),
            sources: Vec::new(),
            resize: self.resize.clone(),
            resize_algorithm: crate::operations::ResizeAlgorithm::default(),
            rotation: self.rotation,
            flip: self.flip,
            adjustments: None,
            convert: self.convert.clone(),
            compress: self.compress.clone(),
            metadata: self.metadata.clone(),
            watermark: self.watermark.clone(),
            rename: self.rename.clone(),
            overwrite_behavior: crate::operations::OverwriteAction::default(),
            preserve_directory_structure: false,
            progressive_jpeg: false,
            avif_speed: self.compress.as_ref().map(|c| match c {
                crate::operations::CompressConfig::Preset(p) => p.avif_speed(),
                _ => 6,
            }).unwrap_or(6),
            output_dpi: 0,
        }
    }

    pub fn all_builtins() -> Vec<Preset> {
        vec![
            Self::builtin_blog_photos(),
            Self::builtin_social_media(),
            Self::builtin_web_optimization(),
            Self::builtin_email_friendly(),
            Self::builtin_privacy_clean(),
            Self::builtin_photographer_export(),
            Self::builtin_archive_compress(),
            Self::builtin_fediverse_ready(),
            Self::builtin_print_ready(),
        ]
    }

    pub fn builtin_blog_photos() -> Preset {
        Preset {
            name: "Blog Photos".into(),
            description: "Resize 1200px wide, JPEG quality High, strip all metadata".into(),
            icon: "image-x-generic-symbolic".into(),
            icon_color: "accent".into(),
            is_custom: false,
            resize: Some(ResizeConfig::ByWidth(1200)),
            rotation: None,
            flip: None,
            convert: None,
            compress: Some(CompressConfig::Preset(QualityPreset::High)),
            metadata: Some(MetadataConfig::StripAll),
            watermark: None,
            rename: None,
        }
    }

    pub fn builtin_social_media() -> Preset {
        Preset {
            name: "Social Media".into(),
            description: "Resize to fit 1080x1080, compress Medium, strip metadata".into(),
            icon: "system-users-symbolic".into(),
            icon_color: "success".into(),
            is_custom: false,
            resize: Some(ResizeConfig::FitInBox {
                max: Dimensions {
                    width: 1080,
                    height: 1080,
                },
                allow_upscale: false,
            }),
            rotation: None,
            flip: None,
            convert: None,
            compress: Some(CompressConfig::Preset(QualityPreset::Medium)),
            metadata: Some(MetadataConfig::StripAll),
            watermark: None,
            rename: None,
        }
    }

    pub fn builtin_web_optimization() -> Preset {
        Preset {
            name: "Web Optimization".into(),
            description: "Convert to WebP, compress High, sequential rename".into(),
            icon: "web-browser-symbolic".into(),
            icon_color: "accent".into(),
            is_custom: false,
            resize: None,
            rotation: None,
            flip: None,
            convert: Some(ConvertConfig::SingleFormat(ImageFormat::WebP)),
            compress: Some(CompressConfig::Preset(QualityPreset::High)),
            metadata: Some(MetadataConfig::StripAll),
            watermark: None,
            rename: Some(RenameConfig {
                prefix: String::new(),
                suffix: String::new(),
                counter_start: 1,
                counter_padding: 3,
                counter_enabled: true,
                counter_position: 3,
                template: None,
                case_mode: 0,
                replace_spaces: 0,
                special_chars: 0,
                regex_find: String::new(),
                regex_replace: String::new(),
            }),
        }
    }

    pub fn builtin_email_friendly() -> Preset {
        Preset {
            name: "Email Friendly".into(),
            description: "Resize 800px wide, JPEG quality Medium".into(),
            icon: "mail-unread-symbolic".into(),
            icon_color: "warning".into(),
            is_custom: false,
            resize: Some(ResizeConfig::ByWidth(800)),
            rotation: None,
            flip: None,
            convert: None,
            compress: Some(CompressConfig::Preset(QualityPreset::Medium)),
            metadata: Some(MetadataConfig::StripAll),
            watermark: None,
            rename: None,
        }
    }

    pub fn builtin_privacy_clean() -> Preset {
        Preset {
            name: "Privacy Clean".into(),
            description: "Strip all metadata, no other changes".into(),
            icon: "security-high-symbolic".into(),
            icon_color: "error".into(),
            is_custom: false,
            resize: None,
            rotation: None,
            flip: None,
            convert: None,
            compress: None,
            metadata: Some(MetadataConfig::StripAll),
            watermark: None,
            rename: None,
        }
    }

    pub fn builtin_photographer_export() -> Preset {
        Preset {
            name: "Photographer Export".into(),
            description: "Resize 2048px, compress High, privacy metadata, rename by date".into(),
            icon: "camera-photo-symbolic".into(),
            icon_color: "success".into(),
            is_custom: false,
            resize: Some(ResizeConfig::ByWidth(2048)),
            rotation: None,
            flip: None,
            convert: None,
            compress: Some(CompressConfig::Preset(QualityPreset::High)),
            metadata: Some(MetadataConfig::Privacy),
            watermark: None,
            rename: Some(RenameConfig {
                prefix: String::new(),
                suffix: String::new(),
                counter_start: 1,
                counter_padding: 4,
                counter_enabled: true,
                counter_position: 3,
                template: Some("{exif_date}_{name}_{counter:4}".into()),
                case_mode: 0,
                replace_spaces: 0,
                special_chars: 0,
                regex_find: String::new(),
                regex_replace: String::new(),
            }),
        }
    }

    pub fn builtin_archive_compress() -> Preset {
        Preset {
            name: "Archive Compress".into(),
            description: "Lossless compression, preserve metadata".into(),
            icon: "folder-symbolic".into(),
            icon_color: "warning".into(),
            is_custom: false,
            resize: None,
            rotation: None,
            flip: None,
            convert: None,
            compress: Some(CompressConfig::Preset(QualityPreset::Maximum)),
            metadata: Some(MetadataConfig::KeepAll),
            watermark: None,
            rename: None,
        }
    }

    pub fn builtin_print_ready() -> Preset {
        Preset {
            name: "Print Ready".into(),
            description: "Maximum quality, convert to PNG, keep all metadata".into(),
            icon: "printer-symbolic".into(),
            icon_color: "success".into(),
            is_custom: false,
            resize: None,
            rotation: None,
            flip: None,
            convert: Some(ConvertConfig::SingleFormat(ImageFormat::Png)),
            compress: Some(CompressConfig::Preset(QualityPreset::Maximum)),
            metadata: Some(MetadataConfig::KeepAll),
            watermark: None,
            rename: None,
        }
    }

    pub fn builtin_fediverse_ready() -> Preset {
        Preset {
            name: "Fediverse Ready".into(),
            description: "Resize 1920x1080, convert to WebP, compress High, strip metadata".into(),
            icon: "network-server-symbolic".into(),
            icon_color: "accent".into(),
            is_custom: false,
            resize: Some(ResizeConfig::FitInBox {
                max: Dimensions {
                    width: 1920,
                    height: 1080,
                },
                allow_upscale: false,
            }),
            rotation: None,
            flip: None,
            convert: Some(ConvertConfig::SingleFormat(ImageFormat::WebP)),
            compress: Some(CompressConfig::Preset(QualityPreset::High)),
            metadata: Some(MetadataConfig::StripAll),
            watermark: None,
            rename: None,
        }
    }
}
