use basic_jwt::JWTPrivateKey;
use clap::Parser;
/// VirtWeb backend API
#[derive(Parser, Debug, Clone)]
#[clap(author, version, about, long_about = None)]
pub struct AppConfig {
    /// Listen address
    #[clap(short, long, env, default_value = "0.0.0.0:8002")]
    pub listen_address: String,
    /// Website main origin
    #[clap(short, long, env, default_value = "http://localhost:5173")]
    pub website_origin: String,
    /// Proxy IP, might end with a star "*"
    #[clap(short, long, env)]
    pub proxy_ip: Option<String>,
    /// Secret key, used to sign some resources. Must be randomly generated
    #[clap(short = 'S', long, env, default_value = "")]
    secret: String,
    /// Specify whether the cookie should be transmitted only over secure connections
    #[clap(long, env)]
    pub cookie_secure: bool,
    /// URL where the OpenID configuration can be found
    #[arg(
        long,
        env,
        default_value = "http://localhost:9001/dex/.well-known/openid-configuration"
    )]
    pub oidc_configuration_url: String,
    /// Disable authentication (for development purposes ONLY)
    #[arg(long, env)]
    pub unsecure_disable_login: bool,
    /// OpenID client ID
    #[arg(long, env, default_value = "foo")]
    pub oidc_client_id: String,
    /// OpenID client secret
    #[arg(long, env, default_value = "bar")]
    pub oidc_client_secret: String,
    /// OpenID login redirect URL
    #[arg(long, env, default_value = "APP_ORIGIN/oidc_cb")]
    oidc_redirect_url: String,
    /// VirtWeb base URL
    #[arg(long, env, default_value = "http://localhost:8000")]
    pub virtweb_base_url: String,
    /// VirtWeb API token ID
    #[arg(long, env)]
    pub virtweb_token_id: String,
    /// VirtWeb API token private key
    #[arg(long, env)]
    virtweb_token_private_key: String,
}
lazy_static::lazy_static! {
    static ref ARGS: AppConfig = {
        AppConfig::parse()
    };
}
impl AppConfig {
    /// Get parsed command line arguments
    pub fn get() -> &'static AppConfig {
        &ARGS
    }
    /// Get auth cookie domain
    pub fn cookie_domain(&self) -> Option<String> {
        if cfg!(debug_assertions) {
            let domain = self.website_origin.split_once("://")?.1;
            Some(
                domain
                    .split_once(':')
                    .map(|s| s.0)
                    .unwrap_or(domain)
                    .to_string(),
            )
        } else {
            // In release mode, the web app is hosted on the same origin as the API
            None
        }
    }
    /// Get app secret
    pub fn secret(&self) -> &str {
        let mut secret = self.secret.as_str();
        if cfg!(debug_assertions) && secret.is_empty() {
            secret = "DEBUGKEYDEBUGKEYDEBUGKEYDEBUGKEYDEBUGKEYDEBUGKEYDEBUGKEYDEBUGKEY";
        }
        if secret.is_empty() {
            panic!("SECRET is undefined or too short (min 64 chars)!")
        }
        secret
    }
    /// Get OpenID providers configuration
    pub fn openid_provider(&self) -> OIDCProvider<'_> {
        OIDCProvider {
            client_id: self.oidc_client_id.as_str(),
            client_secret: self.oidc_client_secret.as_str(),
            configuration_url: self.oidc_configuration_url.as_str(),
        }
    }
    /// Get OIDC callback URL
    pub fn oidc_redirect_url(&self) -> String {
        self.oidc_redirect_url
            .replace("APP_ORIGIN", &self.website_origin)
    }
    /// Get VirtWeb token private key
    pub fn token_private_key(&self) -> JWTPrivateKey {
        JWTPrivateKey::ES384 {
            r#priv: self.virtweb_token_private_key.to_string(),
        }
    }
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct OIDCProvider<'a> {
    #[serde(skip_serializing)]
    pub client_id: &'a str,
    #[serde(skip_serializing)]
    pub client_secret: &'a str,
    #[serde(skip_serializing)]
    pub configuration_url: &'a str,
}
#[cfg(test)]
mod test {
    use crate::app_config::AppConfig;
    #[test]
    fn verify_cli() {
        use clap::CommandFactory;
        AppConfig::command().debug_assert()
    }
}