//! Do real index buffers address their whole vertex pool?
//!
//! `validate_block` rejects a block whose indices reach fewer than `vtx_count−4`
//! vertices ("buffer not covered"). That gate is the furthest-reached rejection
//! for a handful of resources that never decode — so the question is whether it
//! is well founded. This measures the slack on every block that DOES decode: if
//! real geometry always covers its pool, under-coverage is good evidence of a
//! wrong candidate and the gate stands.
use sylpheed_formats::mesh::Xbg7Model;
use std::collections::BTreeMap;

fn main() {
    let dir = std::env::args().nth(1).expect("resource3d dir");
    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<i64, usize> = BTreeMap::new();
    let mut worst: Vec<(i64, String)> = Vec::new();
    for f in &files {
        let Ok(bytes) = std::fs::read(f) else { continue };
        for m in Xbg7Model::anchor_models_cancellable(&bytes, 0.0, &|| false) {
            for sub in &m.meshes {
                if sub.positions.is_empty() || sub.indices.is_empty() {
                    continue;
                }
                let max_idx = *sub.indices.iter().max().unwrap() as i64;
                let slack = sub.positions.len() as i64 - 1 - max_idx;
                *hist.entry(slack.min(20)).or_default() += 1;
                if slack > 4 {
                    worst.push((slack, format!("{} in {}", m.name, f.file_name().unwrap().to_string_lossy())));
                }
            }
        }
    }
    println!("unreferenced tail vertices (vtx_count − 1 − max index), over decoded sub-meshes:");
    for (slack, n) in &hist {
        println!("  {:>3}{} : {n}", slack, if *slack == 20 { "+" } else { " " });
    }
    worst.sort_by_key(|(s, _)| std::cmp::Reverse(*s));
    for (s, w) in worst.iter().take(5) {
        println!("  largest slack {s}: {w}");
    }
}
