//! Benchmarks for spatial query performance

use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
use geographdb_core::spatial::simd::distance_filter_l2;
use geographdb_core::spatial::{BoundingBox, Octree};
use geographdb_core::storage::NodePoint;
use glam::Vec3;

fn benchmark_simd_distance_filter(c: &mut Criterion) {
    let mut group = c.benchmark_group("simd_distance_filter");

    for size in [100, 1000, 10000, 100000].iter() {
        // Generate random points
        let points: Vec<(f32, f32, f32)> = (0..*size)
            .map(|i| {
                let x = (i as f32 * 0.1) % 100.0;
                let y = (i as f32 * 0.2) % 100.0;
                let z = (i as f32 * 0.3) % 100.0;
                (x, y, z)
            })
            .collect();

        let center = (50.0, 50.0, 50.0);
        let radius_sq = 2500.0; // 50^2

        group.bench_with_input(BenchmarkId::from_parameter(size), &points, |b, points| {
            b.iter(|| {
                distance_filter_l2(black_box(points), black_box(center), black_box(radius_sq))
            });
        });
    }

    group.finish();
}

fn benchmark_knn_query(c: &mut Criterion) {
    let mut group = c.benchmark_group("knn_query");

    for (node_count, k) in [(1000, 10), (10000, 10), (10000, 100)].iter() {
        // Build octree with nodes
        let bounds = BoundingBox::new(
            Vec3::new(-500.0, -500.0, -500.0),
            Vec3::new(500.0, 500.0, 500.0),
        );
        let mut octree = Octree::new(bounds);

        for i in 0..*node_count {
            let node = NodePoint {
                id: i as u64,
                x: (i as f32 * 0.5) % 1000.0 - 500.0,
                y: (i as f32 * 0.3) % 1000.0 - 500.0,
                z: (i as f32 * 0.7) % 1000.0 - 500.0,
            };
            octree.insert(node);
        }

        let query_center = Vec3::new(0.0, 0.0, 0.0);
        let label = format!("nodes={}_k={}", node_count, k);

        group.bench_with_input(
            BenchmarkId::new("octree_knn", label),
            &(&octree, *k),
            |b, (octree, k)| {
                b.iter(|| octree.query_knn(black_box(query_center), black_box(*k)));
            },
        );
    }

    group.finish();
}

criterion_group!(benches, benchmark_simd_distance_filter, benchmark_knn_query);
criterion_main!(benches);
