use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};

/// 图像编辑API配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImageEditingConfig {
    pub api_url: String,
    pub api_key: String,
    pub model_id: String,
    pub timeout: u64,
    pub max_retries: u32,
    pub retry_delay: u64,
}

impl Default for ImageEditingConfig {
    fn default() -> Self {
        Self {
            api_url: "https://ark.cn-beijing.volces.com/api/v3/images/generations".to_string(),
            api_key: "21575c22-14aa-40ca-8aa8-f00ca27a3a17".to_string(),
            model_id: "doubao-seededit-3-0-i2i-250628".to_string(),
            timeout: 120,
            max_retries: 3,
            retry_delay: 2,
        }
    }
}

/// 图像编辑请求参数
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImageEditingRequest {
    pub model: String,
    pub prompt: String,
    pub image: String, // Base64编码或URL
    #[serde(skip_serializing_if = "Option::is_none")]
    pub response_format: Option<String>, // "url" 或 "b64_json"
    #[serde(skip_serializing_if = "Option::is_none")]
    pub size: Option<String>, // "adaptive"
    #[serde(skip_serializing_if = "Option::is_none")]
    pub seed: Option<i32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub guidance_scale: Option<f32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub watermark: Option<bool>,
}

impl Default for ImageEditingRequest {
    fn default() -> Self {
        Self {
            model: "doubao-seededit-3-0-i2i-250628".to_string(),
            prompt: String::new(),
            image: String::new(),
            response_format: Some("url".to_string()),
            size: Some("adaptive".to_string()),
            seed: Some(-1),
            guidance_scale: Some(5.5),
            watermark: Some(false),
        }
    }
}

/// 图像编辑响应数据
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImageEditingResponseData {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub url: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub b64_json: Option<String>,
}

/// 图像编辑使用量信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImageEditingUsage {
    pub generated_images: u32,
    pub output_tokens: u32,
    pub total_tokens: u32,
}

/// 图像编辑错误信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImageEditingError {
    pub code: String,
    pub message: String,
}

/// 图像编辑API响应
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImageEditingResponse {
    pub model: String,
    pub created: u64,
    pub data: Vec<ImageEditingResponseData>,
    pub usage: ImageEditingUsage,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub error: Option<ImageEditingError>,
}

/// 图像编辑任务状态
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ImageEditingTaskStatus {
    Pending,
    Processing,
    Completed,
    Failed,
    Cancelled,
}

/// 图像编辑任务
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImageEditingTask {
    pub id: String,
    pub input_image_path: String,
    pub output_image_path: Option<String>,
    pub prompt: String,
    pub status: ImageEditingTaskStatus,
    pub progress: f32, // 0.0 - 1.0
    pub error_message: Option<String>,
    pub request_params: ImageEditingRequest,
    pub response_data: Option<ImageEditingResponse>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
    pub completed_at: Option<DateTime<Utc>>,
}

impl ImageEditingTask {
    pub fn new(
        id: String,
        input_image_path: String,
        prompt: String,
        request_params: ImageEditingRequest,
    ) -> Self {
        let now = Utc::now();
        Self {
            id,
            input_image_path,
            output_image_path: None,
            prompt,
            status: ImageEditingTaskStatus::Pending,
            progress: 0.0,
            error_message: None,
            request_params,
            response_data: None,
            created_at: now,
            updated_at: now,
            completed_at: None,
        }
    }

    pub fn set_processing(&mut self) {
        self.status = ImageEditingTaskStatus::Processing;
        self.progress = 0.1;
        self.updated_at = Utc::now();
    }

    pub fn set_completed(&mut self, output_path: String, response: ImageEditingResponse) {
        self.status = ImageEditingTaskStatus::Completed;
        self.progress = 1.0;
        self.output_image_path = Some(output_path);
        self.response_data = Some(response);
        let now = Utc::now();
        self.updated_at = now;
        self.completed_at = Some(now);
    }

    pub fn set_failed(&mut self, error_message: String) {
        self.status = ImageEditingTaskStatus::Failed;
        self.error_message = Some(error_message);
        self.updated_at = Utc::now();
    }

    pub fn update_progress(&mut self, progress: f32) {
        self.progress = progress.clamp(0.0, 1.0);
        self.updated_at = Utc::now();
    }
}

/// 批量图像编辑任务
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BatchImageEditingTask {
    pub id: String,
    pub input_folder_path: String,
    pub output_folder_path: String,
    pub prompt: String,
    pub total_images: u32,
    pub processed_images: u32,
    pub successful_images: u32,
    pub failed_images: u32,
    pub status: ImageEditingTaskStatus,
    pub progress: f32, // 0.0 - 1.0
    pub individual_tasks: Vec<ImageEditingTask>,
    pub request_params: ImageEditingRequest,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
    pub completed_at: Option<DateTime<Utc>>,
}

impl BatchImageEditingTask {
    pub fn new(
        id: String,
        input_folder_path: String,
        output_folder_path: String,
        prompt: String,
        request_params: ImageEditingRequest,
    ) -> Self {
        let now = Utc::now();
        Self {
            id,
            input_folder_path,
            output_folder_path,
            prompt,
            total_images: 0,
            processed_images: 0,
            successful_images: 0,
            failed_images: 0,
            status: ImageEditingTaskStatus::Pending,
            progress: 0.0,
            individual_tasks: Vec::new(),
            request_params,
            created_at: now,
            updated_at: now,
            completed_at: None,
        }
    }

    pub fn add_task(&mut self, task: ImageEditingTask) {
        self.individual_tasks.push(task);
        self.total_images = self.individual_tasks.len() as u32;
        self.updated_at = Utc::now();
    }

    pub fn update_progress(&mut self) {
        self.processed_images = self.individual_tasks
            .iter()
            .filter(|task| matches!(
                task.status,
                ImageEditingTaskStatus::Completed | ImageEditingTaskStatus::Failed
            ))
            .count() as u32;

        self.successful_images = self.individual_tasks
            .iter()
            .filter(|task| task.status == ImageEditingTaskStatus::Completed)
            .count() as u32;

        self.failed_images = self.individual_tasks
            .iter()
            .filter(|task| task.status == ImageEditingTaskStatus::Failed)
            .count() as u32;

        if self.total_images > 0 {
            self.progress = self.processed_images as f32 / self.total_images as f32;
        }

        // 更新整体状态
        if self.processed_images == self.total_images {
            self.status = if self.failed_images == 0 {
                ImageEditingTaskStatus::Completed
            } else if self.successful_images == 0 {
                ImageEditingTaskStatus::Failed
            } else {
                ImageEditingTaskStatus::Completed // 部分成功也算完成
            };
            self.completed_at = Some(Utc::now());
        } else if self.processed_images > 0 {
            self.status = ImageEditingTaskStatus::Processing;
        }

        self.updated_at = Utc::now();
    }
}

/// 图像编辑参数配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImageEditingParams {
    pub guidance_scale: f32,
    pub seed: i32,
    pub watermark: bool,
    pub response_format: String,
    pub size: String,
}

impl Default for ImageEditingParams {
    fn default() -> Self {
        Self {
            guidance_scale: 5.5,
            seed: -1,
            watermark: false,
            response_format: "url".to_string(),
            size: "adaptive".to_string(),
        }
    }
}
