// SPDX-License-Identifier: AGPL-3.0-or-later
//! Benchmarks for implementations of the [Block] trait.
//! You can run these with `cargo bench`.

use std::{fs::OpenOptions, io::Write, time::Duration};

use btlib::{
    crypto::{ConcreteCreds, Creds},
    BlockOpenOptions, BlockPath, Epoch, Principaled, SECTOR_SZ_DEFAULT,
};
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use tempdir::TempDir;

fn block_write(c: &mut Criterion) {
    let temp_dir = TempDir::new("block_bench").expect("failed to create temp dir");
    let root_creds = ConcreteCreds::generate().expect("failed to generate root_creds");
    let mut node_creds = ConcreteCreds::generate().expect("failed to generate node_creds");
    let components = ["nodes", "phone"];
    let writecap = root_creds
        .issue_writecap(
            node_creds.principal(),
            &mut components.into_iter(),
            Epoch::now() + Duration::from_secs(3600),
        )
        .expect("failed to issue writecap");
    node_creds.set_writecap(writecap).unwrap();

    let mut fs_path = temp_dir.path().to_owned();
    fs_path.extend(components.iter());
    std::fs::create_dir_all(&fs_path).expect("failed to create fs_path");

    let node_path = BlockPath::from_components(root_creds.principal(), components.into_iter());
    let file_path = fs_path.join("file.txt");

    c.bench_function("block_write", |b| {
        b.iter(|| {
            let file = OpenOptions::new()
                .create(true)
                .truncate(true)
                .read(true)
                .write(true)
                .open(&file_path)
                .expect("failed to open file");
            let mut block = BlockOpenOptions::new()
                .with_inner(file)
                .with_creds(node_creds.clone())
                .with_encrypt(true)
                .with_block_path(node_path.clone())
                .open()
                .expect("failed to open block");

            const ZEROS: [u8; SECTOR_SZ_DEFAULT] = [0u8; SECTOR_SZ_DEFAULT];
            const ITER: usize = (512 * 1024) / ZEROS.len();
            for zeros in std::iter::repeat(ZEROS.as_slice()).take(ITER) {
                block.write(black_box(zeros)).expect("write failed");
            }
        })
    });
}

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