use anyhow::{Context, Result};

/// Application configuration loaded from environment variables
#[derive(Clone)]
pub struct AppConfig {
    // Database
    pub database_url: String,
    pub database_max_connections: u32,

    // NATS
    pub nats_url: String,

    // Auth
    pub jwt_secret: String,
    pub jwt_access_expiry_seconds: i64,
    pub jwt_refresh_expiry_seconds: i64,

    // Encryption
    pub encryption_key: String,

    // Cloudflare
    pub cloudflare_api_token: String,
    pub cloudflare_zone_id: String,
    pub base_domain: String,

    // Steam
    pub steam_api_key: String,

    // Email (SMTP)
    pub smtp_host: String,
    pub smtp_port: u16,
    pub smtp_username: String,
    pub smtp_password: String,
    pub smtp_from: String,

    // Server
    pub api_port: u16,
    pub frontend_url: String,
}

impl AppConfig {
    pub fn from_env() -> Result<Self> {
        Ok(Self {
            database_url: env_required("DATABASE_URL")?,
            database_max_connections: env_or_default("DATABASE_MAX_CONNECTIONS", 20),
            nats_url: env_or_default_str("NATS_URL", "nats://localhost:4222"),
            jwt_secret: env_required("JWT_SECRET")?,
            jwt_access_expiry_seconds: env_or_default("JWT_ACCESS_EXPIRY_SECONDS", 900),
            jwt_refresh_expiry_seconds: env_or_default("JWT_REFRESH_EXPIRY_SECONDS", 604800),
            encryption_key: env_required("ENCRYPTION_KEY")?,
            cloudflare_api_token: env_or_default_str("CLOUDFLARE_API_TOKEN", ""),
            cloudflare_zone_id: env_or_default_str("CLOUDFLARE_ZONE_ID", ""),
            base_domain: env_or_default_str("BASE_DOMAIN", "corrosionmgmt.com"),
            steam_api_key: env_or_default_str("STEAM_API_KEY", ""),
            smtp_host: env_or_default_str("SMTP_HOST", "localhost"),
            smtp_port: env_or_default("SMTP_PORT", 587),
            smtp_username: env_or_default_str("SMTP_USERNAME", ""),
            smtp_password: env_or_default_str("SMTP_PASSWORD", ""),
            smtp_from: env_or_default_str("SMTP_FROM", "noreply@corrosionmgmt.com"),
            api_port: env_or_default("API_PORT", 3000),
            frontend_url: env_or_default_str("FRONTEND_URL", "http://localhost:5174"),
        })
    }
}

fn env_required(key: &str) -> Result<String> {
    std::env::var(key).with_context(|| format!("Missing required env var: {key}"))
}

fn env_or_default<T: std::str::FromStr>(key: &str, default: T) -> T {
    std::env::var(key)
        .ok()
        .and_then(|v| v.parse().ok())
        .unwrap_or(default)
}

fn env_or_default_str(key: &str, default: &str) -> String {
    std::env::var(key).unwrap_or_else(|_| default.to_string())
}
