use std::sync::Arc;

use codspeed_criterion_compat::{BenchmarkId, Criterion, criterion_group, criterion_main};
use std::hint::black_box;

use sqpack_rs::Platform;
use sqpack_rs::vfs::InMemoryFs;
use sqpack_rs::write::SqPackAppender;

mod common;

const SQPACK_HEADER_SIZE: u32 = 1024;

fn make_install_inmem() -> InMemoryFs {
    let fs = InMemoryFs::new();
    fs.insert(
        "/install/sqpack/ffxiv/0a0000.win32.index",
        common::make_index_file(&[]),
    );
    fs.insert(
        "/install/sqpack/ffxiv/0a0000.win32.index2",
        common::make_index2_file(&[]),
    );
    let mut dat = common::make_sqpack_header(1);
    dat.resize(SQPACK_HEADER_SIZE as usize, 0);
    fs.insert("/install/sqpack/ffxiv/0a0000.win32.dat0", dat);
    fs
}

fn make_appender(fs: &InMemoryFs) -> SqPackAppender {
    let fs_arc: Arc<InMemoryFs> = Arc::new(fs.clone());
    SqPackAppender::open_with_vfs(
        "/install",
        Platform::Win32,
        fs_arc.clone() as Arc<dyn sqpack_rs::Vfs>,
        fs_arc as Arc<dyn sqpack_rs::vfs::VfsWrite>,
    )
    .expect("open_with_vfs")
}

fn bench_append(c: &mut Criterion) {
    let mut group = c.benchmark_group("append");
    let cases: &[(&str, usize)] = &[
        ("tiny_64B", 64),
        ("medium_100KiB", 100 * 1024),
        ("large_1MiB", 1024 * 1024),
    ];
    for &(label, size) in cases {
        let payload = common::build_compressible_payload(size);
        group.throughput(codspeed_criterion_compat::Throughput::Bytes(size as u64));
        group.bench_with_input(
            BenchmarkId::from_parameter(label),
            &payload,
            |b, payload| {
                b.iter(|| {
                    let fs = make_install_inmem();
                    let mut writer = make_appender(&fs);
                    let outcome = writer
                        .append("exd/bench.exd", black_box(payload))
                        .expect("append");
                    writer.commit().expect("commit");
                    black_box(outcome);
                });
            },
        );
    }
    group.finish();
}

criterion_group!(append_benches, bench_append);
criterion_main!(append_benches);
