//! Hosting types

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

/// Network environment
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum Network {
    #[default]
    Mainnet,
    Testnet,
    Devnet,
}

/// Hosting configuration
#[derive(Debug, Clone)]
pub struct HostingConfig {
    pub api_key: String,
    pub endpoint: String,
    pub network: Network,
    pub timeout_secs: u64,
    pub retries: u32,
    pub debug: bool,
}

impl Default for HostingConfig {
    fn default() -> Self {
        Self {
            api_key: String::new(),
            endpoint: "https://hosting.synor.io/v1".to_string(),
            network: Network::Mainnet,
            timeout_secs: 60,
            retries: 3,
            debug: false,
        }
    }
}

// ==================== Domain Types ====================

/// Domain status
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum DomainStatus {
    Pending,
    Active,
    Expired,
    Suspended,
}

/// Domain information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Domain {
    pub name: String,
    pub status: DomainStatus,
    pub owner: String,
    pub registered_at: i64,
    pub expires_at: i64,
    pub auto_renew: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub records: Option<DomainRecord>,
}

/// Domain record for resolution
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct DomainRecord {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cid: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ipv4: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ipv6: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cname: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub txt: Option<Vec<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<HashMap<String, String>>,
}

/// Domain availability
#[derive(Debug, Clone, Deserialize)]
pub struct DomainAvailability {
    pub name: String,
    pub available: bool,
    pub price: Option<f64>,
    #[serde(default)]
    pub premium: bool,
}

/// Options for registering a domain
#[derive(Debug, Clone, Default, Serialize)]
pub struct RegisterDomainOptions {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub years: Option<i32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub auto_renew: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub records: Option<DomainRecord>,
}

// ==================== DNS Types ====================

/// DNS record type
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum DnsRecordType {
    A,
    AAAA,
    CNAME,
    TXT,
    MX,
    NS,
    SRV,
    CAA,
}

/// DNS record
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DnsRecord {
    #[serde(rename = "type")]
    pub record_type: DnsRecordType,
    pub name: String,
    pub value: String,
    #[serde(default = "default_ttl")]
    pub ttl: i32,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub priority: Option<i32>,
}

fn default_ttl() -> i32 {
    3600
}

/// DNS zone
#[derive(Debug, Clone, Deserialize)]
pub struct DnsZone {
    pub domain: String,
    pub records: Vec<DnsRecord>,
    pub updated_at: i64,
}

// ==================== Deployment Types ====================

/// Deployment status
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum DeploymentStatus {
    Pending,
    Building,
    Deploying,
    Active,
    Failed,
    Inactive,
}

/// Deployment information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Deployment {
    pub id: String,
    pub domain: String,
    pub cid: String,
    pub status: DeploymentStatus,
    pub url: String,
    pub created_at: i64,
    pub updated_at: i64,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub build_logs: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub error_message: Option<String>,
}

/// Redirect rule
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RedirectRule {
    pub source: String,
    pub destination: String,
    #[serde(default = "default_status_code")]
    pub status_code: i32,
    #[serde(default = "default_permanent")]
    pub permanent: bool,
}

fn default_status_code() -> i32 {
    301
}

fn default_permanent() -> bool {
    true
}

/// Options for deploying
#[derive(Debug, Clone, Default, Serialize)]
pub struct DeployOptions {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub domain: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub subdomain: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub headers: Option<HashMap<String, String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub redirects: Option<Vec<RedirectRule>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub spa: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub clean_urls: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub trailing_slash: Option<bool>,
}

/// Deployment statistics
#[derive(Debug, Clone, Deserialize)]
pub struct DeploymentStats {
    pub requests: u64,
    pub bandwidth: u64,
    pub unique_visitors: u64,
    pub period: String,
}

// ==================== SSL Types ====================

/// Certificate status
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum CertificateStatus {
    Pending,
    Issued,
    Expired,
    Revoked,
}

/// SSL certificate
#[derive(Debug, Clone, Deserialize)]
pub struct Certificate {
    pub domain: String,
    pub status: CertificateStatus,
    pub auto_renew: bool,
    pub issuer: String,
    pub issued_at: Option<i64>,
    pub expires_at: Option<i64>,
    pub fingerprint: Option<String>,
}

/// Options for provisioning SSL
#[derive(Debug, Clone, Default, Serialize)]
pub struct ProvisionSslOptions {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub include_www: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub auto_renew: Option<bool>,
}

// ==================== Site Configuration ====================

/// Site configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SiteConfig {
    pub domain: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cid: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub headers: Option<HashMap<String, String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub redirects: Option<Vec<RedirectRule>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub error_pages: Option<HashMap<String, String>>,
    #[serde(default)]
    pub spa: bool,
    #[serde(default = "default_true")]
    pub clean_urls: bool,
    #[serde(default)]
    pub trailing_slash: bool,
}

fn default_true() -> bool {
    true
}

// ==================== Analytics ====================

/// Page view data
#[derive(Debug, Clone, Deserialize)]
pub struct PageView {
    pub path: String,
    pub views: u64,
}

/// Referrer data
#[derive(Debug, Clone, Deserialize)]
pub struct Referrer {
    pub referrer: String,
    pub count: u64,
}

/// Country data
#[derive(Debug, Clone, Deserialize)]
pub struct Country {
    pub country: String,
    pub count: u64,
}

/// Analytics data
#[derive(Debug, Clone, Deserialize)]
pub struct AnalyticsData {
    pub domain: String,
    pub period: String,
    pub page_views: u64,
    pub unique_visitors: u64,
    pub bandwidth: u64,
    pub top_pages: Vec<PageView>,
    pub top_referrers: Vec<Referrer>,
    pub top_countries: Vec<Country>,
}

/// Analytics options
#[derive(Debug, Clone, Default, Serialize)]
pub struct AnalyticsOptions {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub period: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub start: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub end: Option<String>,
}
