#![allow(
    dead_code,
    unused_variables,
    clippy::unnecessary_cast
)]
//! Trading Service Order Matching Latency Benchmarks
//!
//! Measures critical path latencies for order matching and execution:
//! - Order validation: <1μs target
//! - Order matching: <50μs target
//! - Position updates: <20μs target
//! - Risk checks: <20μs target
//! - Full order lifecycle: <100μs target
//!
//! Uses HDR histograms for accurate percentile measurements (P50, P95, P99, P99.9)

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

// Trading engine imports
use common::{OrderSide, OrderType};
use rust_decimal::Decimal;
use std::collections::HashMap;

/// Latency metrics collector with HDR histogram
struct LatencyMetrics {
    histogram: Histogram<u64>,
    samples: Vec<u64>,
}

impl LatencyMetrics {
    fn new() -> Self {
        Self {
            histogram: Histogram::<u64>::new(5).unwrap(), // 5 significant digits
            samples: Vec::new(),
        }
    }

    fn record_nanos(&mut self, nanos: u64) {
        self.histogram.record(nanos / 1000).ok(); // Record in microseconds
        self.samples.push(nanos);
    }

    fn report(&self, label: &str, target_us: f64) {
        let p50 = self.histogram.value_at_percentile(50.0) as f64;
        let p95 = self.histogram.value_at_percentile(95.0) as f64;
        let p99 = self.histogram.value_at_percentile(99.0) as f64;
        let p999 = self.histogram.value_at_percentile(99.9) as f64;
        let max = self.histogram.max() as f64;
        let mean = self.histogram.mean();

        println!("\n=== {} ===", label);
        println!("Samples: {}", self.samples.len());
        println!("Latency (μs):");
        println!("  P50:   {:.3}μs", p50);
        println!("  P95:   {:.3}μs", p95);
        println!("  P99:   {:.3}μs", p99);
        println!("  P999:  {:.3}μs", p999);
        println!("  Max:   {:.3}μs", max);
        println!("  Mean:  {:.3}μs", mean);

        if p99 < target_us {
            println!("✅ TARGET MET: P99 {:.3}μs < {:.1}μs", p99, target_us);
        } else {
            println!("❌ TARGET MISSED: P99 {:.3}μs >= {:.1}μs", p99, target_us);
        }
    }
}

/// Simulated order structure
#[derive(Clone)]
struct TestOrder {
    id: u64,
    symbol: String,
    side: OrderSide,
    order_type: OrderType,
    quantity: Decimal,
    price: Decimal,
}

impl TestOrder {
    fn new(id: u64) -> Self {
        Self {
            id,
            symbol: "BTC-USD".to_string(),
            side: if id % 2 == 0 {
                OrderSide::Buy
            } else {
                OrderSide::Sell
            },
            order_type: OrderType::Limit,
            quantity: Decimal::new(1, 2), // 0.01 BTC
            price: Decimal::new(65000, 0),
        }
    }
}

/// Simulated order book for matching
struct OrderBook {
    bids: Vec<(Decimal, Decimal)>, // (price, quantity)
    asks: Vec<(Decimal, Decimal)>,
}

impl OrderBook {
    fn new() -> Self {
        let mut bids = Vec::new();
        let mut asks = Vec::new();

        // Create realistic order book
        for i in 0..10 {
            bids.push((Decimal::new(64900 - i * 10, 0), Decimal::new(1, 1)));
            asks.push((Decimal::new(65100 + i * 10, 0), Decimal::new(1, 1)));
        }

        Self { bids, asks }
    }

    fn match_order(&self, order: &TestOrder) -> Option<Decimal> {
        match order.side {
            OrderSide::Buy => {
                // Check if we can match with best ask
                if let Some((ask_price, _)) = self.asks.first() {
                    if order.price >= *ask_price {
                        return Some(*ask_price);
                    }
                }
            },
            OrderSide::Sell => {
                // Check if we can match with best bid
                if let Some((bid_price, _)) = self.bids.first() {
                    if order.price <= *bid_price {
                        return Some(*bid_price);
                    }
                }
            },
        }
        None
    }
}

/// Simulated position manager
struct PositionManager {
    positions: HashMap<String, Decimal>,
}

impl PositionManager {
    fn new() -> Self {
        Self {
            positions: HashMap::new(),
        }
    }

    fn update_position(&mut self, symbol: &str, quantity: Decimal, side: OrderSide) {
        let delta = match side {
            OrderSide::Buy => quantity,
            OrderSide::Sell => -quantity,
        };

        *self
            .positions
            .entry(symbol.to_string())
            .or_insert(Decimal::ZERO) += delta;
    }

    fn get_position(&self, symbol: &str) -> Decimal {
        self.positions.get(symbol).copied().unwrap_or(Decimal::ZERO)
    }
}

/// Simulated risk calculator
struct RiskCalculator {
    max_position: Decimal,
    max_order_size: Decimal,
}

impl RiskCalculator {
    fn new() -> Self {
        Self {
            max_position: Decimal::new(10, 0),
            max_order_size: Decimal::new(5, 0),
        }
    }

    fn validate_order(&self, order: &TestOrder, current_position: Decimal) -> bool {
        // Size check
        if order.quantity > self.max_order_size {
            return false;
        }

        // Position limit check
        let new_position = match order.side {
            OrderSide::Buy => current_position + order.quantity,
            OrderSide::Sell => current_position - order.quantity,
        };

        new_position.abs() <= self.max_position
    }
}

//
// ==================== BENCHMARK 1: Order Validation (<1μs) ====================
//

fn bench_order_validation(c: &mut Criterion) {
    let risk_calc = RiskCalculator::new();
    let current_position = Decimal::new(5, 0);

    c.bench_function("order_validation", |b| {
        b.iter_custom(|iters| {
            let mut metrics = LatencyMetrics::new();

            for i in 0..iters {
                let order = TestOrder::new(i);
                let start = Instant::now();

                black_box(risk_calc.validate_order(&order, current_position));

                metrics.record_nanos(start.elapsed().as_nanos() as u64);
            }

            metrics.report("Order Validation", 1.0);
            Duration::from_nanos((metrics.samples.iter().sum::<u64>() / iters.max(1)) as u64)
        });
    });
}

//
// ==================== BENCHMARK 2: Order Matching (<50μs) ====================
//

fn bench_order_matching(c: &mut Criterion) {
    let order_book = OrderBook::new();

    c.bench_function("order_matching", |b| {
        b.iter_custom(|iters| {
            let mut metrics = LatencyMetrics::new();

            for i in 0..iters {
                let order = TestOrder::new(i);
                let start = Instant::now();

                black_box(order_book.match_order(&order));

                metrics.record_nanos(start.elapsed().as_nanos() as u64);
            }

            metrics.report("Order Matching", 50.0);
            Duration::from_nanos((metrics.samples.iter().sum::<u64>() / iters.max(1)) as u64)
        });
    });
}

//
// ==================== BENCHMARK 3: Position Update (<20μs) ====================
//

fn bench_position_update(c: &mut Criterion) {
    c.bench_function("position_update", |b| {
        b.iter_custom(|iters| {
            let mut metrics = LatencyMetrics::new();
            let mut pm = PositionManager::new();

            for i in 0..iters {
                let order = TestOrder::new(i);
                let start = Instant::now();

                pm.update_position(&order.symbol, order.quantity, order.side);

                metrics.record_nanos(start.elapsed().as_nanos() as u64);
            }

            metrics.report("Position Update", 20.0);
            Duration::from_nanos((metrics.samples.iter().sum::<u64>() / iters.max(1)) as u64)
        });
    });
}

//
// ==================== BENCHMARK 4: Full Order Lifecycle (<100μs) ====================
//

fn bench_full_order_lifecycle(c: &mut Criterion) {
    c.bench_function("full_order_lifecycle", |b| {
        b.iter_custom(|iters| {
            let mut metrics = LatencyMetrics::new();
            let risk_calc = RiskCalculator::new();
            let order_book = OrderBook::new();
            let mut pm = PositionManager::new();

            for i in 0..iters {
                let order = TestOrder::new(i);
                let start = Instant::now();

                // Step 1: Risk validation
                let current_pos = pm.get_position(&order.symbol);
                if risk_calc.validate_order(&order, current_pos) {
                    // Step 2: Order matching
                    if let Some(fill_price) = order_book.match_order(&order) {
                        // Step 3: Position update
                        pm.update_position(&order.symbol, order.quantity, order.side);
                    }
                }

                metrics.record_nanos(start.elapsed().as_nanos() as u64);
            }

            metrics.report("Full Order Lifecycle", 100.0);
            Duration::from_nanos((metrics.samples.iter().sum::<u64>() / iters.max(1)) as u64)
        });
    });
}

//
// ==================== BENCHMARK 5: Concurrent Order Processing ====================
//

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

    for concurrency in &[10, 50, 100] {
        group.throughput(Throughput::Elements(*concurrency as u64));
        group.bench_with_input(
            BenchmarkId::from_parameter(concurrency),
            concurrency,
            |b, &n| {
                let rt = Runtime::new().unwrap();

                b.iter_custom(|_iters| {
                    let start = Instant::now();

                    rt.block_on(async {
                        let mut handles = Vec::new();
                        let risk_calc = Arc::new(RiskCalculator::new());
                        let order_book = Arc::new(OrderBook::new());

                        for i in 0..n {
                            let rc = risk_calc.clone();
                            let ob = order_book.clone();

                            handles.push(tokio::spawn(async move {
                                let order = TestOrder::new(i as u64);
                                let current_pos = Decimal::ZERO;

                                if rc.validate_order(&order, current_pos) {
                                    ob.match_order(&order);
                                }
                            }));
                        }

                        for handle in handles {
                            handle.await.ok();
                        }
                    });

                    start.elapsed()
                });
            },
        );
    }

    group.finish();
}

//
// ==================== BENCHMARK 6: Order Book Updates ====================
//

fn bench_orderbook_updates(c: &mut Criterion) {
    c.bench_function("orderbook_level_update", |b| {
        b.iter_custom(|iters| {
            let mut metrics = LatencyMetrics::new();
            let mut order_book = OrderBook::new();

            for i in 0..iters {
                let start = Instant::now();

                // Simulate level update
                let price = Decimal::new(65000 + (i % 100) as i64, 0);
                let quantity = Decimal::new(1, 1);

                if i % 2 == 0 {
                    order_book.bids.push((price, quantity));
                } else {
                    order_book.asks.push((price, quantity));
                }

                metrics.record_nanos(start.elapsed().as_nanos() as u64);
            }

            metrics.report("Order Book Level Update", 10.0);
            Duration::from_nanos((metrics.samples.iter().sum::<u64>() / iters.max(1)) as u64)
        });
    });
}

criterion_group!(
    order_processing_benches,
    bench_order_validation,
    bench_order_matching,
    bench_position_update,
    bench_full_order_lifecycle,
);

criterion_group!(
    throughput_benches,
    bench_concurrent_orders,
    bench_orderbook_updates,
);

criterion_main!(order_processing_benches, throughput_benches,);
