//! End-to-End Routing Latency Benchmark
//!
//! Measures complete request flow:
//! - Client request → Auth pipeline → Backend proxy → Response
//! - TARGET: <10μs total overhead (auth + proxying)
//!
//! Tests:
//! 1. Auth overhead only (mock backend)
//! 2. Proxy overhead only (no auth)
//! 3. Full end-to-end (auth + proxy)
//! 4. Different request sizes
//! 5. Concurrent requests

use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::runtime::Runtime;

/// Mock backend service that responds immediately
struct MockBackend {
    response_time_ns: u64,
}

impl MockBackend {
    fn new(response_time_ns: u64) -> Self {
        Self { response_time_ns }
    }

    async fn handle_request(&self, _request: &[u8]) -> Vec<u8> {
        // Simulate backend processing time
        if self.response_time_ns > 0 {
            tokio::time::sleep(Duration::from_nanos(self.response_time_ns)).await;
        }
        b"response_data".to_vec()
    }
}

/// Mock auth layer
struct MockAuthLayer {
    overhead_ns: u64,
}

impl MockAuthLayer {
    fn new(overhead_ns: u64) -> Self {
        Self { overhead_ns }
    }

    async fn authenticate(&self, _token: &str) -> bool {
        // Simulate auth overhead
        if self.overhead_ns > 0 {
            tokio::time::sleep(Duration::from_nanos(self.overhead_ns)).await;
        }
        true
    }
}

/// Request router
struct Router {
    auth: Arc<MockAuthLayer>,
    backend: Arc<MockBackend>,
}

impl Router {
    fn new(auth_overhead_ns: u64, backend_response_ns: u64) -> Self {
        Self {
            auth: Arc::new(MockAuthLayer::new(auth_overhead_ns)),
            backend: Arc::new(MockBackend::new(backend_response_ns)),
        }
    }

    async fn route_request(&self, token: &str, request: &[u8]) -> Option<Vec<u8>> {
        // Authenticate
        if !self.auth.authenticate(token).await {
            return None;
        }

        // Forward to backend
        Some(self.backend.handle_request(request).await)
    }
}

/// Benchmark 1: Auth overhead only (backend responds instantly)
fn bench_auth_only_overhead(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let router = Router::new(5_000, 0); // 5μs auth, instant backend

    c.bench_function("auth_overhead_only", |b| {
        b.iter(|| {
            rt.block_on(async {
                let result = router
                    .route_request(black_box("valid-jwt-token"), black_box(b"request"))
                    .await;
                black_box(result);
            });
        });
    });
}

/// Benchmark 2: Proxy overhead only (no auth)
fn bench_proxy_only_overhead(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let router = Router::new(0, 0); // No auth, instant backend

    c.bench_function("proxy_overhead_only", |b| {
        b.iter(|| {
            rt.block_on(async {
                let result = router
                    .route_request(black_box("valid-jwt-token"), black_box(b"request"))
                    .await;
                black_box(result);
            });
        });
    });
}

/// Benchmark 3: Full end-to-end with realistic backend
fn bench_end_to_end_realistic(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    // 8μs auth + 100μs backend (simulates actual service)
    let router = Router::new(8_000, 100_000);

    c.bench_function("end_to_end_realistic_backend", |b| {
        b.iter(|| {
            rt.block_on(async {
                let result = router
                    .route_request(black_box("valid-jwt-token"), black_box(b"request"))
                    .await;
                black_box(result);
            });
        });
    });
}

/// Benchmark 4: Target performance (10μs total overhead)
fn bench_target_performance(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    // 8μs auth + instant backend = <10μs total
    let router = Router::new(8_000, 0);

    c.bench_function("target_10us_overhead", |b| {
        b.iter(|| {
            rt.block_on(async {
                let result = router
                    .route_request(black_box("valid-jwt-token"), black_box(b"request"))
                    .await;
                black_box(result);
            });
        });
    });
}

/// Benchmark 5: Different request sizes
fn bench_request_sizes(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let router = Router::new(8_000, 0); // 8μs auth overhead

    let mut group = c.benchmark_group("request_size_impact");

    for size in &[100, 1_000, 10_000, 100_000] {
        let request = vec![0u8; *size];

        group.bench_with_input(
            BenchmarkId::new("request_routing", format!("{}B", size)),
            &request,
            |b, req| {
                b.iter(|| {
                    rt.block_on(async {
                        let result = router
                            .route_request("valid-jwt-token", black_box(req))
                            .await;
                        black_box(result);
                    });
                });
            },
        );
    }

    group.finish();
}

/// Benchmark 6: Concurrent request handling
fn bench_concurrent_requests(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let router = Arc::new(Router::new(8_000, 0));

    let mut group = c.benchmark_group("concurrent_requests");

    for concurrency in &[1, 10, 100] {
        group.bench_with_input(
            BenchmarkId::new("parallel_routing", concurrency),
            concurrency,
            |b, &n| {
                b.iter(|| {
                    rt.block_on(async {
                        let mut handles = vec![];
                        let router_clone = router.clone();

                        for _ in 0..n {
                            let router_ref = router_clone.clone();
                            let handle = tokio::spawn(async move {
                                router_ref
                                    .route_request("valid-jwt-token", b"request")
                                    .await
                            });
                            handles.push(handle);
                        }

                        for handle in handles {
                            black_box(handle.await.unwrap());
                        }
                    });
                });
            },
        );
    }

    group.finish();
}

/// Benchmark 7: Failed auth fast-path
fn bench_auth_failure_fast_path(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();

    // Custom router that fails auth immediately
    struct FastFailRouter {
        auth_overhead_ns: u64,
    }

    impl FastFailRouter {
        async fn route_request(&self, token: &str, _request: &[u8]) -> Option<Vec<u8>> {
            if self.auth_overhead_ns > 0 {
                tokio::time::sleep(Duration::from_nanos(self.auth_overhead_ns)).await;
            }

            // Simulate quick rejection (invalid JWT signature)
            if token.len() < 10 {
                return None;
            }
            None
        }
    }

    let router = FastFailRouter {
        auth_overhead_ns: 100, // 100ns for quick rejection
    };

    c.bench_function("auth_failure_fast_path", |b| {
        b.iter(|| {
            rt.block_on(async {
                let result = router
                    .route_request(black_box("invalid"), black_box(b"request"))
                    .await;
                black_box(result);
            });
        });
    });
}

/// Benchmark 8: Latency percentiles measurement
fn bench_latency_percentiles(c: &mut Criterion) {
    let rt = Runtime::new().unwrap();
    let router = Router::new(8_000, 0);

    c.bench_function("latency_distribution", |b| {
        b.iter_custom(|iters| {
            let mut total = Duration::ZERO;

            for _ in 0..iters {
                let start = Instant::now();
                rt.block_on(async {
                    let result = router.route_request("valid-jwt-token", b"request").await;
                    black_box(result);
                });
                total += start.elapsed();
            }

            total
        });
    });
}

criterion_group!(
    routing_benches,
    bench_auth_only_overhead,
    bench_proxy_only_overhead,
    bench_end_to_end_realistic,
    bench_target_performance,
    bench_request_sizes,
    bench_concurrent_requests,
    bench_auth_failure_fast_path,
    bench_latency_percentiles
);

criterion_main!(routing_benches);
