//! Benchmarks for BFT JSON CRDT operation throughput.
use bft_json_crdt::{
    json_crdt::JsonValue, keypair::make_author, list_crdt::ListCrdt, op::Op, op::ROOT_ID,
};
use criterion::{criterion_group, criterion_main, Criterion};
use rand::seq::SliceRandom;

fn bench_insert_100_root(c: &mut Criterion) {
    c.bench_function("bench insert 100 root", |b| {
        b.iter(|| {
            let mut list = ListCrdt::<i64>::new(make_author(1), vec![]);
            for i in 0..100 {
                list.insert(ROOT_ID, i);
            }
        })
    });
}

fn bench_insert_100_linear(c: &mut Criterion) {
    c.bench_function("bench insert 100 linear", |b| {
        b.iter(|| {
            let mut list = ListCrdt::<i64>::new(make_author(1), vec![]);
            let mut prev = ROOT_ID;
            for i in 0..100 {
                let op = list.insert(prev, i);
                prev = op.id;
            }
        })
    });
}

fn bench_insert_many_agents_conflicts(c: &mut Criterion) {
    c.bench_function("bench insert many agents conflicts", |b| {
        b.iter(|| {
            const N: u8 = 10;
            let mut rng = rand::rng();
            let mut crdts: Vec<ListCrdt<i64>> = Vec::with_capacity(N as usize);
            let mut logs: Vec<Op<JsonValue>> = Vec::new();
            for i in 0..N {
                let list = ListCrdt::new(make_author(i), vec![]);
                crdts.push(list);
                for _ in 0..5 {
                    let op = crdts[i as usize].insert(ROOT_ID, i as i32);
                    logs.push(op);
                }
            }

            logs.shuffle(&mut rng);
            for op in logs {
                for c in &mut crdts {
                    if op.author() != c.our_id {
                        c.apply(op.clone());
                    }
                }
            }

            assert!(crdts.windows(2).all(|w| w[0].view() == w[1].view()));
        })
    });
}

criterion_group!(
    benches,
    bench_insert_100_root,
    bench_insert_100_linear,
    bench_insert_many_agents_conflicts
);
criterion_main!(benches);
