use build_print::*;
use cargo_lock::Lockfile;
use std::env;
use std::fs::OpenOptions;
use std::io::Write;
use std::path::Path;
use std::process::Command;

fn get_git_info() -> String {
    match Command::new("git")
        .arg("describe")
        .arg("--always")
        .arg("--dirty")
        .output()
    {
        Ok(output) if output.status.success() => {
            String::from_utf8_lossy(&output.stdout).trim().to_string()
        }
        _ => {
            match Command::new("git")
                .arg("rev-parse")
                .arg("--abbrev-ref")
                .arg("HEAD")
                .output()
            {
                Ok(output) if output.status.success() => {
                    let head = String::from_utf8_lossy(&output.stdout);
                    let head = head.trim();
                    if head == "HEAD" {
                        "DETACHED".to_string()
                    } else {
                        //TDDO: properly parse branch hashes
                        format!("BRANCH: {}", head)
                    }
                }
                _ => "UNKNOWN".to_string(),
            }
        }
    }
}
static ALLOW_DEAD_CODE: &str = "#[allow(dead_code)]\n";
fn main() {
    if let Err(e) = built::write_built_file() {
        panic!("{e}");
    }
    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("built.rs");
    let proj_root = env!("CARGO_MANIFEST_DIR").to_string();
    let tmp = format!("{}/../Cargo.lock", proj_root);
    let lockfile_path = Path::new(&tmp).canonicalize().expect("INvalid");

    let cargo_version = match Command::new("cargo").arg("--version").output() {
        Ok(output) if output.status.success() => {
            let mut version = String::new();
            version.push_str(ALLOW_DEAD_CODE);
            version.push_str(&String::from_utf8_lossy(&output.stdout).trim().to_string());
            version
        }
        _ => "unknown".to_string(),
    };
    info!("{cargo_version}");

    let rustc_version = match Command::new("rustc").arg("--version").output() {
        Ok(output) if output.status.success() => {
            let mut version = String::new();
            version.push_str(ALLOW_DEAD_CODE);
            version.push_str(&String::from_utf8_lossy(&output.stdout).trim().to_string());
            version
        }
        _ => "unknown".to_string(),
    };
    info!("{rustc_version}");

    let git_info = get_git_info();
    info!("Git Info: {}", git_info);

    let mut built_rs = match OpenOptions::new().append(true).open(&dest_path) {
        Ok(file) => file,
        Err(e) => {
            error!("Could not open built.rs for appending: {}", e);
            return;
        }
    };

    match Lockfile::load(lockfile_path) {
        Ok(lockfile) => {
            let dependencies_to_track = ["tokio", "winit", "wgpu"];

            for package in lockfile.packages {
                let name = package.name.as_str();
                if dependencies_to_track.contains(&name) {
                    let version = package.version.to_string();
                    writeln!(
                        built_rs,
                        "{}pub static {}_VERSION: &str = \"{}\";",
                        ALLOW_DEAD_CODE,
                        name.to_uppercase().replace('-', "_"),
                        version
                    )
                    .unwrap();
                }
            }
        }
        Err(e) => {
            error!("Error loading Cargo.lock: {}", e);
        }
    }

    std::println!("cargo:rerun-if-changed=Cargo.lock");
    std::println!("cargo:rerun-if-changed=.git/HEAD");
    std::println!("cargo:rerun-if-changed=.git/index");
}