//! Which gate stops the resources that never decode?
//! Usage: gate_histogram <resource3d_dir> [max_resources]
use sylpheed_formats::mesh::{debug_best_rejection, xbg7_resource_names, Xbg7Model};
use std::collections::{BTreeMap, HashSet};

fn main() {
    let dir = std::env::args().nth(1).expect("resource3d dir");
    let cap: usize = std::env::args().nth(2).and_then(|s| s.parse().ok()).unwrap_or(usize::MAX);
    let mut files: Vec<_> = std::fs::read_dir(&dir)
        .unwrap()
        .flatten()
        .map(|e| e.path())
        .filter(|p| p.extension().and_then(|s| s.to_str()) == Some("xpr"))
        .collect();
    files.sort();

    let mut hist: BTreeMap<usize, (usize, String)> = BTreeMap::new();
    let mut done = 0usize;
    for f in &files {
        if done >= cap {
            break;
        }
        let Ok(bytes) = std::fs::read(f) else { continue };
        let names = xbg7_resource_names(&bytes);
        if names.is_empty() {
            continue;
        }
        let got: HashSet<String> = Xbg7Model::anchor_models_cancellable(&bytes, 0.0, &|| false)
            .into_iter()
            .map(|m| m.name)
            .collect();
        for n in names.iter().filter(|n| !got.contains(*n)) {
            if done >= cap {
                break;
            }
            done += 1;
            if let Some((rank, why)) = debug_best_rejection(&bytes, n) {
                let e = hist.entry(rank).or_insert((0, String::new()));
                e.0 += 1;
                if e.1.is_empty() {
                    e.1 = format!("{n}: {why}");
                }
            }
        }
    }
    println!("furthest gate reached, over {done} resources that never decode:");
    let label = |r: usize| match r {
        0 => "no gate reached",
        1 => "index out of range",
        2 => "buffer not covered by indices",
        3 => "degenerate / implausible positions",
        4 => "connectivity (mean edge / diagonal)",
        5 => "winding consistency",
        9 => "grouped pool (different path)",
        _ => "?",
    };
    for (r, (n, ex)) in &hist {
        println!("  {:<38} {n:>5}   e.g. {ex}", label(*r));
    }
}
