//! Story 1.5 comparative benchmark: nalgebra vs faer dense LU backends.
//!
//! Measures factorization (`set_linearisation`) and per-RHS solve
//! (`solve_in_place`) on the mock-cycle Jacobian (9×9) and a synthetic 50×50
//! dense Jacobian — the sizes Entropyk Newton actually sees.

use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
use entropyk_solver::linear::NalgebraLuSolver;
use entropyk_solver::linear_faer::FaerLuSolver;
use entropyk_solver::LinearSolver;

mod common;

fn dense_entries(n: usize) -> Vec<(usize, usize, f64)> {
    let mut entries = Vec::with_capacity(n * n);
    for i in 0..n {
        for j in 0..n {
            let v = if i == j {
                4.0 + 0.01 * (i as f64)
            } else {
                1.0 / (1.0 + (i as f64 - j as f64).abs())
            };
            entries.push((i, j, v));
        }
    }
    entries
}

fn bench_pair(c: &mut Criterion, label: &str, entries: &[(usize, usize, f64)], n: usize) {
    let mut group = c.benchmark_group(label);
    let rhs: Vec<f64> = (0..n)
        .map(|i| (i as f64 * 0.7 - 1.3).sin() * 100.0)
        .collect();

    let mut nal = NalgebraLuSolver::new();
    nal.set_problem(n, n).unwrap();
    let mut faer = FaerLuSolver::new();
    faer.set_problem(n, n).unwrap();

    group.bench_function(BenchmarkId::new("factor", "nalgebra"), |b| {
        b.iter(|| {
            black_box(nal.set_linearisation(black_box(entries))).unwrap();
        });
    });
    group.bench_function(BenchmarkId::new("factor", "faer"), |b| {
        b.iter(|| {
            black_box(faer.set_linearisation(black_box(entries))).unwrap();
        });
    });

    nal.set_linearisation(entries).unwrap();
    faer.set_linearisation(entries).unwrap();
    group.bench_function(BenchmarkId::new("solve", "nalgebra"), |b| {
        b.iter(|| {
            let mut rhs = rhs.clone();
            let _ = black_box(nal.solve_in_place(black_box(&mut rhs)));
        });
    });
    group.bench_function(BenchmarkId::new("solve", "faer"), |b| {
        b.iter(|| {
            let mut rhs = rhs.clone();
            let _ = black_box(faer.solve_in_place(black_box(&mut rhs)));
        });
    });
    group.finish();
}

fn bench_lu_backends(c: &mut Criterion) {
    let (system, state) = common::build_mock_system();
    let jacobian = common::assemble_jacobian(&system, &state);
    let n = jacobian.nrows();
    let jm = jacobian.as_matrix();
    let entries: Vec<(usize, usize, f64)> = (0..n)
        .flat_map(|i| (0..n).map(move |j| (i, j, jm[(i, j)])))
        .collect();
    bench_pair(c, "lu_mock_9x9", &entries, n);

    let entries50 = dense_entries(50);
    bench_pair(c, "lu_dense_50x50", &entries50, 50);

    let _ = state;
}

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