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

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(),
            }
        }
    }
}

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() => {
            String::from_utf8_lossy(&output.stdout).trim().to_string()
        }
        _ => "unknown".to_string(),
    };
    info!("{cargo_version}");

    let rustc_version = match Command::new("rustc").arg("--version").output() {
        Ok(output) if output.status.success() => {
            String::from_utf8_lossy(&output.stdout).trim().to_string()
        }
        _ => "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;
        }
    };

    writeln!(built_rs, "pub const GIT_COMMIT_HASH: &str = \"{}\";", git_info).unwrap();

    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 const {}_VERSION: &str = \"{}\";",
                            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");
}