//! Roundtrip gate for master/examples/.
//!
//! Mirrors crates/ailang-surface/tests/round_trip.rs but scoped to
//! the master examples directory. For each .ail.json fixture: load,
//! print via ailang_surface::print, reparse, canonicalise both sides,
//! assert byte equality.

use std::path::{Path, PathBuf};

fn examples_dir() -> PathBuf {
    let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    manifest.parent().unwrap().join("master").join("examples")
}

fn list_examples() -> Vec<PathBuf> {
    let mut paths: Vec<PathBuf> = std::fs::read_dir(examples_dir())
        .expect("master/examples/ should exist")
        .filter_map(|entry| entry.ok())
        .map(|entry| entry.path())
        .filter(|path| path.extension().and_then(|s| s.to_str()) == Some("json"))
        .filter(|path| {
            path.file_name()
                .and_then(|s| s.to_str())
                .map(|name| name.ends_with(".ail.json"))
                .unwrap_or(false)
        })
        .collect();
    paths.sort();
    paths
}

fn round_trip_one(path: &Path) -> Result<(), String> {
    let original = ailang_core::load_module(path)
        .map_err(|e| format!("{}: load_module failed: {e}", path.display()))?;
    let text = ailang_surface::print(&original);
    let parsed = ailang_surface::parse(&text)
        .map_err(|e| format!("{}: surface::parse failed: {e}", path.display()))?;
    let bytes_original = ailang_core::canonical::to_bytes(&original);
    let bytes_parsed = ailang_core::canonical::to_bytes(&parsed);
    if bytes_original != bytes_parsed {
        return Err(format!(
            "{}: roundtrip diverged.\n--- printed AIL ---\n{}\n--- original bytes len {} vs parsed bytes len {} ---",
            path.display(),
            text,
            bytes_original.len(),
            bytes_parsed.len(),
        ));
    }
    Ok(())
}

#[test]
fn every_example_roundtrips_via_ail() {
    let examples = list_examples();
    assert!(
        !examples.is_empty(),
        "master/examples/ should contain at least one .ail.json fixture"
    );
    let mut failures: Vec<String> = Vec::new();
    for path in &examples {
        if let Err(msg) = round_trip_one(path) {
            failures.push(msg);
        }
    }
    if !failures.is_empty() {
        panic!(
            "{} of {} examples failed roundtrip:\n\n{}",
            failures.len(),
            examples.len(),
            failures.join("\n\n")
        );
    }
}
