use std::{io::Write, option_env, process::Command};

use syn::parse_quote;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let prefix = option_env!("PREFIX").unwrap_or("/usr/local").to_owned();
    let bindir = option_env!("BINDIR")
        .map(ToOwned::to_owned)
        .unwrap_or_else(|| format!("{prefix}/bin"));
    let datadir = option_env!("DATADIR")
        .map(ToOwned::to_owned)
        .unwrap_or_else(|| format!("{prefix}/share"));
    let pkgdatadir = option_env!("PKGDATADIR")
        .map(ToOwned::to_owned)
        .unwrap_or_else(|| format!("{datadir}/xfce4/xfwl4"));
    let localedir = option_env!("LOCALEDIR")
        .map(ToOwned::to_owned)
        .unwrap_or_else(|| format!("{datadir}/locale"));

    let gettext_package = env!("CARGO_PKG_NAME");

    let git_hash = get_git_hash();
    let version_full = if let Some(git_hash) = git_hash {
        format!("{}-{}", env!("CARGO_PKG_VERSION"), git_hash)
    } else {
        env!("CARGO_PKG_VERSION").to_owned()
    };

    for name in [
        "BINDIR",
        "CARGO_PKG_NAME",
        "CARGO_PKG_VERSION",
        "DATADIR",
        "LOCALEDIR",
        "PKGDATADIR",
        "PREFIX",
    ] {
        println!("cargo::rerun-if-env-changed={name}");
    }

    let build_config_contents: syn::File = parse_quote! {
        /// This file is autogenerated by build.rs; DO NOT EDIT

        #[allow(unused)]
        pub const BUILD_PREFIX: &str = #prefix;
        #[allow(unused)]
        pub const BUILD_BINDIR: &str = #bindir;
        #[allow(unused)]
        pub const BUILD_DATADIR: &str = #datadir;
        #[allow(unused)]
        pub const BUILD_PKGDATADIR: &str = #pkgdatadir;
        #[allow(unused)]
        pub const BUILD_LOCALEDIR: &str = #localedir;

        #[allow(unused)]
        pub const GETTEXT_PACKAGE: &str = #gettext_package;

        #[allow(unused)]
        pub const BUILD_VERSION_FULL: &str = #version_full;
    };

    let mut build_config = tempfile::NamedTempFile::new_in(std::env::var("OUT_DIR").expect("OUT_DIR not set"))?;
    build_config.write_all(prettyplease::unparse(&build_config_contents).as_bytes())?;

    let build_config_path = format!(
        "{}/src/build_config.rs",
        std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set")
    );
    build_config.persist(build_config_path)?;

    Ok(())
}

fn get_git_hash() -> Option<String> {
    let hash = run_git(&["rev-parse", "--short", "HEAD"]);

    for path in ["HEAD", "logs/HEAD"] {
        if let Some(path) = run_git(&["rev-parse", "--git-path", path]) {
            println!("cargo:rerun-if-changed={path}");
        }
    }

    hash
}

fn run_git(args: &[&str]) -> Option<String> {
    let out = Command::new("git").args(args).output().ok()?;
    if !out.status.success() {
        None
    } else {
        let s = String::from_utf8_lossy(&out.stdout).trim().to_owned();
        (!s.is_empty()).then_some(s)
    }
}
