use criterion::{criterion_group, criterion_main, Criterion, black_box};
use dms::{encode, tier1};

const SIMPLE_T0: &str = "x: 1\ny: \"hello\"\na: [1, 2, 3]\n";

const T1_WITH_LEADING: &str = "\
+++
_dms_tier: 1
_dms_imports:
  + dialect: \"x\"
    version: \"1.0.0\"
    bind:
      \"|\": [\"tag\"]
+++
|tag()
x: 1
|tag(class: \"x\")
y: \"hello\"
|tag()
a: [1, 2, 3]
";

fn build_registry() -> tier1::InMemoryRegistry {
    let d = tier1::DialectSpec {
        name: "x".into(),
        version: "1.0.0".into(),
        version_strategy: tier1::VersionStrategy::default(),
        families: vec![tier1::FamilySpec {
            name: "tag".into(),
            default_sigils: vec!["|".into()],
            empty_default: dms::Value::Table(Default::default()),
            content_slot: Some("children".into()),
            params: tier1::ParamSignature::default(),
        }],
        structs: vec![],
    };
    tier1::InMemoryRegistry::new().with(d)
}

fn bench_encode(c: &mut Criterion) {
    let mut g = c.benchmark_group("encode");

    // Tier-0 baseline
    let t0_doc = dms::decode_document(SIMPLE_T0).unwrap();
    g.bench_function("tier0/simple", |b| {
        b.iter(|| encode(black_box(&t0_doc)).unwrap())
    });

    // Tier-1 encode without registry
    let t1_doc = tier1::decode_t1(T1_WITH_LEADING).unwrap();
    g.bench_function("tier1/leading_no_registry", |b| {
        b.iter(|| tier1::encode_t1(black_box(&t1_doc)).unwrap())
    });

    // Tier-1 encode with registry (hoist-aware canonical form)
    let registry = build_registry();
    let t1_doc_r = tier1::decode_t1_with_registry(T1_WITH_LEADING, &registry).unwrap();
    g.bench_function("tier1/leading_with_registry", |b| {
        b.iter(|| tier1::encode_t1_with_registry(black_box(&t1_doc_r), &registry).unwrap())
    });

    g.finish();
}

criterion_group!(benches, bench_encode);
criterion_main!(benches);
