use std::hint::black_box;

use codspeed_criterion_compat::{Criterion, criterion_group, criterion_main};

use sqpack_rs::mdl::Mdl;
use sqpack_rs::mdl::{
    LOD_SIZE, MODEL_FILE_HEADER_SIZE, MODEL_HEADER_SIZE, VERTEX_DECLARATION_SLOT_BYTES,
    VERTEX_ELEMENT_SLOTS,
};

const BOUNDING_BOX_BYTES: usize = 32;

fn build_minimal_mdl() -> Vec<u8> {
    let mut buf = Vec::new();

    buf.extend_from_slice(&1u32.to_le_bytes());
    buf.extend_from_slice(&0u32.to_le_bytes());
    buf.extend_from_slice(&0u32.to_le_bytes());
    buf.extend_from_slice(&1u16.to_le_bytes());
    buf.extend_from_slice(&0u16.to_le_bytes());
    for _ in 0..3 {
        buf.extend_from_slice(&0u32.to_le_bytes());
    }
    for _ in 0..3 {
        buf.extend_from_slice(&0u32.to_le_bytes());
    }
    for _ in 0..3 {
        buf.extend_from_slice(&0u32.to_le_bytes());
    }
    for _ in 0..3 {
        buf.extend_from_slice(&0u32.to_le_bytes());
    }
    buf.push(1);
    buf.push(0);
    buf.push(0);
    buf.push(0);
    assert_eq!(buf.len(), MODEL_FILE_HEADER_SIZE);

    buf.push(0xFF);
    buf.extend_from_slice(&[0; 7]);
    for _ in 1..VERTEX_ELEMENT_SLOTS {
        buf.extend_from_slice(&[0u8; 8]);
    }
    assert_eq!(
        buf.len(),
        MODEL_FILE_HEADER_SIZE + VERTEX_DECLARATION_SLOT_BYTES
    );

    buf.extend_from_slice(&0u16.to_le_bytes());
    buf.extend_from_slice(&0u16.to_le_bytes());
    buf.extend_from_slice(&0u32.to_le_bytes());

    buf.extend_from_slice(&0f32.to_le_bytes());
    for _ in 0..9 {
        buf.extend_from_slice(&0u16.to_le_bytes());
    }
    buf.push(1);
    buf.push(0);
    buf.extend_from_slice(&0u16.to_le_bytes());
    buf.push(0);
    buf.push(0);
    buf.extend_from_slice(&0f32.to_le_bytes());
    buf.extend_from_slice(&0f32.to_le_bytes());
    buf.extend_from_slice(&0u16.to_le_bytes());
    buf.extend_from_slice(&0u16.to_le_bytes());
    buf.push(0);
    buf.push(0);
    buf.push(0);
    buf.push(0);
    buf.extend_from_slice(&0u16.to_le_bytes());
    buf.extend_from_slice(&0u16.to_le_bytes());
    buf.extend_from_slice(&0u16.to_le_bytes());
    buf.extend_from_slice(&[0u8; 6]);
    assert_eq!(
        buf.len(),
        MODEL_FILE_HEADER_SIZE + VERTEX_DECLARATION_SLOT_BYTES + 8 + MODEL_HEADER_SIZE
    );

    for _ in 0..3 {
        buf.extend_from_slice(&[0u8; LOD_SIZE]);
    }

    buf.extend_from_slice(&0u32.to_le_bytes());
    buf.push(0);

    for _ in 0..4 {
        buf.extend_from_slice(&[0u8; BOUNDING_BOX_BYTES]);
    }

    buf
}

fn bench_mdl_parse(c: &mut Criterion) {
    let mdl_bytes = build_minimal_mdl();

    let mut group = c.benchmark_group("mdl.parse");

    group.bench_function("minimal_mdl", |b| {
        b.iter(|| {
            let mdl = Mdl::parse(black_box(&mdl_bytes)).expect("parse");
            black_box(mdl);
        });
    });

    group.finish();
}

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