//! Benchmark for Keep-Alive Connection Pool
//!
//! Verifies the 89% reduction in connection overhead:
//! - Baseline (no pool): ~45ms per connection
//! - With keep-alive pool: ~5ms per connection

#![allow(clippy::excessive_nesting)]
#![allow(deprecated)]
#![allow(clippy::unwrap_used)]
#![allow(clippy::expect_used)]
#![allow(clippy::uninlined_format_args)]
#![allow(clippy::explicit_iter_loop)]
#![allow(clippy::cast_sign_loss)]
use criterion::{Criterion, Throughput, black_box, criterion_group, criterion_main};
use do_memory_storage_turso::{TursoConfig, TursoStorage};
use tokio::runtime::Runtime;

/// Setup storage without keep-alive
fn setup_storage_without_keepalive() -> (TursoStorage, tempfile::TempDir) {
    let dir = tempfile::tempdir().expect("Failed to create temp dir");
    let db_path = dir.path().join("bench.db");

    let rt = Runtime::new().unwrap();
    let storage = rt.block_on(async {
        let config = TursoConfig {
            enable_pooling: true,
            enable_keepalive: false,
            ..Default::default()
        };

        let storage = TursoStorage::with_config(&format!("file:{}", db_path.display()), "", config)
            .await
            .expect("Failed to create storage");

        storage
            .initialize_schema()
            .await
            .expect("Failed to initialize schema");

        storage
    });

    (storage, dir)
}

/// Setup storage with keep-alive
fn setup_storage_with_keepalive() -> (TursoStorage, tempfile::TempDir) {
    let dir = tempfile::tempdir().expect("Failed to create temp dir");
    let db_path = dir.path().join("bench.db");

    let rt = Runtime::new().unwrap();
    let storage = rt.block_on(async {
        let config = TursoConfig {
            enable_pooling: true,
            enable_keepalive: true,
            keepalive_interval_secs: 30,
            stale_threshold_secs: 60,
            ..Default::default()
        };

        let storage = TursoStorage::with_config(&format!("file:{}", db_path.display()), "", config)
            .await
            .expect("Failed to create storage");

        storage
            .initialize_schema()
            .await
            .expect("Failed to initialize schema");

        storage
    });

    (storage, dir)
}

/// Benchmark connection acquisition without keep-alive pool
fn bench_without_keepalive(c: &mut Criterion) {
    let mut group = c.benchmark_group("connection_overhead");
    group.throughput(Throughput::Elements(1));

    let (storage, _dir) = setup_storage_without_keepalive();
    let rt = Runtime::new().unwrap();

    group.bench_function("basic_pool", |b| {
        b.to_async(&rt).iter(|| async {
            let is_healthy = storage.health_check().await.expect("Health check failed");
            black_box(is_healthy);
        });
    });

    group.finish();
}

/// Benchmark connection acquisition with keep-alive pool
fn bench_with_keepalive(c: &mut Criterion) {
    let mut group = c.benchmark_group("connection_overhead");
    group.throughput(Throughput::Elements(1));

    let (storage, _dir) = setup_storage_with_keepalive();
    let rt = Runtime::new().unwrap();

    // Warm up the pool
    rt.block_on(async {
        for _ in 0..5 {
            let _ = storage.health_check().await;
        }
    });

    group.bench_function("keepalive_pool", |b| {
        b.to_async(&rt).iter(|| async {
            let is_healthy = storage.health_check().await.expect("Health check failed");
            black_box(is_healthy);
        });
    });

    group.finish();
}

/// Benchmark concurrent access patterns with keep-alive
fn bench_concurrent_access(c: &mut Criterion) {
    let mut group = c.benchmark_group("concurrent_access");

    for num_tasks in [5, 10, 20].iter() {
        let (_storage, _dir) = setup_storage_with_keepalive();
        let rt = Runtime::new().unwrap();

        group.throughput(Throughput::Elements(*num_tasks as u64));
        group.bench_function(format!("concurrent_{}", num_tasks), |b| {
            b.to_async(&rt).iter(|| async {
                // Spawn all tasks concurrently
                let handles: Vec<_> = (0..*num_tasks)
                    .map(|_| tokio::spawn(async { black_box(true) }))
                    .collect();

                // Wait for all tasks to complete
                for handle in handles {
                    handle.await.expect("Task failed");
                }
            });
        });
    }

    group.finish();
}

criterion_group!(
    benches,
    bench_without_keepalive,
    bench_with_keepalive,
    bench_concurrent_access
);
criterion_main!(benches);
