use std::process::Command;

fn main() {
    println!("cargo:rerun-if-env-changed=METACRATE_RUST_COMMIT");
    println!("cargo:rerun-if-changed=../.git/HEAD");
    println!("cargo:rerun-if-changed=../.git/packed-refs");
    if let Some(reference) = git_reference() {
        println!("cargo:rerun-if-changed=../.git/{reference}");
    }

    let commit = std::env::var("METACRATE_RUST_COMMIT")
        .ok()
        .filter(|value| valid_commit(value))
        .or_else(git_commit)
        .unwrap_or_else(|| "unavailable".to_owned());
    println!("cargo:rustc-env=METACRATE_RUST_COMMIT={commit}");
}

fn git_reference() -> Option<String> {
    let output = Command::new("git")
        .args(["symbolic-ref", "--quiet", "HEAD"])
        .output()
        .ok()?;
    let reference = String::from_utf8(output.stdout).ok()?;
    let reference = reference.trim();
    (output.status.success()
        && reference.starts_with("refs/")
        && reference
            .bytes()
            .all(|byte| byte.is_ascii_alphanumeric() || b"/-_.".contains(&byte)))
    .then(|| reference.to_owned())
}

fn git_commit() -> Option<String> {
    let output = Command::new("git")
        .args(["rev-parse", "--verify", "HEAD"])
        .output()
        .ok()?;
    let commit = String::from_utf8(output.stdout).ok()?;
    let commit = commit.trim();
    (output.status.success() && valid_commit(commit)).then(|| commit.to_owned())
}

fn valid_commit(value: &str) -> bool {
    matches!(value.len(), 40 | 64) && value.bytes().all(|byte| byte.is_ascii_hexdigit())
}
