//! Calibrate the connectivity cap against the whole disc.
//!
//! `XBG7_EDGE_CAP` sets the cap; this reports, for one setting, how much
//! geometry decodes and how self-consistent it is across containers — the two
//! numbers any change to the cap has to trade off. Run it once per cap value.
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();

    // name -> (verts, tris) -> spans seen, exactly as mesh_consistency_disc.rs.
    let mut seen: BTreeMap<String, Vec<([i64; 3], usize, usize)>> = BTreeMap::new();
    let (mut models, mut verts) = (0usize, 0usize);
    for f in &files {
        let Ok(bytes) = std::fs::read(f) else { continue };
        for m in Xbg7Model::anchor_models_cancellable(&bytes, 0.0, &|| false) {
            let (mut lo, mut hi) = ([f32::MAX; 3], [f32::MIN; 3]);
            for s in &m.meshes {
                for q in &s.positions {
                    for k in 0..3 {
                        lo[k] = lo[k].min(q[k]);
                        hi[k] = hi[k].max(q[k]);
                    }
                }
            }
            if lo[0] == f32::MAX {
                continue;
            }
            let v: usize = m.meshes.iter().map(|s| s.positions.len()).sum();
            let t: usize = m.meshes.iter().map(|s| s.indices.len() / 3).sum();
            models += 1;
            verts += v;
            if std::env::var("DUMP").is_ok() {
                // Per-resource signature, so two cap settings can be diffed:
                // a cap change that silently MOVES an existing anchor is the
                // risk a coverage count cannot see.
                println!(
                    "{}|{}|{v}|{t}|{}|{}|{}|{}",
                    f.file_name().unwrap().to_string_lossy(),
                    m.name,
                    m.meshes[0].vbuf_offset.unwrap_or(0),
                    (hi[0] - lo[0]).round() as i64,
                    (hi[1] - lo[1]).round() as i64,
                    (hi[2] - lo[2]).round() as i64
                );
            }
            seen.entry(m.name.clone()).or_default().push((
                [
                    (hi[0] - lo[0]).round() as i64,
                    (hi[1] - lo[1]).round() as i64,
                    (hi[2] - lo[2]).round() as i64,
                ],
                v,
                t,
            ));
        }
    }
    let (mut shared, mut inconsistent) = (0usize, 0usize);
    for (_, list) in &seen {
        if list.len() < 2 || !list.iter().all(|e| e.1 == list[0].1 && e.2 == list[0].2) {
            continue;
        }
        shared += 1;
        if list.iter().any(|e| e.0 != list[0].0) {
            inconsistent += 1;
        }
    }
    println!(
        "cap={}  models={models}  verts={verts}  shared={shared}  inconsistent={inconsistent}",
        std::env::var("XBG7_EDGE_CAP").unwrap_or_else(|_| "0.42 (default)".into())
    );
}
