//! Risk Engine Position Validation Latency Benchmarks
//!
//! Measures risk calculation and validation latencies:
//! - Position risk check: <20μs target
//! - VaR calculation: <50μs target
//! - Portfolio Greeks: <30μs target
//! - Compliance checks: <10μs target
//!
//! Uses HDR histograms for statistical accuracy

#![allow(
    dead_code,
    unused_crate_dependencies,
    clippy::doc_markdown,
    clippy::integer_division,
    clippy::non_ascii_literal,
    clippy::str_to_string,
    clippy::unnecessary_cast,
    clippy::unseparated_literal_suffix,
    clippy::unwrap_used
)]

use criterion::{black_box, criterion_group, criterion_main, Criterion};
use hdrhistogram::Histogram;
use rust_decimal::Decimal;
use std::collections::HashMap;
use std::time::{Duration, Instant};

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

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

    fn record_nanos(&mut self, nanos: u64) {
        self.histogram.record(nanos / 1000).ok(); // μs
        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;

        println!("\n=== {} ===", label);
        println!("P50:  {:.3}μs", p50);
        println!("P95:  {:.3}μs", p95);
        println!("P99:  {:.3}μs", p99);
        println!("P999: {:.3}μs", p999);

        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);
        }
    }
}

/// Position data
struct Position {
    symbol: String,
    quantity: Decimal,
    entry_price: Decimal,
    current_price: Decimal,
}

/// Risk limits
struct RiskLimits {
    max_position_size: Decimal,
    max_portfolio_value: Decimal,
    max_single_order: Decimal,
    max_leverage: Decimal,
}

/// Risk calculator
struct RiskEngine {
    limits: RiskLimits,
    positions: HashMap<String, Position>,
}

impl RiskEngine {
    fn new() -> Self {
        let mut positions = HashMap::new();

        // Pre-populate with test positions
        positions.insert(
            "BTC-USD".to_string(),
            Position {
                symbol: "BTC-USD".to_string(),
                quantity: Decimal::new(5, 0),
                entry_price: Decimal::new(64000, 0),
                current_price: Decimal::new(65000, 0),
            },
        );

        positions.insert(
            "ETH-USD".to_string(),
            Position {
                symbol: "ETH-USD".to_string(),
                quantity: Decimal::new(50, 0),
                entry_price: Decimal::new(3200, 0),
                current_price: Decimal::new(3300, 0),
            },
        );

        Self {
            limits: RiskLimits {
                max_position_size: Decimal::new(100, 0),
                max_portfolio_value: Decimal::new(10000000, 0),
                max_single_order: Decimal::new(50, 0),
                max_leverage: Decimal::new(3, 0),
            },
            positions,
        }
    }

    fn check_position_limit(&self, symbol: &str, new_quantity: Decimal) -> bool {
        let current = self
            .positions
            .get(symbol)
            .map(|p| p.quantity)
            .unwrap_or(Decimal::ZERO);

        (current + new_quantity).abs() <= self.limits.max_position_size
    }

    fn calculate_var(&self, confidence: Decimal) -> Decimal {
        let mut total_risk = Decimal::ZERO;

        for position in self.positions.values() {
            let notional = position.quantity * position.current_price;
            let risk = notional * confidence / Decimal::new(100, 0);
            total_risk += risk.abs();
        }

        total_risk
    }

    fn calculate_portfolio_value(&self) -> Decimal {
        self.positions
            .values()
            .map(|p| p.quantity * p.current_price)
            .sum()
    }

    fn check_leverage(&self, new_position_value: Decimal) -> bool {
        let current_value = self.calculate_portfolio_value();
        let total_exposure = current_value + new_position_value;

        // Simplified leverage check (would use equity in production)
        total_exposure <= current_value * self.limits.max_leverage
    }
}

//
// ==================== BENCHMARK 1: Position Risk Check (<20μs) ====================
//

fn bench_position_risk_check(c: &mut Criterion) {
    let engine = RiskEngine::new();

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

            for i in 0..iters {
                let symbol = if i % 2 == 0 { "BTC-USD" } else { "ETH-USD" };
                let quantity = Decimal::new((i % 10) as i64, 0);

                let start = Instant::now();
                black_box(engine.check_position_limit(symbol, quantity));
                metrics.record_nanos(start.elapsed().as_nanos() as u64);
            }

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

//
// ==================== BENCHMARK 2: VaR Calculation (<50μs) ====================
//

fn bench_var_calculation(c: &mut Criterion) {
    let engine = RiskEngine::new();

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

            for i in 0..iters {
                let confidence = Decimal::new(95 + (i % 5) as i64, 0);

                let start = Instant::now();
                black_box(engine.calculate_var(confidence));
                metrics.record_nanos(start.elapsed().as_nanos() as u64);
            }

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

//
// ==================== BENCHMARK 3: Portfolio Value Calculation (<30μs) ====================
//

fn bench_portfolio_value(c: &mut Criterion) {
    let engine = RiskEngine::new();

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

            for _ in 0..iters {
                let start = Instant::now();
                black_box(engine.calculate_portfolio_value());
                metrics.record_nanos(start.elapsed().as_nanos() as u64);
            }

            metrics.report("Portfolio Value Calculation", 30.0);
            Duration::from_nanos((metrics.samples.iter().sum::<u64>() / iters.max(1)) as u64)
        });
    });
}

//
// ==================== BENCHMARK 4: Leverage Check (<10μs) ====================
//

fn bench_leverage_check(c: &mut Criterion) {
    let engine = RiskEngine::new();

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

            for i in 0..iters {
                let new_position_value = Decimal::new((100000 + i * 1000) as i64, 0);

                let start = Instant::now();
                black_box(engine.check_leverage(new_position_value));
                metrics.record_nanos(start.elapsed().as_nanos() as u64);
            }

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

//
// ==================== BENCHMARK 5: Full Risk Validation (<50μs) ====================
//

fn bench_full_risk_validation(c: &mut Criterion) {
    let engine = RiskEngine::new();

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

            for i in 0..iters {
                let symbol = if i % 2 == 0 { "BTC-USD" } else { "ETH-USD" };
                let quantity = Decimal::new((i % 10) as i64, 0);
                let price = Decimal::new(65000, 0);

                let start = Instant::now();

                // Step 1: Position limit check
                let position_ok = engine.check_position_limit(symbol, quantity);

                // Step 2: Leverage check
                let new_value = quantity * price;
                let leverage_ok = engine.check_leverage(new_value);

                // Step 3: VaR calculation
                let var = engine.calculate_var(Decimal::new(95, 0));

                black_box((position_ok, leverage_ok, var));
                metrics.record_nanos(start.elapsed().as_nanos() as u64);
            }

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

//
// ==================== BENCHMARK 6: Multi-Position Risk Aggregation ====================
//

fn bench_multi_position_risk(c: &mut Criterion) {
    c.bench_function("multi_position_risk_aggregation", |b| {
        b.iter_custom(|iters| {
            let mut metrics = LatencyMetrics::new();

            for _ in 0..iters {
                // Create engine with multiple positions
                let mut engine = RiskEngine::new();

                // Add more positions
                for j in 0..5 {
                    engine.positions.insert(
                        format!("SYMBOL-{}", j),
                        Position {
                            symbol: format!("SYMBOL-{}", j),
                            quantity: Decimal::new(10 + j as i64, 0),
                            entry_price: Decimal::new(1000, 0),
                            current_price: Decimal::new(1050, 0),
                        },
                    );
                }

                let start = Instant::now();

                // Calculate aggregate risk across all positions
                let portfolio_value = engine.calculate_portfolio_value();
                let var_95 = engine.calculate_var(Decimal::new(95, 0));
                let var_99 = engine.calculate_var(Decimal::new(99, 0));

                black_box((portfolio_value, var_95, var_99));
                metrics.record_nanos(start.elapsed().as_nanos() as u64);
            }

            metrics.report("Multi-Position Risk Aggregation", 100.0);
            Duration::from_nanos((metrics.samples.iter().sum::<u64>() / iters.max(1)) as u64)
        });
    });
}

criterion_group!(
    risk_benches,
    bench_position_risk_check,
    bench_var_calculation,
    bench_portfolio_value,
    bench_leverage_check,
    bench_full_risk_validation,
    bench_multi_position_risk,
);

criterion_main!(risk_benches);
