use std::collections::HashMap;

use serde::{Deserialize, Serialize};

// ---- Account ----

#[derive(Debug, Clone, Deserialize)]
pub struct Account {
    pub id: String,
    pub name: String,
    pub email: String,
    pub plan: String,
    pub monthly_quota: i64,
    pub emails_sent_this_month: i64,
    pub quota_reset_at: String,
    pub created_at: String,
}

// ---- Email Types ----

#[derive(Debug, Clone, Serialize)]
pub struct SendEmailParams {
    pub from: String,
    pub to: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub subject: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cc: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub bcc: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reply_to: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub html_body: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub text_body: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub template_alias: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub template_data: Option<serde_json::Value>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub headers: Option<serde_json::Value>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tags: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<HashMap<String, String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub attachments: Option<Vec<Attachment>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub idempotency_key: Option<String>,
}

#[derive(Debug, Clone, Serialize)]
pub struct Attachment {
    pub filename: String,
    pub content: String,
    pub content_type: String,
}

#[derive(Debug, Clone, Deserialize)]
pub struct SendEmailResponse {
    pub id: String,
    pub message_id: String,
    pub status: String,
    pub to: String,
    pub created_at: String,
}

#[derive(Debug, Clone, Serialize)]
pub struct SendBatchParams {
    pub emails: Vec<SendEmailParams>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct SendBatchResponse {
    pub data: Vec<SendEmailResponse>,
    #[serde(default)]
    pub errors: Vec<BatchError>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct BatchError {
    pub index: i32,
    pub error: String,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum EmailStatus {
    Queued,
    Processing,
    Sent,
    Delivered,
    Bounced,
    Failed,
    Rejected,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Email {
    pub id: String,
    pub account_id: String,
    pub domain_id: Option<String>,
    pub message_id: String,
    pub from_address: String,
    pub to_address: String,
    pub cc: Option<Vec<String>>,
    pub bcc: Option<Vec<String>>,
    pub reply_to: Option<String>,
    pub subject: String,
    pub html_body: Option<String>,
    pub text_body: Option<String>,
    pub template_id: Option<String>,
    pub status: EmailStatus,
    pub attempts: i32,
    pub max_attempts: i32,
    pub error_message: Option<String>,
    pub smtp_response: Option<String>,
    pub tags: Vec<String>,
    #[serde(default)]
    pub metadata: HashMap<String, String>,
    pub created_at: String,
    pub updated_at: String,
    pub sent_at: Option<String>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct EmailEvent {
    pub id: String,
    pub email_id: String,
    pub account_id: String,
    pub event_type: String,
    pub bounce_type: Option<String>,
    pub bounce_category: Option<String>,
    pub created_at: String,
}

#[derive(Debug, Clone, Deserialize)]
pub struct EmailDetail {
    pub email: Email,
    pub events: Vec<EmailEvent>,
}

// ---- Template Types ----

#[derive(Debug, Clone, Deserialize)]
pub struct Template {
    pub id: String,
    pub account_id: String,
    pub alias: String,
    pub name: String,
    pub subject: String,
    pub html_body: Option<String>,
    pub text_body: Option<String>,
    pub created_at: String,
    pub updated_at: String,
}

#[derive(Debug, Clone, Serialize)]
pub struct CreateTemplateParams {
    pub alias: String,
    pub name: String,
    pub subject: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub html_body: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub text_body: Option<String>,
}

#[derive(Debug, Clone, Serialize)]
pub struct UpdateTemplateParams {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub subject: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub html_body: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub text_body: Option<String>,
}

// ---- Domain Types ----

#[derive(Debug, Clone, Deserialize)]
pub struct Domain {
    pub id: String,
    pub account_id: String,
    pub domain: String,
    pub dkim_selector: String,
    pub spf_verified: bool,
    pub dkim_verified: bool,
    pub dmarc_verified: bool,
    pub return_path_verified: bool,
    pub dns_records: Vec<DnsRecord>,
    pub verified_at: Option<String>,
    pub created_at: String,
    pub updated_at: String,
}

#[derive(Debug, Clone, Deserialize)]
pub struct DnsRecord {
    #[serde(rename = "type")]
    pub type_: String,
    pub name: String,
    pub value: String,
    pub ttl: Option<u32>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct DomainVerification {
    pub domain_id: String,
    pub spf_verified: bool,
    pub dkim_verified: bool,
    pub dmarc_verified: bool,
    pub return_path_verified: bool,
    pub fully_verified: bool,
    pub dns_records: Vec<DnsRecord>,
}

// ---- Webhook Types ----

#[derive(Debug, Clone, Deserialize)]
pub struct Webhook {
    pub id: String,
    pub account_id: String,
    pub url: String,
    pub events: Vec<String>,
    pub is_active: bool,
    pub failure_count: Option<i32>,
    pub last_success_at: Option<String>,
    pub last_failure_at: Option<String>,
    pub last_failure_reason: Option<String>,
    pub created_at: String,
    pub updated_at: String,
}

#[derive(Debug, Clone, Serialize)]
pub struct CreateWebhookParams {
    pub url: String,
    pub events: Vec<String>,
}

#[derive(Debug, Clone, Serialize)]
pub struct UpdateWebhookParams {
    pub url: String,
    pub events: Vec<String>,
    pub is_active: bool,
}

#[derive(Debug, Clone, Deserialize)]
pub struct WebhookTestResponse {
    pub message: String,
    pub payload: serde_json::Value,
}

// ---- Suppression Types ----

#[derive(Debug, Clone, Deserialize)]
pub struct Suppression {
    pub id: String,
    pub account_id: String,
    pub email_address: String,
    pub reason: String,
    pub source_email_id: Option<String>,
    pub created_at: String,
}

// ---- Contact List Types ----

#[derive(Debug, Clone, Deserialize)]
pub struct ContactList {
    pub id: String,
    pub account_id: String,
    pub name: String,
    pub description: Option<String>,
    pub double_opt_in: bool,
    pub contact_count: i64,
    pub created_at: String,
    pub updated_at: String,
}

#[derive(Debug, Clone, Serialize)]
pub struct CreateContactListParams {
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub double_opt_in: Option<bool>,
}

#[derive(Debug, Clone, Serialize)]
pub struct UpdateContactListParams {
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    pub double_opt_in: bool,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Contact {
    pub id: String,
    pub list_id: String,
    pub email: String,
    pub metadata: Option<serde_json::Value>,
    pub status: String,
    pub created_at: String,
}

#[derive(Debug, Clone, Serialize)]
pub struct AddContactParams {
    pub email: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Clone, Serialize)]
pub struct BulkAddContactsParams {
    pub contacts: Vec<AddContactParams>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct BulkAddContactsResponse {
    pub inserted: i64,
    pub total_requested: i64,
}

#[derive(Debug, Clone)]
pub struct ListContactsParams {
    pub page: Option<i64>,
    pub per_page: Option<i64>,
    pub status: Option<String>,
}

// ---- Analytics Types ----

#[derive(Debug, Clone)]
pub struct AnalyticsQuery {
    pub period: Option<String>,
    pub from: Option<String>,
    pub to: Option<String>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct AnalyticsPeriod {
    pub from: String,
    pub to: String,
    #[serde(default)]
    pub period: Option<String>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct AnalyticsOverviewResponse {
    pub data: serde_json::Value,
    pub period: AnalyticsPeriod,
}

#[derive(Debug, Clone)]
pub struct TimeseriesQuery {
    pub period: Option<String>,
    pub from: Option<String>,
    pub to: Option<String>,
    pub metrics: Option<String>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct TimeseriesPoint {
    pub date: String,
    pub sent: Option<i64>,
    pub delivered: Option<i64>,
    pub bounced: Option<i64>,
    pub opens: Option<i64>,
    pub clicks: Option<i64>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct TimeseriesResponse {
    pub data: Vec<TimeseriesPoint>,
    pub period: AnalyticsPeriod,
}

#[derive(Debug, Clone)]
pub struct DomainAnalyticsQuery {
    pub period: Option<String>,
    pub from: Option<String>,
    pub to: Option<String>,
    pub limit: Option<i64>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct DomainAnalytics {
    pub domain: String,
    pub sent: i64,
    pub delivered: i64,
    pub bounced: i64,
    pub open_rate: f64,
    pub click_rate: f64,
}

#[derive(Debug, Clone, Deserialize)]
pub struct DomainAnalyticsResponse {
    pub data: Vec<DomainAnalytics>,
    pub period: AnalyticsPeriod,
}

// ---- Audit Log Types ----

#[derive(Debug, Clone, Deserialize)]
pub struct AuditLog {
    pub id: String,
    pub account_id: String,
    pub action: String,
    pub resource_type: String,
    pub resource_id: Option<String>,
    pub ip_address: Option<String>,
    pub user_agent: Option<String>,
    pub details: Option<serde_json::Value>,
    pub created_at: String,
}

// ---- Dead Letter Types ----

#[derive(Debug, Clone, Deserialize)]
pub struct DeadLetter {
    pub id: String,
    pub email_id: String,
    pub account_id: String,
    pub from_address: String,
    pub to_address: String,
    pub subject: String,
    pub error_message: String,
    pub original_status: String,
    pub attempts: i32,
    pub created_at: String,
}

// ---- Inbound Email Types ----

#[derive(Debug, Clone, Deserialize)]
pub struct InboundEmail {
    pub id: String,
    pub account_id: String,
    pub domain_id: String,
    pub from_address: String,
    pub to_addresses: Vec<String>,
    pub subject: String,
    pub text_body: Option<String>,
    pub html_body: Option<String>,
    pub raw_size: i64,
    pub created_at: String,
}

// ---- Inbound Route Types ----

#[derive(Debug, Clone, Deserialize)]
pub struct InboundRoute {
    pub id: String,
    pub account_id: String,
    pub domain_id: String,
    pub pattern: String,
    pub match_type: String,
    pub priority: i32,
    pub webhook_url: Option<String>,
    pub is_active: bool,
    pub created_at: String,
    pub updated_at: String,
}

#[derive(Debug, Clone, Serialize)]
pub struct CreateInboundRouteParams {
    pub domain_id: String,
    pub pattern: String,
    pub match_type: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub priority: Option<i32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub webhook_url: Option<String>,
}

#[derive(Debug, Clone, Serialize)]
pub struct UpdateInboundRouteParams {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub pattern: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub match_type: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub priority: Option<i32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub webhook_url: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub is_active: Option<bool>,
}

// ---- Pagination ----

#[derive(Debug, Clone)]
pub struct ListParams {
    pub page: Option<i64>,
    pub per_page: Option<i64>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct PaginatedResponse<T> {
    pub data: Vec<T>,
    pub pagination: Pagination,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Pagination {
    pub page: i64,
    pub per_page: i64,
    pub total: i64,
    pub total_pages: i64,
}
