use std::{
    fs::{self, File},
    path::Path,
};

use criterion::{Criterion, black_box, criterion_group, criterion_main};
use tici_common::cdc_file_name::CDC_FILENAME_MATCH;
use tici_shard::writer::cdc_log::CDCLog;
use zip::ZipArchive;

fn prepare_data(zip_path: &str) -> Vec<String> {
    let zip_path = Path::new(zip_path);
    let parent_dir = zip_path.parent().unwrap_or_else(|| Path::new("."));
    let file = File::open(zip_path).unwrap();
    let mut archive = ZipArchive::new(file).unwrap();

    {
        assert!(!archive.is_empty());
        let file = archive.by_index(0).unwrap();
        let target_dir = parent_dir.join(file.mangled_name());
        assert!(file.is_dir());
        fs::create_dir_all(&target_dir).unwrap();
    }

    let mut paths = Vec::new();
    let len = archive.len();
    for i in 1..len {
        let mut file = archive.by_index(i).unwrap();
        let outpath = parent_dir.join(file.mangled_name());
        if file.is_dir() {
            fs::create_dir_all(&outpath).unwrap();
        } else {
            if let Some(p) = outpath.parent() {
                if !p.exists() {
                    fs::create_dir_all(p).unwrap();
                }
            }
            let mut outfile = File::create(&outpath).unwrap();
            std::io::copy(&mut file, &mut outfile).unwrap();
            paths.push(outpath.to_string_lossy().to_string());
        }
    }
    paths
}

fn bench_parse_cdc_log(c: &mut Criterion) {
    let paths = prepare_data("../../ci/cdc_test_data.zip");
    let datas: Vec<String> = paths
        .iter()
        .filter(|path| CDC_FILENAME_MATCH.is_match(path))
        .map(|path| fs::read_to_string(path).unwrap())
        .collect();
    c.bench_function("CDCLog parse", |b| {
        b.iter(|| {
            for data in datas.iter() {
                for line in data.lines() {
                    let trimmed = line.trim();
                    if trimmed.is_empty() {
                        continue;
                    }

                    let entry = black_box(CDCLog::new(black_box(trimmed))).unwrap();

                    black_box(entry);
                }
            }
        })
    });
}

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