//! Email types and structures
//!
//! This module defines the core types used throughout the email system.

#![allow(dead_code)]

use std::collections::HashMap;

use serde::{Deserialize, Serialize};
// use thiserror::Error;

/// Email provider configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmailConfig {
    /// Default sender email address
    pub default_from: String,
    /// Default sender name
    pub default_from_name: String,
    /// Email provider type
    pub provider: EmailProvider,
    /// SMTP configuration (if using SMTP)
    pub smtp: Option<SmtpConfig>,
    /// SendGrid configuration (if using SendGrid)
    pub sendgrid: Option<SendGridConfig>,
    /// Template directory path
    pub template_dir: String,
    /// Enable email sending (set to false for testing)
    pub enabled: bool,
}

/// Supported email providers
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum EmailProvider {
    Smtp,
    SendGrid,
    Console, // For development/testing
}

/// SMTP server configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SmtpConfig {
    /// SMTP server hostname
    pub host: String,
    /// SMTP server port
    pub port: u16,
    /// Username for authentication
    pub username: String,
    /// Password for authentication
    pub password: String,
    /// Use TLS encryption
    pub use_tls: bool,
    /// Use STARTTLS
    pub use_starttls: bool,
}

/// SendGrid API configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SendGridConfig {
    /// SendGrid API key
    pub api_key: String,
    /// SendGrid API endpoint (usually https://api.sendgrid.com/v3/mail/send)
    pub endpoint: String,
}

/// Email message structure
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmailMessage {
    /// Recipient email address
    pub to: String,
    /// Recipient name (optional)
    pub to_name: Option<String>,
    /// Sender email address (optional, uses default if not provided)
    pub from: Option<String>,
    /// Sender name (optional, uses default if not provided)
    pub from_name: Option<String>,
    /// Email subject
    pub subject: String,
    /// Plain text body
    pub text_body: Option<String>,
    /// HTML body
    pub html_body: Option<String>,
    /// CC recipients
    pub cc: Option<Vec<String>>,
    /// BCC recipients
    pub bcc: Option<Vec<String>>,
    /// Reply-to address
    pub reply_to: Option<String>,
    /// Email headers
    pub headers: Option<HashMap<String, String>>,
    /// Email template name (if using templates)
    pub template: Option<String>,
    /// Template variables
    pub template_data: Option<HashMap<String, serde_json::Value>>,
    /// Language code for template rendering (e.g., "en", "es", "fr")
    pub language: Option<String>,
}

impl EmailMessage {
    /// Create a new email message
    pub fn new(to: &str, subject: &str) -> Self {
        Self {
            to: to.to_string(),
            to_name: None,
            from: None,
            from_name: None,
            subject: subject.to_string(),
            text_body: None,
            html_body: None,
            cc: None,
            bcc: None,
            reply_to: None,
            headers: None,
            template: None,
            template_data: None,
            language: None,
        }
    }

    /// Set recipient name
    pub fn to_name(mut self, name: &str) -> Self {
        self.to_name = Some(name.to_string());
        self
    }

    /// Set sender email
    pub fn from(mut self, email: &str) -> Self {
        self.from = Some(email.to_string());
        self
    }

    /// Set sender name
    pub fn from_name(mut self, name: &str) -> Self {
        self.from_name = Some(name.to_string());
        self
    }

    /// Set plain text body
    pub fn text_body(mut self, body: &str) -> Self {
        self.text_body = Some(body.to_string());
        self
    }

    /// Set HTML body
    pub fn html_body(mut self, body: &str) -> Self {
        self.html_body = Some(body.to_string());
        self
    }

    /// Add CC recipient
    pub fn cc(mut self, email: &str) -> Self {
        self.cc.get_or_insert_with(Vec::new).push(email.to_string());
        self
    }

    /// Add BCC recipient
    pub fn bcc(mut self, email: &str) -> Self {
        self.bcc
            .get_or_insert_with(Vec::new)
            .push(email.to_string());
        self
    }

    /// Set reply-to address
    pub fn reply_to(mut self, email: &str) -> Self {
        self.reply_to = Some(email.to_string());
        self
    }

    /// Set email template
    pub fn template(mut self, template_name: &str) -> Self {
        self.template = Some(template_name.to_string());
        self
    }

    /// Add template data
    pub fn template_data(mut self, key: &str, value: serde_json::Value) -> Self {
        self.template_data
            .get_or_insert_with(HashMap::new)
            .insert(key.to_string(), value);
        self
    }

    /// Add multiple template data entries
    pub fn template_data_map(mut self, data: HashMap<String, serde_json::Value>) -> Self {
        self.template_data = Some(data);
        self
    }

    /// Add custom header
    pub fn header(mut self, key: &str, value: &str) -> Self {
        self.headers
            .get_or_insert_with(HashMap::new)
            .insert(key.to_string(), value.to_string());
        self
    }

    /// Set language for template rendering
    pub fn language(mut self, lang: &str) -> Self {
        self.language = Some(lang.to_string());
        self
    }
}

/// Email template definition
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmailTemplate {
    /// Template name/identifier
    pub name: String,
    /// Template subject (can contain variables)
    pub subject: String,
    /// Plain text template content
    pub text_content: Option<String>,
    /// HTML template content
    pub html_content: Option<String>,
    /// Template variables description
    pub variables: Option<Vec<TemplateVariable>>,
}

/// Template variable definition
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TemplateVariable {
    /// Variable name
    pub name: String,
    /// Variable description
    pub description: String,
    /// Whether the variable is required
    pub required: bool,
    /// Default value (if any)
    pub default: Option<String>,
}

/// Form submission data structure
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FormSubmission {
    /// Form type (contact, support, etc.)
    pub form_type: String,
    /// Submitter's name
    pub name: String,
    /// Submitter's email
    pub email: String,
    /// Subject of the message
    pub subject: String,
    /// Message content
    pub message: String,
    /// Additional form fields
    pub fields: Option<HashMap<String, String>>,
    /// Timestamp of submission
    pub submitted_at: chrono::DateTime<chrono::Utc>,
    /// IP address of submitter
    pub ip_address: Option<String>,
    /// User agent
    pub user_agent: Option<String>,
}

impl FormSubmission {
    /// Create a new form submission
    pub fn new(form_type: &str, name: &str, email: &str, subject: &str, message: &str) -> Self {
        Self {
            form_type: form_type.to_string(),
            name: name.to_string(),
            email: email.to_string(),
            subject: subject.to_string(),
            message: message.to_string(),
            fields: None,
            submitted_at: chrono::Utc::now(),
            ip_address: None,
            user_agent: None,
        }
    }

    /// Add a custom field
    pub fn field(mut self, key: &str, value: &str) -> Self {
        self.fields
            .get_or_insert_with(HashMap::new)
            .insert(key.to_string(), value.to_string());
        self
    }

    /// Set IP address
    pub fn ip_address(mut self, ip: &str) -> Self {
        self.ip_address = Some(ip.to_string());
        self
    }

    /// Set user agent
    pub fn user_agent(mut self, ua: &str) -> Self {
        self.user_agent = Some(ua.to_string());
        self
    }

    /// Convert to email message
    pub fn to_email_message(&self, recipient: &str) -> EmailMessage {
        let mut template_data = HashMap::new();
        template_data.insert(
            "name".to_string(),
            serde_json::Value::String(self.name.clone()),
        );
        template_data.insert(
            "email".to_string(),
            serde_json::Value::String(self.email.clone()),
        );
        template_data.insert(
            "subject".to_string(),
            serde_json::Value::String(self.subject.clone()),
        );
        template_data.insert(
            "message".to_string(),
            serde_json::Value::String(self.message.clone()),
        );
        template_data.insert(
            "form_type".to_string(),
            serde_json::Value::String(self.form_type.clone()),
        );
        template_data.insert(
            "submitted_at".to_string(),
            serde_json::Value::String(self.submitted_at.to_rfc3339()),
        );

        if let Some(fields) = &self.fields {
            for (key, value) in fields {
                template_data.insert(key.clone(), serde_json::Value::String(value.clone()));
            }
        }

        EmailMessage::new(recipient, &format!("Form Submission: {}", self.subject))
            .from(&self.email)
            .from_name(&self.name)
            .reply_to(&self.email)
            .template("form_submission")
            .template_data_map(template_data)
            .language("en") // Default language, can be overridden
    }
}

/// Email sending status
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EmailStatus {
    /// Email was sent successfully
    Sent,
    /// Email failed to send
    Failed(String),
    /// Email is queued for sending
    Queued,
    /// Email sending is disabled
    Disabled,
}

/// Email sending result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmailSendResult {
    /// Message ID (if available)
    pub message_id: Option<String>,
    /// Status of the email
    pub status: EmailStatus,
    /// Additional information
    pub info: Option<String>,
}

impl EmailSendResult {
    /// Create a success result
    #[allow(dead_code)]
    pub fn success(message_id: Option<String>) -> Self {
        Self {
            message_id,
            status: EmailStatus::Sent,
            info: None,
        }
    }

    /// Create a failure result
    #[allow(dead_code)]
    pub fn failure(error: &str) -> Self {
        Self {
            message_id: None,
            status: EmailStatus::Failed(error.to_string()),
            info: None,
        }
    }

    /// Create a queued result
    #[allow(dead_code)]
    pub fn queued() -> Self {
        Self {
            message_id: None,
            status: EmailStatus::Queued,
            info: None,
        }
    }

    /// Create a disabled result
    #[allow(dead_code)]
    pub fn disabled() -> Self {
        Self {
            message_id: None,
            status: EmailStatus::Disabled,
            info: Some("Email sending is disabled".to_string()),
        }
    }
}
