use serde::{Deserialize, Serialize};
use serde_json::Value;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AssetType {
    Image,
    Video,
    Audio,
    Music,
    Tts,
    Model3d,
    Character,
    Prop,
    Sprite,
    World,
    Text,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ImageEditMode {
    Edit,
    Inpaint,
    Restyle,
    Expand,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GenerateRequest {
    pub asset_type: AssetType,
    pub prompt: Option<String>,
    pub model: Option<String>,
    pub input_file: Option<String>,
    pub provider: Option<String>,
    pub size: Option<String>,
    pub transparent: Option<bool>,
    #[serde(default)]
    pub reference_images: Vec<String>,
    pub edit_mode: Option<ImageEditMode>,
    pub session_id: Option<String>,
    #[serde(default)]
    pub params: Value,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GenerateResponse {
    pub provider_id: String,
    pub output_path: Option<String>,
    pub output_url: Option<String>,
    pub output_data: Option<String>,
    pub url: Option<String>,
    #[serde(default)]
    pub metadata: Value,
    pub cost_usd: Option<f64>,
    pub elapsed_ms: Option<u64>,
    pub job_id: Option<String>,
    pub user_id: Option<String>,
    pub session_id: Option<String>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ImageOptions {
    pub model: Option<String>,
    pub provider: Option<String>,
    pub size: Option<String>,
    pub transparent: Option<bool>,
    pub input: Option<String>,
    #[serde(default)]
    pub reference_images: Vec<String>,
    pub edit_mode: Option<ImageEditMode>,
    pub session_id: Option<String>,
    #[serde(default)]
    pub params: Value,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct VideoOptions {
    pub model: Option<String>,
    pub provider: Option<String>,
    pub input: Option<String>,
    pub size: Option<String>,
    pub ratio: Option<String>,
    #[serde(default)]
    pub reference_images: Vec<String>,
    #[serde(default)]
    pub params: Value,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AudioOptions {
    pub model: Option<String>,
    pub provider: Option<String>,
    pub audio_type: Option<String>,
    pub duration: Option<u32>,
    #[serde(default)]
    pub params: Value,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct TtsOptions {
    pub model: Option<String>,
    pub provider: Option<String>,
    pub voice: Option<String>,
    pub voice_id: Option<String>,
    pub language: Option<String>,
    pub instructions: Option<String>,
    #[serde(default)]
    pub params: Value,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct MusicOptions {
    pub model: Option<String>,
    pub provider: Option<String>,
    pub duration: Option<u32>,
    pub force_instrumental: Option<bool>,
    pub output_format: Option<String>,
    #[serde(default)]
    pub params: Value,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Model3dOptions {
    pub model: Option<String>,
    pub provider: Option<String>,
    pub input: Option<String>,
    #[serde(default)]
    pub images: Vec<String>,
    pub ai_model: Option<String>,
    pub polycount: Option<u32>,
    pub pbr: Option<bool>,
    pub hd_texture: Option<bool>,
    pub auto_size: Option<bool>,
    pub pose_mode: Option<String>,
    pub texture_prompt: Option<String>,
    pub format: Option<String>,
    #[serde(default)]
    pub params: Value,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CharacterOptions {
    pub model: Option<String>,
    pub provider: Option<String>,
    pub input: Option<String>,
    #[serde(default)]
    pub images: Vec<String>,
    pub format: Option<String>,
    pub polycount: Option<u32>,
    pub pbr: Option<bool>,
    pub hd_texture: Option<bool>,
    pub pose_mode: Option<String>,
    pub ai_model: Option<String>,
    pub auto_size: Option<bool>,
    pub texture_prompt: Option<String>,
    #[serde(default)]
    pub params: Value,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PropOptions {
    pub model: Option<String>,
    pub provider: Option<String>,
    pub input: Option<String>,
    #[serde(default)]
    pub images: Vec<String>,
    pub format: Option<String>,
    pub polycount: Option<u32>,
    pub pbr: Option<bool>,
    pub hd_texture: Option<bool>,
    pub ai_model: Option<String>,
    pub auto_size: Option<bool>,
    pub texture_prompt: Option<String>,
    pub symmetry_mode: Option<String>,
    #[serde(default)]
    pub params: Value,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct SpriteOptions {
    pub model: Option<String>,
    pub provider: Option<String>,
    pub input: Option<String>,
    pub animation_type: Option<String>,
    pub direction: Option<String>,
    pub duration: Option<u32>,
    pub style: Option<String>,
    pub output_format: Option<String>,
    pub fps: Option<u32>,
    #[serde(default)]
    pub params: Value,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct WorldOptions {
    pub model: Option<String>,
    pub provider: Option<String>,
    pub input: Option<String>,
    pub display_name: Option<String>,
    #[serde(default)]
    pub params: Value,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct TextOptions {
    pub model: Option<String>,
    pub provider: Option<String>,
    pub max_tokens: Option<u32>,
    #[serde(default)]
    pub params: Value,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct BatchSharedRequest {
    pub transparent: Option<bool>,
    pub size: Option<String>,
    pub model: Option<String>,
    pub provider: Option<String>,
    #[serde(default)]
    pub reference_images: Vec<String>,
    pub input_file: Option<String>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct BatchComposeRequest {
    pub direction: Option<ComposeDirection>,
    pub columns: Option<u32>,
    pub padding: Option<u32>,
    pub frame_width: Option<u32>,
    pub frame_height: Option<u32>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BatchGenerateRequest {
    pub asset_type: AssetType,
    pub prompts: Vec<String>,
    #[serde(default)]
    pub shared: BatchSharedRequest,
    pub compose: Option<BatchComposeRequest>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BatchFrameResult {
    pub index: usize,
    pub provider_id: Option<String>,
    pub output_data: Option<String>,
    pub output_url: Option<String>,
    pub cost_usd: Option<f64>,
    pub elapsed_ms: Option<u64>,
    pub error: Option<String>,
    pub url: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BatchSpritesheetResult {
    pub output_data: String,
    pub width: u32,
    pub height: u32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BatchGenerateResponse {
    pub job_id: String,
    pub user_id: String,
    #[serde(default)]
    pub frames: Vec<BatchFrameResult>,
    pub total_cost_usd: Option<f64>,
    pub elapsed_ms: Option<u64>,
    pub spritesheet: Option<BatchSpritesheetResult>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CropMode {
    Tightest,
    PowerOf2,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ComposeDirection {
    Horizontal,
    Vertical,
    Grid,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "op", rename_all = "snake_case")]
pub enum ProcessOperation {
    SmartCrop {
        mode: Option<CropMode>,
    },
    Resize {
        width: u32,
        height: u32,
    },
    Compose {
        direction: ComposeDirection,
        columns: Option<u32>,
        padding: Option<u32>,
        frame_width: Option<u32>,
        frame_height: Option<u32>,
    },
    ExtractFrames {
        count: Option<u32>,
    },
    RemoveBg {
        bg_color: Option<String>,
    },
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProcessRequest {
    pub input: Option<String>,
    #[serde(default)]
    pub inputs: Vec<String>,
    pub operations: Vec<ProcessOperation>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProcessOutputItem {
    pub output_data: String,
    pub width: u32,
    pub height: u32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProcessResponse {
    pub output_data: String,
    pub width: u32,
    pub height: u32,
    #[serde(default)]
    pub outputs: Vec<ProcessOutputItem>,
    #[serde(default)]
    pub operations_applied: Vec<String>,
    pub elapsed_ms: u64,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Process3dRequest {
    pub task_id: Option<String>,
    pub operation: String,
    #[serde(default)]
    pub params: Value,
    pub frame_count: Option<u32>,
    pub resolution: Option<u32>,
    pub camera_angle: Option<String>,
    pub directions: Option<u32>,
}

pub type Process3dResponse = Value;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum VoiceType {
    Vc,
    Vd,
}

impl VoiceType {
    pub fn as_str(&self) -> &'static str {
        match self {
            Self::Vc => "vc",
            Self::Vd => "vd",
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VoiceCloneRequest {
    pub audio_base64: String,
    pub audio_mime: Option<String>,
    pub name: String,
    pub target_model: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VoiceDesignRequest {
    pub voice_prompt: String,
    pub preview_text: String,
    pub name: String,
    pub target_model: Option<String>,
    pub language: Option<String>,
}

pub type VoiceCloneResponse = Value;
pub type VoiceDesignResponse = Value;
pub type VoiceListResponse = Value;
pub type VoiceDeleteResponse = Value;

pub type LoginResponse = Value;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JobStatusResponse {
    pub id: String,
    pub user_id: Option<String>,
    pub asset_type: String,
    pub provider_id: String,
    pub status: String,
    pub error_message: Option<String>,
    pub output_path: Option<String>,
    pub cost_usd: Option<f64>,
    pub created_at: String,
    pub started_at: Option<String>,
    pub completed_at: Option<String>,
    pub duration_ms: Option<i64>,
    #[serde(default)]
    pub request: Value,
    pub response: Option<Value>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JobCancelResponse {
    pub id: String,
    pub previous_status: String,
    pub status: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProviderHealth {
    pub healthy: bool,
    pub latency_ms: Option<u64>,
    pub message: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProviderHealthEntry {
    pub id: String,
    pub health: ProviderHealth,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProviderHealthListResponse {
    pub providers: Vec<ProviderHealthEntry>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProviderHealthResponse {
    pub id: String,
    pub health: ProviderHealth,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UploadResult {
    pub filename: String,
    pub url: String,
    pub size: u64,
    pub content_type: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AssetFile {
    pub filename: String,
    pub url: String,
    pub size: u64,
    pub content_type: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AssetListResponse {
    #[serde(default)]
    pub files: Vec<AssetFile>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AssetDeleteResponse {
    pub filename: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LibraryItem {
    pub id: String,
    pub asset_type: String,
    pub name: String,
    pub description: String,
    #[serde(default)]
    pub tags: Vec<String>,
    pub file_path: String,
    pub file_url: String,
    pub file_size: i64,
    pub duration_seconds: Option<f64>,
    pub source: String,
    pub source_job_id: Option<String>,
    #[serde(default)]
    pub metadata: Value,
    pub created_at: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LibrarySearchResponse {
    #[serde(default)]
    pub items: Vec<LibraryItem>,
    pub total: i64,
    pub limit: i64,
    pub offset: i64,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct LibraryAddRequest {
    pub asset_type: String,
    pub name: String,
    pub description: Option<String>,
    #[serde(default)]
    pub tags: Vec<String>,
    pub file_url: String,
    pub file_path: Option<String>,
    pub file_size: Option<i64>,
    pub duration_seconds: Option<f64>,
    pub source: Option<String>,
    pub source_job_id: Option<String>,
    #[serde(default)]
    pub metadata: Value,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LibraryAddResponse {
    pub id: String,
    pub asset_type: String,
    pub name: String,
    pub file_url: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LibraryDeleteResponse {
    pub id: String,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct LibraryCatalogJobsRequest {
    pub asset_type: Option<String>,
    pub after: Option<String>,
    pub provider_id: Option<String>,
    #[serde(default)]
    pub dry_run: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LibraryCatalogJobsResponse {
    pub dry_run: Option<bool>,
    pub would_catalog: Option<i64>,
    pub cataloged: Option<u64>,
    pub errors: Option<usize>,
    #[serde(default)]
    pub error_details: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JobSummary {
    pub id: String,
    pub user_id: Option<String>,
    pub asset_type: String,
    pub provider_id: String,
    pub status: String,
    pub error_message: Option<String>,
    pub output_path: Option<String>,
    pub cost_usd: Option<f64>,
    pub created_at: String,
    pub started_at: Option<String>,
    pub completed_at: Option<String>,
    pub duration_ms: Option<i64>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProviderCapabilities {
    pub supports_transparency: bool,
    pub supports_streaming: bool,
    pub max_concurrent: u32,
    pub rate_limit_rpm: Option<u32>,
    pub priority: i32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProviderInfo {
    pub id: String,
    pub display_name: String,
    pub asset_types: Vec<AssetType>,
    pub capabilities: ProviderCapabilities,
}
