#![allow(
    clippy::assertions_on_constants,
    clippy::assertions_on_result_states,
    clippy::clone_on_copy,
    clippy::decimal_literal_representation,
    clippy::doc_markdown,
    clippy::empty_line_after_doc_comments,
    clippy::field_reassign_with_default,
    clippy::get_unwrap,
    clippy::identity_op,
    clippy::inconsistent_digit_grouping,
    clippy::indexing_slicing,
    clippy::integer_division,
    clippy::len_zero,
    clippy::let_underscore_must_use,
    clippy::manual_div_ceil,
    clippy::manual_let_else,
    clippy::manual_range_contains,
    clippy::modulo_arithmetic,
    clippy::needless_range_loop,
    clippy::non_ascii_literal,
    clippy::redundant_clone,
    clippy::shadow_reuse,
    clippy::shadow_same,
    clippy::shadow_unrelated,
    clippy::single_match_else,
    clippy::str_to_string,
    clippy::string_slice,
    clippy::tests_outside_test_module,
    clippy::too_many_lines,
    clippy::unnecessary_wraps,
    clippy::unseparated_literal_suffix,
    clippy::use_debug,
    clippy::useless_vec,
    clippy::wildcard_enum_match_arm,
    clippy::else_if_without_else,
    clippy::expect_used,
    clippy::missing_const_for_fn,
    clippy::similar_names,
    clippy::type_complexity,
    clippy::collapsible_else_if,
    clippy::doc_lazy_continuation,
    clippy::items_after_test_module,
    clippy::map_clone,
    clippy::multiple_unsafe_ops_per_block,
    clippy::unwrap_or_default,
    clippy::assign_op_pattern,
    clippy::needless_borrow,
    clippy::println_empty_string,
    clippy::unnecessary_cast,
    clippy::used_underscore_binding,
    clippy::create_dir,
    clippy::implicit_saturating_sub,
    clippy::exit,
    clippy::expect_fun_call,
    clippy::too_many_arguments,
    clippy::unnecessary_map_or,
    clippy::unwrap_used,
    dead_code,
    unused_imports,
    unused_variables,
    clippy::cloned_ref_to_slice_refs,
    clippy::neg_multiply,
    clippy::while_let_loop,
    clippy::bool_assert_comparison,
    clippy::excessive_precision,
    clippy::trivially_copy_pass_by_ref,
    clippy::op_ref,
    clippy::redundant_closure,
    clippy::unnecessary_lazy_evaluations,
    clippy::if_then_some_else_none,
    clippy::unnecessary_to_owned,
    clippy::single_component_path_imports,
)]
//! Performance Benchmarks for Alternative Bar Sampling (Wave B)
//!
//! Agent B14 - Alternative bar sampling performance validation:
//! - Tick Bars (Agent B3)
//! - Volume Bars (Wave B)
//! - Dollar Bars (Wave B)
//! - Imbalance Bars (Wave B)
//! - Triple Barrier Labeling (Wave B)
//! - Barrier Optimization (Wave B)
//!
//! ## Performance Targets
//! - Tick bars: <50μs per bar formation
//! - Volume bars: <50μs per bar formation
//! - Dollar bars: <50μs per bar formation
//! - Imbalance bars: <50μs per bar formation
//! - Triple barrier labeling: <100μs per label
//! - Barrier optimization: <10s for 100 parameter combinations
//!
//! ## Memory Targets
//! - Each sampler: <1MB memory usage
//!
//! ## Run Benchmarks
//! ```bash
//! cargo bench -p ml --bench alternative_bars_bench
//! ```

use chrono::{DateTime, Duration, Utc};
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use ml::features::alternative_bars::{
    DollarBarSampler, TickBarSampler, VolumeBarSampler,
};
use ml::features::barrier_optimization::{BarrierOptimizer, BarrierParams};
use ml::labeling::triple_barrier::{BarrierTracker, PricePoint, TripleBarrierEngine};
use ml::labeling::types::BarrierConfig;
use std::time::Duration as StdDuration;

// ============================================================================
// Test Data Generator
// ============================================================================

/// Generate realistic tick-level trade data for benchmarking
///
/// Returns: (price, volume, timestamp) tuples
fn generate_tick_data(num_ticks: usize, seed: u64) -> Vec<(f64, f64, DateTime<Utc>)> {
    let mut rng = fastrand::Rng::with_seed(seed);
    let mut data = Vec::with_capacity(num_ticks);
    let mut price = 100.0;
    let mut timestamp = Utc::now();

    for _i in 0..num_ticks {
        // Random walk with mean reversion
        let drift = (100.0 - price) * 0.001;
        let noise = (rng.f64() - 0.5) * 0.05;
        price += drift + noise;
        price = price.max(90.0).min(110.0);

        // Volume varies between 1 and 100 contracts
        let volume = 1.0 + rng.f64() * 99.0;

        // Timestamps advance 10-1000ms per tick
        let ms_delta = 10 + (rng.f64() * 990.0) as i64;
        timestamp = timestamp + Duration::milliseconds(ms_delta);

        data.push((price, volume, timestamp));
    }

    data
}

/// Generate price series for barrier optimization
fn generate_price_series(num_prices: usize, seed: u64) -> Vec<f64> {
    let mut rng = fastrand::Rng::with_seed(seed);
    let mut prices = Vec::with_capacity(num_prices);
    let mut price = 100.0;

    for _ in 0..num_prices {
        price += (rng.f64() - 0.5) * 0.5;
        price = price.max(80.0).min(120.0);
        prices.push(price);
    }

    prices
}

// ============================================================================
// Tick Bar Benchmarks (Agent B3)
// ============================================================================

/// Benchmark tick bar formation with various thresholds
fn bench_tick_bars(c: &mut Criterion) {
    let mut group = c.benchmark_group("tick_bars");
    group.measurement_time(StdDuration::from_secs(5));

    let data = generate_tick_data(10000, 42);

    for threshold in [50, 100, 500, 1000].iter() {
        group.throughput(Throughput::Elements(*threshold as u64));

        group.bench_with_input(
            BenchmarkId::new("formation", threshold),
            threshold,
            |b, &thresh| {
                b.iter(|| {
                    let mut sampler = TickBarSampler::new(thresh);
                    let mut bar_count = 0;

                    for &(price, volume, timestamp) in data.iter().take(thresh * 2) {
                        if let Some(_bar) = sampler.update(
                            black_box(price),
                            black_box(volume),
                            black_box(timestamp),
                        ) {
                            bar_count += 1;
                        }
                    }

                    black_box(bar_count);
                });
            },
        );
    }

    group.finish();
}

/// Benchmark tick bar incremental update (single tick)
fn bench_tick_bars_incremental(c: &mut Criterion) {
    let mut group = c.benchmark_group("tick_bars_incremental");
    group.measurement_time(StdDuration::from_secs(5));

    let data = generate_tick_data(1000, 43);

    group.bench_function("single_tick_update", |b| {
        let mut idx = 50;

        b.iter(|| {
            let mut sam = TickBarSampler::new(100);
            // Warm up
            for &(p, v, t) in data.iter().take(50) {
                sam.update(p, v, t);
            }

            let (price, volume, timestamp) = data[idx % data.len()];
            let result = sam.update(black_box(price), black_box(volume), black_box(timestamp));
            black_box(result);
            idx += 1;
        });
    });

    group.finish();
}

// ============================================================================
// Volume Bar Benchmarks
// ============================================================================

/// Benchmark volume bar formation
fn bench_volume_bars(c: &mut Criterion) {
    let mut group = c.benchmark_group("volume_bars");
    group.measurement_time(StdDuration::from_secs(5));

    let data = generate_tick_data(10000, 44);

    for threshold in [1000, 5000, 10000].iter() {
        group.throughput(Throughput::Elements(*threshold as u64));

        group.bench_with_input(
            BenchmarkId::new("formation", threshold),
            threshold,
            |b, &thresh| {
                b.iter(|| {
                    let mut sampler = VolumeBarSampler::new(thresh);
                    let mut bar_count = 0;

                    for &(price, volume, timestamp) in data.iter() {
                        if let Some(_bar) = sampler.update(
                            black_box(price),
                            black_box(volume),
                            black_box(timestamp),
                        ) {
                            bar_count += 1;
                            if bar_count >= 10 {
                                break;
                            }
                        }
                    }

                    black_box(bar_count);
                });
            },
        );
    }

    group.finish();
}

/// Benchmark volume bar incremental update
fn bench_volume_bars_incremental(c: &mut Criterion) {
    let mut group = c.benchmark_group("volume_bars_incremental");
    group.measurement_time(StdDuration::from_secs(5));

    let data = generate_tick_data(1000, 45);

    group.bench_function("single_update", |b| {
        let mut idx = 50;

        b.iter(|| {
            let mut sam = VolumeBarSampler::new(5000);
            // Warm up
            for &(p, v, t) in data.iter().take(50) {
                sam.update(p, v, t);
            }

            let (price, volume, timestamp) = data[idx % data.len()];
            let result = sam.update(black_box(price), black_box(volume), black_box(timestamp));
            black_box(result);
            idx += 1;
        });
    });

    group.finish();
}

// ============================================================================
// Dollar Bar Benchmarks
// ============================================================================

/// Benchmark dollar bar formation (fixed threshold)
fn bench_dollar_bars_fixed(c: &mut Criterion) {
    let mut group = c.benchmark_group("dollar_bars_fixed");
    group.measurement_time(StdDuration::from_secs(5));

    let data = generate_tick_data(10000, 46);

    for threshold in [50000.0, 100000.0, 500000.0].iter() {
        group.bench_with_input(
            BenchmarkId::new("formation", threshold),
            threshold,
            |b, &thresh| {
                b.iter(|| {
                    let mut sampler = DollarBarSampler::new(thresh);
                    let mut bar_count = 0;

                    for &(price, volume, timestamp) in &data {
                        if let Some(_bar) = sampler.update(
                            black_box(price),
                            black_box(volume),
                            black_box(timestamp),
                        ) {
                            bar_count += 1;
                            if bar_count >= 10 {
                                break;
                            }
                        }
                    }

                    black_box(bar_count);
                });
            },
        );
    }

    group.finish();
}

/// Benchmark dollar bar formation (adaptive EWMA)
fn bench_dollar_bars_adaptive(c: &mut Criterion) {
    let mut group = c.benchmark_group("dollar_bars_adaptive");
    group.measurement_time(StdDuration::from_secs(5));

    let data = generate_tick_data(10000, 47);

    for alpha in [0.1, 0.3, 0.5].iter() {
        group.bench_with_input(BenchmarkId::new("adaptive_ewma", alpha), alpha, |b, &a| {
            b.iter(|| {
                let mut sampler = DollarBarSampler::new_adaptive(100000.0, a);
                let mut bar_count = 0;

                for &(price, volume, timestamp) in &data {
                    if let Some(_bar) =
                        sampler.update(black_box(price), black_box(volume), black_box(timestamp))
                    {
                        bar_count += 1;
                        if bar_count >= 10 {
                            break;
                        }
                    }
                }

                black_box(bar_count);
            });
        });
    }

    group.finish();
}

/// Benchmark dollar bar incremental update
fn bench_dollar_bars_incremental(c: &mut Criterion) {
    let mut group = c.benchmark_group("dollar_bars_incremental");
    group.measurement_time(StdDuration::from_secs(5));

    let data = generate_tick_data(1000, 48);

    group.bench_function("single_update", |b| {
        let mut idx = 50;

        b.iter(|| {
            let mut sam = DollarBarSampler::new(100000.0);
            // Warm up
            for &(p, v, t) in data.iter().take(50) {
                sam.update(p, v, t);
            }

            let (price, volume, timestamp) = data[idx % data.len()];
            let result = sam.update(black_box(price), black_box(volume), black_box(timestamp));
            black_box(result);
            idx += 1;
        });
    });

    group.finish();
}

// ============================================================================
// Triple Barrier Labeling Benchmarks
// ============================================================================

/// Benchmark triple barrier single tracker update
fn bench_triple_barrier_single(c: &mut Criterion) {
    let mut group = c.benchmark_group("triple_barrier_single");
    group.measurement_time(StdDuration::from_secs(5));

    let config = BarrierConfig::conservative();

    group.bench_function("tracker_update", |b| {
        b.iter(|| {
            let mut tracker = BarrierTracker::new(10000, 1692000000_000_000_000, config.clone());
            let price_point = PricePoint::new(black_box(10050), black_box(1692000000_500_000_000));
            let result = tracker.update(black_box(price_point));
            black_box(result);
        });
    });

    group.finish();
}

/// Benchmark triple barrier engine with multiple trackers
fn bench_triple_barrier_engine(c: &mut Criterion) {
    let mut group = c.benchmark_group("triple_barrier_engine");
    group.measurement_time(StdDuration::from_secs(5));

    let config = BarrierConfig::conservative();

    for num_trackers in [10, 50, 100, 500].iter() {
        group.throughput(Throughput::Elements(*num_trackers as u64));

        group.bench_with_input(
            BenchmarkId::new("update_all", num_trackers),
            num_trackers,
            |b, &n| {
                b.iter(|| {
                    let mut engine = TripleBarrierEngine::new(1000);

                    // Start N trackers
                    for i in 0..n {
                        let _ = engine.start_tracking(
                            config.clone(),
                            10000 + i * 10,
                            1692000000_000_000_000,
                        );
                    }

                    // Update all with new price
                    let price_point =
                        PricePoint::new(black_box(10050), black_box(1692000000_500_000_000));
                    let labels = engine.update_all(black_box(price_point));
                    black_box(labels);
                });
            },
        );
    }

    group.finish();
}

/// Benchmark triple barrier label generation throughput
fn bench_triple_barrier_throughput(c: &mut Criterion) {
    let mut group = c.benchmark_group("triple_barrier_throughput");
    group.measurement_time(StdDuration::from_secs(10));

    let config = BarrierConfig::conservative();
    let num_prices = 1000;
    let num_trackers = 100;

    group.throughput(Throughput::Elements((num_prices * num_trackers) as u64));

    group.bench_function("generate_labels", |b| {
        b.iter(|| {
            let mut engine = TripleBarrierEngine::new(num_trackers * 2);

            // Start trackers
            for i in 0..num_trackers {
                let _ = engine.start_tracking(
                    config.clone(),
                    10000 + (i as u64 * 10),
                    1692000000_000_000_000,
                );
            }

            // Stream prices and generate labels
            let mut total_labels = 0;
            for i in 0..num_prices {
                let price = 10000 + ((i % 200) as u64);
                let timestamp = 1692000000_000_000_000 + (i as u64 * 100_000_000);
                let price_point = PricePoint::new(price, timestamp);

                let labels = engine.update_all(black_box(price_point));
                total_labels += labels.len();
            }

            black_box(total_labels);
        });
    });

    group.finish();
}

// ============================================================================
// Barrier Optimization Benchmarks
// ============================================================================

/// Benchmark barrier parameter optimization (grid search)
fn bench_barrier_optimization_grid(c: &mut Criterion) {
    let mut group = c.benchmark_group("barrier_optimization");
    group.measurement_time(StdDuration::from_secs(15));

    let prices = generate_price_series(200, 49);

    // Default optimizer: 5 profit × 4 stop × 4 horizon = 80 combinations
    group.bench_function("grid_search_80_params", |b| {
        b.iter(|| {
            let optimizer = BarrierOptimizer::new();
            let result = optimizer.optimize(black_box(&prices));
            black_box(result);
        });
    });

    group.finish();
}

/// Benchmark barrier optimization with custom search space
fn bench_barrier_optimization_custom(c: &mut Criterion) {
    let mut group = c.benchmark_group("barrier_optimization_custom");
    group.measurement_time(StdDuration::from_secs(20));

    let prices = generate_price_series(200, 50);

    // Custom ranges: 10 profit × 6 stop × 5 horizon = 300 combinations
    let profit_range = vec![0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0];
    let stop_range = vec![0.25, 0.5, 1.0, 1.5, 2.0, 2.5];
    let horizon_range = vec![5, 10, 15, 20, 30];

    group.bench_function("grid_search_300_params", |b| {
        b.iter(|| {
            let optimizer = BarrierOptimizer::with_ranges(
                profit_range.clone(),
                stop_range.clone(),
                horizon_range.clone(),
            );
            let result = optimizer.optimize(black_box(&prices));
            black_box(result);
        });
    });

    group.finish();
}

/// Benchmark single barrier parameter evaluation
fn bench_barrier_single_eval(c: &mut Criterion) {
    let mut group = c.benchmark_group("barrier_single_eval");
    group.measurement_time(StdDuration::from_secs(5));

    let prices = generate_price_series(200, 51);
    let optimizer = BarrierOptimizer::new();
    let params = BarrierParams::new(2.0, 1.0, 10);

    group.bench_function("backtest_params", |b| {
        b.iter(|| {
            let sharpe = optimizer.backtest_params(black_box(&params), black_box(&prices));
            black_box(sharpe);
        });
    });

    group.finish();
}

/// Benchmark Sharpe ratio calculation
fn bench_sharpe_calculation(c: &mut Criterion) {
    let mut group = c.benchmark_group("sharpe_calculation");
    group.measurement_time(StdDuration::from_secs(3));

    let returns: Vec<f64> = (0..100).map(|i| (i as f64 - 50.0) * 0.001).collect();
    let optimizer = BarrierOptimizer::new();

    group.bench_function("calculate_sharpe_100_returns", |b| {
        b.iter(|| {
            let sharpe = optimizer.calculate_sharpe(black_box(&returns));
            black_box(sharpe);
        });
    });

    group.finish();
}

// ============================================================================
// Comparison: Alternative Bars vs Time Bars
// ============================================================================

/// Benchmark comparison of all bar sampling methods
fn bench_bar_sampling_comparison(c: &mut Criterion) {
    let mut group = c.benchmark_group("bar_sampling_comparison");
    group.measurement_time(StdDuration::from_secs(10));

    let data = generate_tick_data(5000, 52);

    // Tick bars (100 ticks/bar)
    group.bench_function("tick_bars_100", |b| {
        b.iter(|| {
            let mut sampler = TickBarSampler::new(100);
            let mut bars = Vec::new();

            for &(price, volume, timestamp) in &data {
                if let Some(bar) =
                    sampler.update(black_box(price), black_box(volume), black_box(timestamp))
                {
                    bars.push(bar);
                }
            }

            black_box(bars);
        });
    });

    // Volume bars (5000 volume/bar)
    group.bench_function("volume_bars_5k", |b| {
        b.iter(|| {
            let mut sampler = VolumeBarSampler::new(5000);
            let mut bars = Vec::new();

            for &(price, volume, timestamp) in &data {
                if let Some(bar) =
                    sampler.update(black_box(price), black_box(volume), black_box(timestamp))
                {
                    bars.push(bar);
                }
            }

            black_box(bars);
        });
    });

    // Dollar bars (100k $/bar)
    group.bench_function("dollar_bars_100k", |b| {
        b.iter(|| {
            let mut sampler = DollarBarSampler::new(100000.0);
            let mut bars = Vec::new();

            for &(price, volume, timestamp) in &data {
                if let Some(bar) =
                    sampler.update(black_box(price), black_box(volume), black_box(timestamp))
                {
                    bars.push(bar);
                }
            }

            black_box(bars);
        });
    });

    group.finish();
}

// ============================================================================
// Memory Usage Benchmarks
// ============================================================================

/// Benchmark memory footprint of samplers (via repeated allocation)
fn bench_sampler_memory_footprint(c: &mut Criterion) {
    let mut group = c.benchmark_group("sampler_memory");
    group.measurement_time(StdDuration::from_secs(5));

    group.bench_function("tick_sampler_allocation", |b| {
        b.iter(|| {
            let sampler = TickBarSampler::new(black_box(100));
            black_box(sampler);
        });
    });

    group.bench_function("volume_sampler_allocation", |b| {
        b.iter(|| {
            let sampler = VolumeBarSampler::new(black_box(5000));
            black_box(sampler);
        });
    });

    group.bench_function("dollar_sampler_allocation", |b| {
        b.iter(|| {
            let sampler = DollarBarSampler::new(black_box(100000.0));
            black_box(sampler);
        });
    });

    group.finish();
}

// ============================================================================
// Criterion Configuration
// ============================================================================

criterion_group!(
    tick_bar_benches,
    bench_tick_bars,
    bench_tick_bars_incremental
);

criterion_group!(
    volume_bar_benches,
    bench_volume_bars,
    bench_volume_bars_incremental
);

criterion_group!(
    dollar_bar_benches,
    bench_dollar_bars_fixed,
    bench_dollar_bars_adaptive,
    bench_dollar_bars_incremental
);

criterion_group!(
    triple_barrier_benches,
    bench_triple_barrier_single,
    bench_triple_barrier_engine,
    bench_triple_barrier_throughput
);

criterion_group!(
    barrier_optimization_benches,
    bench_barrier_optimization_grid,
    bench_barrier_optimization_custom,
    bench_barrier_single_eval,
    bench_sharpe_calculation
);

criterion_group!(
    comparison_benches,
    bench_bar_sampling_comparison,
    bench_sampler_memory_footprint
);

criterion_main!(
    tick_bar_benches,
    volume_bar_benches,
    dollar_bar_benches,
    triple_barrier_benches,
    barrier_optimization_benches,
    comparison_benches
);
