use std::{
    env,
    fs::File,
    io::{self, BufRead, BufReader},
    path::Path,
};

/// Takes a path to a library like `libframework.so` and returns the name for the linker, aka
/// `framework`
fn libname_from_path(p: &Path) -> String {
    let base = p
        .file_stem()
        .and_then(|os_str| os_str.to_str())
        .expect("'p' must be valid UTF-8 and have an extension.")
        .strip_prefix("lib")
        .expect("'p' should start with `lib`");

    // foo.so.1.2.3 -> foo
    base.split('.').next().unwrap_or(base).to_string()
}

fn print_link_options(p: &Path) {
    println!(
        "cargo:rustc-link-search=native={}",
        p.parent().unwrap().to_string_lossy()
    );
    println!("cargo:rustc-link-lib={}", libname_from_path(p));
}

/// Registers the libraries specified in the `EVEREST_RS_LINK_DEPENDENCIES` environment variable.
/// Expected to be a path to a text file that contains one object file path per line.
fn register_everest_link_deps(link_deps_path: &str) -> io::Result<()> {
    let link_deps = File::open(link_deps_path).map_err(|e| {
        io::Error::new(
            e.kind(),
            format!("Could not open EVEREST_RS_LINK_DEPENDENCIES file '{link_deps_path}': {e}"),
        )
    })?;

    let mut found_any = false;
    for line in BufReader::new(link_deps).lines() {
        let line = line?;
        let path = Path::new(&line);
        if !path.is_file() {
            return Err(io::Error::new(io::ErrorKind::NotFound, format!(
                "Cannot find library path '{line}' specified in EVEREST_RS_LINK_DEPENDENCIES ({link_deps_path}).",
            )));
        }

        print_link_options(path);
        found_any = true;
    }

    if found_any {
        Ok(())
    } else {
        Err(io::Error::new(
            io::ErrorKind::NotFound,
            format!("No library paths found in EVEREST_RS_LINK_DEPENDENCIES ({link_deps_path})."),
        ))
    }
}

fn main() {
    // See https://doc.rust-lang.org/cargo/reference/features.html#build-scripts
    // for details.
    if env::var("CARGO_FEATURE_BUILD_BAZEL").is_ok() {
        println!("Skipping due to bazel");
        return;
    }

    let Ok(link_deps_path) = env::var("EVEREST_RS_LINK_DEPENDENCIES") else {
        panic!("EVEREST_RS_LINK_DEPENDENCIES environment variable is not set. This variable should point to the build/everestrs-link-dependencies.txt file generated by CMake.");
    };

    register_everest_link_deps(&link_deps_path)
        .expect("Failed to register libraries specified in EVEREST_RS_LINK_DEPENDENCIES");

    println!("cargo:rustc-link-lib=boost_log");
    println!("cargo:rustc-link-lib=boost_log_setup");
}
