//! Throughput of the streaming superkmer pipeline (`RollingStat`'s hot path:
//! minimizer selection + entropy tracking fused in a single pass).
//!
//! Reference point for the `obikentropy` extraction: the entropy bookkeeping
//! that used to live inline in `RollingStat` was pulled out into a composed
//! `EntropyTracker`. This benchmark is run before and after that change to
//! confirm no regression.

use criterion::{Criterion, Throughput, criterion_group, criterion_main};
use obikrope::Rope;
use obiskbuilder::SuperKmerIter;

const K: usize = 21;
const M: usize = 9;
const LEVEL_MAX: usize = 6;
const THETA: f64 = 0.7;
const SEQ_LEN: usize = 200_000;

/// Deterministic pseudo-random ACGT sequence — high enough complexity that
/// the entropy filter rarely rejects, so the bench stays on the steady-state
/// path rather than repeatedly resetting.
fn make_sequence(len: usize) -> Vec<u8> {
    let mut state: u64 = 0x9E3779B97F4A7C15;
    (0..len)
        .map(|_| {
            state ^= state << 13;
            state ^= state >> 7;
            state ^= state << 17;
            b"ACGT"[(state % 4) as usize]
        })
        .collect()
}

fn make_rope(seq: &[u8]) -> Rope {
    let mut rope = Rope::new(None);
    rope.push(seq.to_vec());
    rope
}

fn bench_build_superkmers(c: &mut Criterion) {
    obikseq::set_k(K);
    obikseq::set_m(M);

    let seq = make_sequence(SEQ_LEN);
    let rope = make_rope(&seq);

    let mut group = c.benchmark_group("build_superkmers");
    group.throughput(Throughput::Bytes(SEQ_LEN as u64));
    group.bench_function("stream", |b| {
        b.iter(|| {
            SuperKmerIter::new(std::hint::black_box(&rope), K, LEVEL_MAX, THETA).count()
        });
    });
    group.finish();
}

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