use criterion::{black_box, criterion_group, criterion_main, Criterion};
use fp_checker_core::{check_code, render_report, CheckerConfig, OutputFormat};
use std::fs;
use std::path::PathBuf;

fn fixture_path(relative: &str) -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("../../tests/fixtures")
        .join(relative)
}

fn sample_source() -> String {
    fs::read_to_string(fixture_path("sample_project/sample.py")).expect("sample fixture exists")
}

fn synthetic_large_source() -> String {
    let mut source = String::from("STATE = []\n\n");
    for index in 0..200 {
        source.push_str(&format!(
            "def f_{index}(items=[]):\n    for item in items:\n        print(item)\n    STATE.append({index})\n    return items\n\n"
        ));
    }
    source
}

fn benchmark_check_code(c: &mut Criterion) {
    let config = CheckerConfig::default();
    let sample = sample_source();
    let synthetic = synthetic_large_source();

    c.bench_function("check_code/sample_fixture", |b| {
        b.iter(|| check_code(black_box(&sample), "sample.py", black_box(&config)));
    });

    c.bench_function("check_code/synthetic_large", |b| {
        b.iter(|| check_code(black_box(&synthetic), "synthetic.py", black_box(&config)));
    });
}

fn benchmark_render(c: &mut Criterion) {
    let config = CheckerConfig::default();
    let report = check_code(&synthetic_large_source(), "synthetic.py", &config);

    c.bench_function("render_report/json", |b| {
        b.iter(|| render_report(black_box(&report), OutputFormat::Json).expect("json render"));
    });

    c.bench_function("render_report/sarif", |b| {
        b.iter(|| render_report(black_box(&report), OutputFormat::Sarif).expect("sarif render"));
    });
}

criterion_group!(benches, benchmark_check_code, benchmark_render);
criterion_main!(benches);
