//! Determinism fence: the encoder is contractually bit-exact on the
//! same input, and the decoder is contractually bit-exact on the same
//! bitstream. This file exists to catch a future change that would
//! quietly break either property — a parallel order search with a
//! race, a `HashMap` iteration order leaking into state, a
//! non-deterministic tie-break. All three would pass the round-trip
//! tests but fail here.
//!
//! Tests drive small deterministic inputs (LFSR noise, sine) so they
//! don't depend on corpus presence and run in milliseconds.

use lac::{decode_frame, encode_frame};

// ── Deterministic inputs ────────────────────────────────────────────────────

/// 32-bit Galois LFSR, mirrored from `tests/synthetic.rs`. Seeded
/// deterministically so repeated calls with the same `seed` produce
/// bit-identical outputs, which is the property we rely on below.
fn lfsr_noise(n: usize, bit_depth: u8, seed: u32) -> Vec<i32> {
    assert!((1..=24).contains(&bit_depth));
    let mut state = if seed == 0 { 0xACE1_ACE1 } else { seed };
    let shift = 32 - bit_depth as u32;
    let max: i32 = (1i32 << (bit_depth - 1)) - 1;
    (0..n)
        .map(|_| {
            let lsb = state & 1;
            state >>= 1;
            if lsb != 0 {
                state ^= 0x8020_0003;
            }
            ((state as i32) >> shift).max(-max)
        })
        .collect()
}

// ── Tests ───────────────────────────────────────────────────────────────────

#[test]
fn encode_byte_equal_on_same_input_silence() {
    let samples = vec![0i32; 4096];
    let a = encode_frame(&samples);
    let b = encode_frame(&samples);
    assert_eq!(a, b, "encoder produced different bytes for identical input");
}

#[test]
fn encode_byte_equal_on_same_input_noise() {
    // 16-bit noise — exercises the non-trivial LPC/Rice search path
    // where any latent non-determinism (tie-break, parallelism, hash
    // ordering) would be most likely to surface.
    let samples = lfsr_noise(4096, 16, 0xDEAD);
    let a = encode_frame(&samples);
    let b = encode_frame(&samples);
    assert_eq!(
        a,
        b,
        "encoder produced different bytes on a noisy input (first {} bytes)",
        a.len().min(16)
    );
}

#[test]
fn encode_byte_equal_on_same_input_24bit_full_scale() {
    // Full-scale content stresses the autocorrelation accumulator
    // width; any non-determinism in coefficient quantization would
    // show up differently from the silence and noise cases.
    let samples = vec![(1 << 23) - 1; 2048];
    let a = encode_frame(&samples);
    let b = encode_frame(&samples);
    assert_eq!(a, b);
}

#[test]
fn encode_byte_equal_across_many_repeats() {
    // Ten encodes of the same input — catches an intermittent race
    // that a two-shot comparison might miss by luck. LFSR seed chosen
    // independently from the other tests to reduce correlation
    // between failure modes.
    let samples = lfsr_noise(2048, 20, 0xBEEF);
    let reference = encode_frame(&samples);
    for i in 1..10 {
        let current = encode_frame(&samples);
        assert_eq!(
            current, reference,
            "encode #{} differs from the reference encode",
            i
        );
    }
}

#[test]
fn decode_byte_equal_on_same_input() {
    // Decoder determinism: same bitstream, same samples, every time.
    let samples = lfsr_noise(2048, 16, 0xF00D);
    let bytes = encode_frame(&samples);
    let a = decode_frame(&bytes).expect("decode a");
    let b = decode_frame(&bytes).expect("decode b");
    assert_eq!(
        a, b,
        "decoder produced different samples for identical bytes"
    );
    assert_eq!(a, samples, "decoder output doesn't match original samples");
}
