use std::hint::black_box;

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

use sqpack_rs::tex::{Tex, TextureFormat, decompress_to_rgba8};

const BC1_FORMAT_RAW: u32 = 0x3420;

const BC1_BLOCK_BYTES: usize = 8;

fn build_bc1_512x512_tex() -> Vec<u8> {
    const WIDTH: usize = 512;
    const HEIGHT: usize = 512;
    const BLOCKS_W: usize = WIDTH.div_ceil(4);
    const BLOCKS_H: usize = HEIGHT.div_ceil(4);
    const SURFACE_BYTES: usize = BLOCKS_W * BLOCKS_H * BC1_BLOCK_BYTES;
    const HEADER_BYTES: usize = 80;
    #[allow(clippy::cast_possible_truncation)]
    const SURFACE_OFFSET: u32 = HEADER_BYTES as u32;

    let mut buf = vec![0u8; HEADER_BYTES + SURFACE_BYTES];

    let attribute: u32 = 0x0080_0000;
    buf[0..4].copy_from_slice(&attribute.to_le_bytes());
    buf[4..8].copy_from_slice(&BC1_FORMAT_RAW.to_le_bytes());
    let width_u16 = u16::try_from(WIDTH).expect("512 fits u16");
    buf[8..10].copy_from_slice(&width_u16.to_le_bytes());
    let height_u16 = u16::try_from(HEIGHT).expect("512 fits u16");
    buf[10..12].copy_from_slice(&height_u16.to_le_bytes());
    buf[12..14].copy_from_slice(&1u16.to_le_bytes());
    buf[14] = 1;
    buf[15] = 1;
    let surf_offset_field_start = 0x10 + 12;
    buf[surf_offset_field_start..surf_offset_field_start + 4]
        .copy_from_slice(&SURFACE_OFFSET.to_le_bytes());

    buf
}

fn build_bc1_512x512_surface_body() -> Vec<u8> {
    const WIDTH: usize = 512;
    const HEIGHT: usize = 512;
    const BLOCKS_W: usize = WIDTH.div_ceil(4);
    const BLOCKS_H: usize = HEIGHT.div_ceil(4);
    vec![0u8; BLOCKS_W * BLOCKS_H * BC1_BLOCK_BYTES]
}

fn bench_tex_parse(c: &mut Criterion) {
    let tex_bytes = build_bc1_512x512_tex();

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

    group.bench_function("bc1_512x512", |b| {
        b.iter(|| {
            let tex = Tex::parse(black_box(&tex_bytes)).expect("parse");
            black_box(tex);
        });
    });

    group.finish();
}

fn bench_tex_decompress(c: &mut Criterion) {
    let surface = build_bc1_512x512_surface_body();

    let mut group = c.benchmark_group("tex.decompress");

    group.bench_function("bc1_512x512_to_rgba8", |b| {
        b.iter(|| {
            let rgba =
                decompress_to_rgba8(black_box(TextureFormat::BC1), 512, 512, black_box(&surface))
                    .expect("decompress");
            black_box(rgba);
        });
    });

    group.finish();
}

criterion_group!(benches, bench_tex_parse, bench_tex_decompress);
criterion_main!(benches);
