//! Supply-chain (BOM) identifiers for the adom-lbr v1.6.0 contract.
//!
//! Whenever chip-fetcher shells `adom-lbr generate`/`export` it MUST pass the
//! supply-chain IDs it already looked up — `--mfr`, `--mpn`, `--mouser`,
//! `--digikey`, `--lcsc` — so adom-lbr writes MF/MPN/MOUSER/DIGIKEY/LCSC into
//! the library device <technology>, which Fusion 360 / Altium / OrCAD surface in
//! the BOM. Omitting one is only OK when that distributor genuinely has no match
//! (adom-lbr just notes it). We read everything we know from `stock.json` (the
//! Mouser snapshot), falling back to `info.json` and `<mpn>-symbol.extracted.json`.

use serde_json::Value;
use std::path::Path;

fn read_json(dir: &Path, name: &str) -> Value {
    std::fs::read_to_string(dir.join(name))
        .ok()
        .and_then(|s| serde_json::from_str(&s).ok())
        .unwrap_or(Value::Null)
}

/// Follow a path of keys to a non-empty string.
fn s(v: &Value, path: &[&str]) -> Option<String> {
    let mut cur = v;
    for k in path {
        cur = cur.get(k)?;
    }
    cur.as_str().filter(|x| !x.is_empty()).map(|x| x.to_string())
}

/// The adom-lbr BOM flags for a part, in order. Always includes `--mpn` (the
/// orderable MPN); `--mfr` and `--mouser` when known; `--digikey`/`--lcsc` only
/// when a real distributor part number is on record (omitted otherwise, which
/// adom-lbr accepts as "not stocked there").
pub fn flags(dir: &Path, mpn: &str) -> Vec<String> {
    let stock = read_json(dir, "stock.json");
    let info = read_json(dir, "info.json");
    let sym = read_json(dir, &format!("{mpn}-symbol.extracted.json"));

    // Manufacturer: Mouser snapshot → info.json → extracted symbol.
    let mfr = s(&stock, &["mouser", "manufacturer"])
        .or_else(|| s(&info, &["manufacturer"]))
        .or_else(|| s(&sym, &["manufacturer"]));

    // Orderable MPN: Mouser's exact MPN → info.json → the part name itself.
    let part_mpn = s(&stock, &["mouser", "mpn"])
        .or_else(|| s(&info, &["mpn"]))
        .unwrap_or_else(|| mpn.to_string());

    let mouser = s(&stock, &["mouser", "mouser_pn"]);
    // DigiKey / LCSC only when an explicit order code is recorded (stock.json is
    // Mouser-centric; these are usually absent → correctly omitted).
    let digikey = s(&stock, &["digikey", "digikey_pn"]).or_else(|| s(&stock, &["digikey_pn"]));
    let lcsc = s(&stock, &["lcsc", "lcsc_pn"]).or_else(|| s(&stock, &["lcsc_pn"]));

    let mut f = Vec::new();
    if let Some(m) = mfr {
        f.push("--mfr".into());
        f.push(m);
    }
    f.push("--mpn".into());
    f.push(part_mpn);
    if let Some(m) = mouser {
        f.push("--mouser".into());
        f.push(m);
    }
    if let Some(d) = digikey {
        f.push("--digikey".into());
        f.push(d);
    }
    if let Some(l) = lcsc {
        f.push("--lcsc".into());
        f.push(l);
    }
    f
}