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

const T1_DOC: &str = "\
+++
_dms_tier: 1
_dms_imports:
  + dialect: \"x\"
    version: \"1.0.0\"
    bind:
      \"|\": [\"tag\"]
+++
|tag()
x: 1
y: \"hello\"
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_round_trip(c: &mut Criterion) {
    let mut g = c.benchmark_group("round_trip");
    let registry = build_registry();

    // Full round-trip: decode → encode
    g.bench_function("tier1/decode_then_encode", |b| {
        b.iter(|| {
            let doc =
                tier1::decode_t1_with_registry(black_box(T1_DOC), &registry).unwrap();
            tier1::encode_t1_with_registry(black_box(&doc), &registry).unwrap()
        })
    });

    // Decode only (registry path)
    g.bench_function("tier1/decode_only", |b| {
        b.iter(|| tier1::decode_t1_with_registry(black_box(T1_DOC), &registry).unwrap())
    });

    // Encode only (pre-decoded document)
    let pre_decoded = tier1::decode_t1_with_registry(T1_DOC, &registry).unwrap();
    g.bench_function("tier1/encode_only", |b| {
        b.iter(|| tier1::encode_t1_with_registry(black_box(&pre_decoded), &registry).unwrap())
    });

    // Streaming decode — batch-decode then emit events as an iterator
    g.bench_function("tier1/streaming_decode", |b| {
        b.iter(|| {
            let iter = tier1_stream::decode_t1_streaming(black_box(T1_DOC)).unwrap();
            let events: Vec<_> = iter.collect();
            black_box(events)
        })
    });

    g.finish();
}

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