use serde::Deserialize;
use std::process::Command;

// We don't use cargo-metadata because it has a very unstable API!

#[derive(Deserialize, Debug)]
struct Metadata {
  workspace_members: Vec<PackageId>,
  resolve: MResolve,
  packages: Vec<MPackage>,
}
#[derive(Deserialize, Debug)]
struct MResolve {
  nodes: Vec<MNode>,
}
#[derive(Deserialize, Debug)]
struct MNode {
  id: PackageId,
  dependencies: Vec<PackageId>,
}
#[derive(Deserialize, Debug)]
struct MPackage {
  id: PackageId,
  version: String,
  name: String,
}
#[derive(Deserialize, Debug, Eq, PartialEq)]
#[serde(transparent)]
struct PackageId(String);

impl Metadata {
  fn package(&self, id: &PackageId) -> &MPackage {
    self.packages.iter()
      .find(|p| &p.id == id).expect("missing")
  }
}

struct Context<'c> {
  hippo: &'c MNode,
  metadata: &'c Metadata,
}

impl Context<'_> {
  fn emit_for_package(&self, package: &str, versions: &[&str]) {
    let pkg = self.hippo.dependencies.iter()
      .map(|i| self.metadata.package(i))
      .find(|i| i.name == package).expect("no nix in hippotat's deps");

    let pkg = &pkg.version;
    let pkg: semver::Version = pkg.parse().expect(pkg);

    for test in versions {
      let cfg = test.replace('.', "_").replace(">=", "ge_");
      let test: semver::VersionReq = test.parse().unwrap();
      let cfg = format!("{package}_{cfg}");
      println!(r#"cargo:rustc-check-cfg=cfg({cfg})"#);
      if test.matches(&pkg) {
        println!("cargo:rustc-cfg={cfg}");
      }
    }
  }
}

fn main(){
  let x = Command::new("cargo")
    .args(["metadata", "--format-version=1"])
    .stderr(std::process::Stdio::inherit())
    .output().unwrap();
  if !x.status.success() { panic!() }
  let output = std::str::from_utf8(&x.stdout).unwrap();
//  eprintln!("{}", output);
  let metadata: Metadata = serde_json::from_str(&output).unwrap();

  let hippo = metadata.workspace_members.iter()
    .map(|i| metadata.package(i))
    .find(|p| p.name == "hippotat").expect("no hippotat in workspace?");
  let hippo = metadata.resolve.nodes.iter()
    .find(|n| n.id == hippo.id).expect("no hippotat in nodes!");

  let ctx = Context { hippo, metadata: &metadata };

  ctx.emit_for_package("nix", &[">=0.27", ">=0.28"]);
}
