//! `wai_identify_vectors` — the corpus of `extensions/media-identify.md` §10.
//!
//! - `gen <dir>`: writes `<dir>/gen/` and `<dir>/vectors.json` from `<dir>/ext/` (never in CI).
//! - `verify <dir>`: requires that they regenerate byte for byte, and every result with them.

use std::collections::BTreeMap;
use std::path::Path;
use std::process::ExitCode;
use wai::identify::corpus;

fn read_dir(root: &Path, sub: &str, out: &mut BTreeMap<String, Vec<u8>>) -> std::io::Result<()> {
    let d = root.join(sub);
    if !d.is_dir() {
        return Ok(());
    }
    for e in std::fs::read_dir(d)? {
        let p = e?.path();
        let name = p.file_name().expect("a file name").to_string_lossy().to_string();
        out.insert(format!("{sub}/{name}"), std::fs::read(&p)?);
    }
    Ok(())
}

fn files(dir: &Path) -> std::io::Result<BTreeMap<String, Vec<u8>>> {
    let mut out = BTreeMap::new();
    read_dir(dir, "ext", &mut out)?;
    read_dir(dir, "gen", &mut out)?;
    if dir.join("vectors.json").is_file() {
        out.insert("vectors.json".into(), std::fs::read(dir.join("vectors.json"))?);
    }
    Ok(out)
}

fn run() -> Result<bool, String> {
    let args: Vec<String> = std::env::args().skip(1).collect();
    let (Some(cmd), Some(dir), 2) = (args.first(), args.get(1), args.len()) else {
        return Err("wai_identify_vectors gen|verify <dir>".into());
    };
    let dir = Path::new(dir);
    let all = files(dir).map_err(|e| e.to_string())?;
    match cmd.as_str() {
        "gen" => {
            let ext: BTreeMap<String, Vec<u8>> = all.into_iter().filter(|(k, _)| k.starts_with("ext/")).collect();
            let made = corpus::generate(&ext)?;
            let g = dir.join("gen");
            if g.exists() {
                std::fs::remove_dir_all(&g).map_err(|e| e.to_string())?;
            }
            std::fs::create_dir_all(&g).map_err(|e| e.to_string())?;
            for (k, v) in &made {
                std::fs::write(dir.join(k), v).map_err(|e| format!("{k}: {e}"))?;
            }
            eprintln!("wrote {} files", made.len());
            Ok(true)
        }
        "verify" => {
            let fails = corpus::verify(&all);
            for f in &fails {
                eprintln!("FAIL {f}");
            }
            eprintln!("{} failures", fails.len());
            Ok(fails.is_empty())
        }
        other => Err(format!("{other}: gen or verify")),
    }
}

fn main() -> ExitCode {
    match run() {
        Ok(true) => ExitCode::SUCCESS,
        Ok(false) => ExitCode::from(1),
        Err(e) => {
            eprintln!("{e}");
            ExitCode::from(2)
        }
    }
}
