use std::{env, fs, path::PathBuf};

const H3_DNS_SERVER_ENV: &str = "DHTTP_H3_DNS_SERVER";
const HTTP_DNS_SERVER_ENV: &str = "DHTTP_HTTP_DNS_SERVER";
const MDNS_SERVICE_ENV: &str = "DHTTP_MDNS_SERVICE";

const DEFAULT_H3_DNS_SERVER: &str = "https://dhttp.example.net";
const DEFAULT_HTTP_DNS_SERVER: &str = "https://dhttp.example.net";
const DEFAULT_MDNS_SERVICE: &str = "dhttp.example.net";

fn main() {
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR is set by cargo"));

    let h3_dns_server = env_or_default(H3_DNS_SERVER_ENV, DEFAULT_H3_DNS_SERVER);
    let http_dns_server = env_or_default(HTTP_DNS_SERVER_ENV, DEFAULT_HTTP_DNS_SERVER);
    let mdns_service = env_or_default(MDNS_SERVICE_ENV, DEFAULT_MDNS_SERVICE);

    let bootstrap = format!(
        "// @generated by build.rs; do not edit.\n\
         pub const DHTTP_H3_DNS_SERVER: &str = {h3_dns_server:?};\n\
         pub const DHTTP_HTTP_DNS_SERVER: &str = {http_dns_server:?};\n\
         pub const DHTTP_MDNS_SERVICE: &str = {mdns_service:?};\n"
    );
    fs::write(out_dir.join("bootstrap.rs"), bootstrap)
        .expect("failed to write generated DHTTP DNS bootstrap constants");

    println!("cargo::rerun-if-env-changed={H3_DNS_SERVER_ENV}");
    println!("cargo::rerun-if-env-changed={HTTP_DNS_SERVER_ENV}");
    println!("cargo::rerun-if-env-changed={MDNS_SERVICE_ENV}");
}

fn env_or_default(name: &str, default: &str) -> String {
    env::var(name).unwrap_or_else(|_| default.to_owned())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn missing_env_uses_dhttp_example_net_placeholder() {
        let name = format!("__DDNS_MISSING_BOOTSTRAP_{}", std::process::id());

        assert_eq!(
            env_or_default(&name, DEFAULT_H3_DNS_SERVER),
            "https://dhttp.example.net"
        );
        assert_eq!(
            env_or_default(&name, DEFAULT_HTTP_DNS_SERVER),
            "https://dhttp.example.net"
        );
        assert_eq!(
            env_or_default(&name, DEFAULT_MDNS_SERVICE),
            "dhttp.example.net"
        );
    }

    #[test]
    fn placeholder_urls_do_not_include_explicit_ports() {
        for url in [DEFAULT_H3_DNS_SERVER, DEFAULT_HTTP_DNS_SERVER] {
            let authority = url
                .strip_prefix("https://")
                .expect("placeholder URL uses https")
                .split('/')
                .next()
                .expect("placeholder URL has an authority");

            assert_eq!(authority, "dhttp.example.net");
        }
    }
}
