//! Core types for ComfyUI SDK

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

pub mod api;
pub mod events;

// Re-export all types
pub use api::*;
pub use events::*;

/// Base ComfyUI node definition
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComfyUINode {
    pub class_type: String,
    pub inputs: HashMap<String, serde_json::Value>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub _meta: Option<NodeMeta>,
}

/// Node metadata
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeMeta {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub title: Option<String>,
}

/// ComfyUI workflow definition
pub type ComfyUIWorkflow = HashMap<String, ComfyUINode>;

/// Parameter schema types
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum ParameterType {
    String,
    Number,
    Boolean,
    Array,
    Object,
    Integer,
    Float,
    Image,
    Audio,
    Video,
}

/// Node mapping configuration for parameter-to-workflow binding
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeMapping {
    pub node_id: String,
    pub input_field: String,
}

/// Parameter schema definition
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParameterSchema {
    pub param_type: ParameterType,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub required: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub default: Option<serde_json::Value>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub r#enum: Option<Vec<serde_json::Value>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub min: Option<f64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub max: Option<f64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    pub step: Option<f64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub pattern: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub items: Option<Box<ParameterSchema>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub properties: Option<HashMap<String, ParameterSchema>>,
    // Media file related properties
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    pub accept: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "maxSize")]
    #[serde(default)]
    pub max_size: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    pub width: Option<u32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    pub height: Option<u32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    pub duration: Option<f64>,
    // Workflow node mapping
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    pub node_mapping: Option<NodeMapping>,
}

/// Template metadata
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TemplateMetadata {
    pub id: String,
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub version: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub author: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tags: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub category: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub created_at: Option<DateTime<Utc>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub updated_at: Option<DateTime<Utc>>,
}

/// Workflow template data
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorkflowTemplateData {
    pub metadata: TemplateMetadata,
    pub workflow: ComfyUIWorkflow,
    pub parameters: HashMap<String, ParameterSchema>,
}

/// Client configuration
#[derive(Debug, Clone)]
pub struct ComfyUIClientConfig {
    pub base_url: String,
    pub timeout: Option<std::time::Duration>,
    pub retry_attempts: Option<u32>,
    pub retry_delay: Option<std::time::Duration>,
    pub headers: Option<HashMap<String, String>>,
}

impl Default for ComfyUIClientConfig {
    fn default() -> Self {
        Self {
            base_url: "http://localhost:8188".to_string(),
            timeout: Some(std::time::Duration::from_secs(30)),
            retry_attempts: Some(3),
            retry_delay: Some(std::time::Duration::from_millis(1000)),
            headers: None,
        }
    }
}

/// Parameter values type
pub type ParameterValues = HashMap<String, serde_json::Value>;

/// Variable syntax options
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum VariableSyntax {
    DoubleBrace, // {{}}
    DollarBrace, // ${}
    AtBrace,     // @{}
}

/// Template validation result
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ValidationResult {
    pub valid: bool,
    pub errors: Vec<ValidationError>,
}

/// Validation error
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ValidationError {
    pub path: String,
    pub message: String,
    pub value: Option<serde_json::Value>,
}

impl ValidationResult {
    /// Create a successful validation result
    pub fn success() -> Self {
        Self {
            valid: true,
            errors: Vec::new(),
        }
    }

    /// Create a failed validation result with errors
    pub fn failure(errors: Vec<ValidationError>) -> Self {
        Self {
            valid: false,
            errors,
        }
    }

    /// Add an error to the validation result
    pub fn add_error(&mut self, error: ValidationError) {
        self.valid = false;
        self.errors.push(error);
    }
}

impl ValidationError {
    /// Create a new validation error
    pub fn new(path: impl Into<String>, message: impl Into<String>) -> Self {
        Self {
            path: path.into(),
            message: message.into(),
            value: None,
        }
    }

    /// Create a new validation error with value
    pub fn with_value(
        path: impl Into<String>,
        message: impl Into<String>,
        value: serde_json::Value,
    ) -> Self {
        Self {
            path: path.into(),
            message: message.into(),
            value: Some(value),
        }
    }
}

impl ParameterSchema {
    /// Creates a new ParameterSchema with the given type and default values for other fields
    pub fn new(param_type: ParameterType) -> Self {
        Self {
            param_type,
            required: None,
            default: None,
            description: None,
            r#enum: None,
            min: None,
            max: None,
            step: None,
            pattern: None,
            items: None,
            properties: None,
            accept: None,
            max_size: None,
            width: None,
            height: None,
            duration: None,
            node_mapping: None,
        }
    }
}
