use anyhow::{Context, Result};

#[derive(Clone, Debug)]
pub struct Settings {
    pub port: u16,
    pub database_url: String,
    pub oidc_client_id: String,
    pub oidc_client_secret: String,
    pub oidc_authorize_url: String,
    pub oidc_token_url: String,
    pub oidc_userinfo_url: String,
    pub oidc_redirect_url: String,
    pub oidc_scopes: String,
    pub session_secret: String,
    pub cookie_secure: bool,
    pub stun_urls: Vec<String>,
    pub turn_urls: Vec<String>,
    pub turn_username: Option<String>,
    pub turn_password: Option<String>,
}

impl Settings {
    pub fn from_env() -> Result<Self> {
        Ok(Self {
            port: std::env::var("PORT")
                .unwrap_or_else(|_| "3000".into())
                .parse()
                .context("PORT must be a valid u16")?,
            database_url: required("DATABASE_URL")?,
            oidc_client_id: required("OIDC_CLIENT_ID")?,
            oidc_client_secret: required("OIDC_CLIENT_SECRET")?,
            oidc_authorize_url: required("OIDC_AUTHORIZE_URL")?,
            oidc_token_url: required("OIDC_TOKEN_URL")?,
            oidc_userinfo_url: required("OIDC_USERINFO_URL")?,
            oidc_redirect_url: required("OIDC_REDIRECT_URL")?,
            oidc_scopes: std::env::var("OIDC_SCOPES").unwrap_or_else(|_| "openid profile email".to_string()),
            session_secret: required("SESSION_SECRET")?,
            cookie_secure: std::env::var("COOKIE_SECURE")
                .unwrap_or_else(|_| "false".into())
                .parse()
                .context("COOKIE_SECURE must be true/false")?,
            stun_urls: parse_csv_env("STUN_URLS", "stun:stun.l.google.com:19302"),
            turn_urls: parse_csv_env("TURN_URLS", ""),
            turn_username: optional("TURN_USERNAME"),
            turn_password: optional("TURN_PASSWORD"),
        })
    }
}

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

fn optional(name: &str) -> Option<String> {
    std::env::var(name)
        .ok()
        .map(|v| v.trim().to_string())
        .filter(|v| !v.is_empty())
}

fn parse_csv_env(name: &str, default_value: &str) -> Vec<String> {
    let raw = std::env::var(name).unwrap_or_else(|_| default_value.to_string());
    raw.split(',')
        .map(str::trim)
        .filter(|s| !s.is_empty())
        .map(ToString::to_string)
        .collect()
}
