extern crate bindgen;
extern crate pkg_config;
extern crate system_deps;

use std::env;
use std::path::Path;
use std::process::Command;

use system_deps::Dependencies;

fn watch_file(path: &str) {
    println!("cargo::rerun-if-changed={}", path);
}

fn bind(out_dir: &str, dependencies: &Dependencies) {
    let includes: Vec<String> = dependencies
        .all_include_paths()
        .iter()
        .filter_map(|inc| inc.to_str())
        .map(|inc| format!("-I{inc}"))
        .collect();

    let bindings = bindgen::Builder::default()
        .headers([
            "wmenu/menu.h",
            "wmenu/pango.h",
            "wmenu/pool-buffer.h",
            "wmenu/render.h",
            "wmenu/wayland.h",
        ])
        .clang_args(includes)
        .clang_arg("-Wall")
        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
        .blocklist_var("FP_.*")
        .generate()
        .expect("Unable to generate bindings");

    bindings
        .write_to_file(&out_dir)
        .expect("couldn't write bindings");
}

fn build(out_dir: &str, dependencies: &Dependencies) {
    let _ = Command::new("meson")
        .args(["setup", &out_dir, "wmenu"])
        .output();

    Command::new("meson")
        .args(["compile", "-C", &out_dir])
        .output()
        .expect("could not build wmenu");
}

fn main() {
    let deps = system_deps::Config::new().probe().unwrap();

    let out_dir = env::var("OUT_DIR").unwrap();
    let bindings = Path::new(&out_dir).join("bindings.rs");
    let build_dir = Path::new(&out_dir).join("build/");
    let build_dir = build_dir.to_str().unwrap();

    println!("cargo:rustc-link-search=native={}", build_dir);
    println!("cargo:rustc-link-lib=wmenu");

    watch_file("Cargo.toml");
    watch_file("build.rs");

    bind(bindings.to_str().unwrap(), &deps);
    build(build_dir, &deps);
}