//! Performance benchmarks for monge-rs.

use criterion::{black_box, criterion_group, criterion_main, Criterion};

use nalgebra::Vector2;
use monge_rs::geometry::Circle;
use monge_rs::homothetic::{
    external_homothetic_center, internal_homothetic_center, external_triple, monge_collinear_area,
};
use monge_rs::radical_axis::RadicalAxis;
use monge_rs::consensus::{zero_holonomy_area, Agent, simulate_consensus, consensus_step};
use monge_rs::p48::{all_48_directions, verify_all_pairs, verify_zero_drift, int_det, PRIMITIVE_TRIPLES};

fn bench_homothetic_center(c: &mut Criterion) {
    let c1 = Circle::new(Vector2::new(0.0, 0.0), 1.0);
    let c2 = Circle::new(Vector2::new(4.0, 0.0), 2.0);

    c.bench_function("external_homothetic_center", |b| {
        b.iter(|| external_homothetic_center(black_box(&c1), black_box(&c2)))
    });

    c.bench_function("internal_homothetic_center", |b| {
        b.iter(|| internal_homothetic_center(black_box(&c1), black_box(&c2)))
    });
}

fn bench_monge_theorem(c: &mut Criterion) {
    let c1 = Circle::new(Vector2::new(0.0, 0.0), 1.0);
    let c2 = Circle::new(Vector2::new(4.0, 0.0), 2.0);
    let c3 = Circle::new(Vector2::new(2.0, 3.0), 1.5);

    c.bench_function("external_triple", |b| {
        b.iter(|| external_triple(black_box(&c1), black_box(&c2), black_box(&c3)))
    });

    c.bench_function("monge_collinear_area", |b| {
        b.iter(|| monge_collinear_area(black_box(&c1), black_box(&c2), black_box(&c3)))
    });
}

fn bench_radical_axis(c: &mut Criterion) {
    let c1 = Circle::new(Vector2::new(0.0, 0.0), 1.0);
    let c2 = Circle::new(Vector2::new(4.0, 0.0), 2.0);

    c.bench_function("radical_axis_new", |b| {
        b.iter(|| RadicalAxis::new(black_box(&c1), black_box(&c2)))
    });

    let pt = Vector2::new(1.625, 0.0);
    let axis = RadicalAxis::new(&c1, &c2);
    c.bench_function("radical_axis_eval", |b| {
        b.iter(|| axis.eval(black_box(&pt)))
    });
}

fn bench_consensus(c: &mut Criterion) {
    let agents = [
        Agent::new(Vector2::new(0.0, 0.0), 1.0),
        Agent::new(Vector2::new(4.0, 0.0), 2.0),
        Agent::new(Vector2::new(2.0, 3.0), 1.5),
    ];

    c.bench_function("zero_holonomy_area", |b| {
        b.iter(|| zero_holonomy_area(black_box(&agents)))
    });

    c.bench_function("consensus_step", |b| {
        b.iter(|| consensus_step(black_box(&agents), 0.1))
    });

    c.bench_function("simulate_consensus_100", |b| {
        b.iter(|| simulate_consensus(black_box(&agents), 100, 0.1))
    });
}

fn bench_p48(c: &mut Criterion) {
    c.bench_function("p48_all_directions", |b| {
        b.iter(all_48_directions)
    });

    let dirs = all_48_directions();
    c.bench_function("p48_int_det_pair", |b| {
        b.iter(|| int_det(black_box(&dirs[0]), black_box(&dirs[1])))
    });

    c.bench_function("p48_verify_all_pairs", |b| {
        b.iter(verify_all_pairs)
    });

    c.bench_function("p48_verify_zero_drift", |b| {
        b.iter(verify_zero_drift)
    });
}

criterion_group!(
    benches,
    bench_homothetic_center,
    bench_monge_theorem,
    bench_radical_axis,
    bench_consensus,
    bench_p48,
);
criterion_main!(benches);
