#![allow(
    clippy::tests_outside_test_module,
    clippy::unwrap_used,
    clippy::expect_used,
    clippy::indexing_slicing,
    clippy::str_to_string,
    clippy::string_to_string,
    clippy::assertions_on_result_states,
    clippy::assertions_on_constants,
    clippy::let_underscore_must_use,
    clippy::use_debug,
    clippy::doc_markdown,
    clippy::shadow_unrelated,
    clippy::shadow_reuse,
    clippy::similar_names,
    clippy::clone_on_copy,
    clippy::get_unwrap,
    clippy::modulo_arithmetic,
    clippy::integer_division,
    clippy::non_ascii_literal,
    clippy::useless_vec,
    clippy::useless_format,
    clippy::wildcard_enum_match_arm,
    clippy::manual_range_contains,
    clippy::const_is_empty,
    clippy::needless_range_loop,
    clippy::field_reassign_with_default,
    clippy::items_after_test_module,
    clippy::missing_const_for_fn,
    unused_imports,
    unused_variables,
    unused_mut,
    unused_assignments,
    unused_comparisons,
    unused_must_use,
    dead_code,
)]
//! Comprehensive tests for lockfree queue implementations
//!
//! This test suite covers:
//! - `LockFreeRingBuffer` (SPSC queue) with concurrency tests
//! - `SmallBatchRing` with single/multi-threaded modes
//! - `SharedMemoryChannel` for inter-service communication
//! - Atomic operations (`AtomicMetrics`, `AtomicFlag`, `SequenceGenerator`)
//! - Performance benchmarks for HFT requirements (<1μs latency)

use std::sync::Arc;
use std::thread;
use std::time::{Duration, Instant};
use trading_engine::lockfree::{
    atomic_ops::{AtomicFlag, AtomicMetrics, SequenceGenerator},
    ring_buffer::{LockFreeRingBuffer, SPSCQueue},
    small_batch_ring::{BatchMode, SmallBatchOrdersSoA, SmallBatchRing},
    HftMessage, SharedMemoryChannel,
};

// ============================================================================
// LockFreeRingBuffer (SPSC Queue) Tests
// ============================================================================

#[test]
fn test_spsc_basic_operations() {
    let queue = SPSCQueue::<u64>::new(8).expect("Failed to create SPSC queue");

    // Test empty
    assert!(queue.is_empty());
    assert!(!queue.is_full());
    assert_eq!(queue.len(), 0);
    assert_eq!(queue.try_pop(), None);

    // Test push/pop
    queue.try_push(42).unwrap();
    assert!(!queue.is_empty());
    assert_eq!(queue.len(), 1);
    assert_eq!(queue.try_pop(), Some(42));
    assert!(queue.is_empty());
}

#[test]
fn test_spsc_capacity_validation() {
    // Zero capacity should fail
    LockFreeRingBuffer::<u64>::new(0).unwrap_err();

    // Non-power-of-2 should fail
    LockFreeRingBuffer::<u64>::new(3).unwrap_err();
    LockFreeRingBuffer::<u64>::new(7).unwrap_err();
    LockFreeRingBuffer::<u64>::new(100).unwrap_err();

    // Power-of-2 should succeed
    LockFreeRingBuffer::<u64>::new(2).unwrap();
    LockFreeRingBuffer::<u64>::new(4).unwrap();
    LockFreeRingBuffer::<u64>::new(8).unwrap();
    LockFreeRingBuffer::<u64>::new(1024).unwrap();
}

#[test]
fn test_spsc_full_condition() {
    let queue = LockFreeRingBuffer::<u64>::new(4).expect("Failed to create queue");

    // Fill to usable capacity (3 items for capacity-4 SPSC)
    // SPSC ring buffers reserve one slot to distinguish full from empty
    for i in 0..3 {
        assert!(queue.try_push(i).is_ok(), "Failed to push item {}", i);
    }

    assert!(queue.is_full());
    assert_eq!(queue.len(), 3);

    // Should fail when full
    assert!(queue.try_push(99).is_err());

    // Pop one item
    assert_eq!(queue.try_pop(), Some(0));
    assert!(!queue.is_full());

    // Should succeed now
    queue.try_push(99).unwrap();
}

#[test]
fn test_spsc_wraparound() {
    let queue = LockFreeRingBuffer::<u64>::new(4).expect("Failed to create queue");

    // Test multiple wraparounds
    for cycle in 0..10 {
        for i in 0..4 {
            let value = cycle * 4 + i;
            queue.try_push(value).unwrap();
            assert_eq!(queue.try_pop(), Some(value));
        }
    }

    assert!(queue.is_empty());
}

#[test]
fn test_spsc_utilization() {
    let queue = LockFreeRingBuffer::<u64>::new(8).expect("Failed to create queue");

    assert_eq!(queue.utilization(), 0.0);

    queue.try_push(1).unwrap();
    assert!((queue.utilization() - 0.125).abs() < 0.01); // 1/8

    queue.try_push(2).unwrap();
    assert!((queue.utilization() - 0.25).abs() < 0.01); // 2/8

    // Fill to usable capacity (7 items for capacity-8 SPSC)
    for i in 3..=7 {
        queue.try_push(i).unwrap();
    }
    // Utilization at full capacity: 7/8 = 0.875
    assert!((queue.utilization() - 0.875).abs() < 0.01);
}

#[test]
fn test_spsc_concurrent_single_producer_consumer() {
    let queue = Arc::new(LockFreeRingBuffer::<u64>::new(1024).expect("Failed to create queue"));
    let queue_consumer = Arc::clone(&queue);

    const NUM_ITEMS: u64 = 10_000; // Reduced for faster testing

    // Producer thread
    let producer = thread::spawn(move || {
        for i in 0..NUM_ITEMS {
            let mut retries = 0;
            while queue.try_push(i).is_err() {
                thread::yield_now();
                retries += 1;
                if retries > 10000 {
                    panic!("Producer stuck at {}", i);
                }
            }
        }
    });

    // Consumer thread
    let consumer = thread::spawn(move || {
        let mut received = Vec::new();
        let start = Instant::now();
        while received.len() < NUM_ITEMS as usize {
            if let Some(item) = queue_consumer.try_pop() {
                received.push(item);
            } else {
                thread::yield_now();
            }

            // Timeout check
            if start.elapsed().as_secs() > 10 {
                panic!("Consumer timeout after {} items", received.len());
            }
        }
        received
    });

    producer.join().expect("Producer failed");
    let received = consumer.join().expect("Consumer failed");

    // Verify order and completeness
    assert_eq!(received.len(), NUM_ITEMS as usize);
    for (i, item) in received.into_iter().enumerate() {
        assert_eq!(item, i as u64, "Item out of order at index {}", i);
    }
}

#[test]
fn test_spsc_performance_latency() {
    let queue = LockFreeRingBuffer::<u64>::new(8192).expect("Failed to create queue");

    const NUM_OPERATIONS: usize = 100_000;
    let start = Instant::now();

    // Measure push+pop latency
    for i in 0..NUM_OPERATIONS {
        queue.try_push(i as u64).expect("Push failed");
        let value = queue.try_pop().expect("Pop failed");
        assert_eq!(value, i as u64);
    }

    let duration = start.elapsed();
    let avg_latency_ns = duration.as_nanos() / (NUM_OPERATIONS * 2) as u128;

    println!("SPSC performance:");
    println!("  Average latency: {}ns per operation", avg_latency_ns);
    println!(
        "  Throughput: {:.0} ops/sec",
        (NUM_OPERATIONS * 2) as f64 / duration.as_secs_f64()
    );

    // HFT requirement: sub-microsecond latency
    #[cfg(not(debug_assertions))]
    assert!(
        avg_latency_ns < 1000,
        "Latency too high: {}ns > 1000ns",
        avg_latency_ns
    );

    #[cfg(debug_assertions)]
    assert!(
        avg_latency_ns < 100_000,
        "Latency too high for debug: {}ns",
        avg_latency_ns
    );
}

#[test]
#[ignore = "Slow test - run with --ignored"]
fn test_spsc_stress_test() {
    let queue = Arc::new(LockFreeRingBuffer::<u64>::new(256).expect("Failed to create queue"));
    let queue_consumer = Arc::clone(&queue);

    const STRESS_ITEMS: usize = 100_000; // Reduced for faster testing

    let producer = thread::spawn(move || {
        for i in 0..STRESS_ITEMS {
            let mut retries = 0;
            while queue.try_push(i as u64).is_err() {
                thread::yield_now();
                retries += 1;
                if retries > 10000 {
                    panic!("Producer stuck at item {}", i);
                }
            }
        }
    });

    let consumer = thread::spawn(move || {
        let mut count = 0;
        let mut prev = None;
        let start = Instant::now();
        while count < STRESS_ITEMS {
            if let Some(item) = queue_consumer.try_pop() {
                if let Some(p) = prev {
                    assert_eq!(item, p + 1, "Out of order at {}", count);
                }
                prev = Some(item);
                count += 1;
            } else {
                thread::yield_now();
            }

            // Timeout check to prevent infinite loops
            if start.elapsed().as_secs() > 30 {
                panic!("Consumer timeout after {} items", count);
            }
        }
    });

    producer.join().expect("Producer failed");
    consumer.join().expect("Consumer failed");
}

// ============================================================================
// SmallBatchRing Tests
// ============================================================================

#[test]
fn test_small_batch_ring_creation() {
    let ring =
        SmallBatchRing::<u64>::new(8, BatchMode::SingleThreaded).expect("Failed to create ring");

    assert_eq!(ring.capacity(), 8);
    assert_eq!(ring.len(), 0);
    assert!(ring.is_empty());
    assert!(!ring.is_full());
    assert_eq!(ring.batch_mode(), BatchMode::SingleThreaded);
}

#[test]
fn test_small_batch_push_pop() {
    let ring =
        SmallBatchRing::<u32>::new(16, BatchMode::SingleThreaded).expect("Failed to create ring");

    // Push batch
    let items = [1, 2, 3, 4, 5];
    let pushed = ring.push_batch(&items).expect("Failed to push batch");
    assert_eq!(pushed, 5);
    assert_eq!(ring.len(), 5);

    // Pop batch
    let mut output = [0_u32; 3];
    let popped = ring.pop_batch(&mut output);
    assert_eq!(popped, 3);
    assert_eq!(output, [1, 2, 3]);
    assert_eq!(ring.len(), 2);

    // Pop remaining
    let mut remaining = [0_u32; 5];
    let remaining_count = ring.pop_batch(&mut remaining);
    assert_eq!(remaining_count, 2);
    assert_eq!(remaining[0..2], [4, 5]);
    assert!(ring.is_empty());
}

#[test]
fn test_small_batch_mode_switching() {
    let mut ring =
        SmallBatchRing::<u64>::new(8, BatchMode::MultiThreaded).expect("Failed to create ring");

    assert_eq!(ring.batch_mode(), BatchMode::MultiThreaded);

    ring.set_single_threaded();
    assert_eq!(ring.batch_mode(), BatchMode::SingleThreaded);

    ring.set_multi_threaded();
    assert_eq!(ring.batch_mode(), BatchMode::MultiThreaded);
}

#[test]
fn test_small_batch_overflow_handling() {
    let ring =
        SmallBatchRing::<u32>::new(8, BatchMode::SingleThreaded).expect("Failed to create ring");

    // Push 10 items to 8-capacity ring
    let items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    let result = ring.push_batch(&items);

    // Should push only what fits
    result.unwrap();
    let pushed = result.unwrap();
    assert_eq!(pushed, 8);
    assert!(ring.is_full());
}

#[test]
fn test_small_batch_single_vs_multi_threaded() {
    let items = [1_u64, 2, 3, 4, 5, 6, 7, 8];

    // Single-threaded mode
    let st_ring = SmallBatchRing::<u64>::new(16, BatchMode::SingleThreaded)
        .expect("Failed to create ST ring");
    let st_pushed = st_ring.push_batch(&items).unwrap();
    let mut st_output = [0_u64; 8];
    let st_popped = st_ring.pop_batch(&mut st_output);

    // Multi-threaded mode
    let mt_ring =
        SmallBatchRing::<u64>::new(16, BatchMode::MultiThreaded).expect("Failed to create MT ring");
    let mt_pushed = mt_ring.push_batch(&items).unwrap();
    let mut mt_output = [0_u64; 8];
    let mt_popped = mt_ring.pop_batch(&mut mt_output);

    // Both should produce same results
    assert_eq!(st_pushed, mt_pushed);
    assert_eq!(st_popped, mt_popped);
    assert_eq!(st_output, mt_output);
    assert_eq!(st_output, items);
}

#[test]
fn test_small_batch_performance() {
    let ring =
        SmallBatchRing::<u64>::new(1024, BatchMode::SingleThreaded).expect("Failed to create ring");

    const NUM_BATCHES: usize = 10_000;
    const BATCH_SIZE: usize = 8;

    let start = Instant::now();

    for batch_id in 0..NUM_BATCHES {
        let mut items = [0_u64; BATCH_SIZE];
        for i in 0..BATCH_SIZE {
            items[i] = (batch_id * BATCH_SIZE + i) as u64;
        }

        ring.push_batch(&items).expect("Failed to push batch");

        let mut output = [0_u64; BATCH_SIZE];
        let popped = ring.pop_batch(&mut output);
        assert_eq!(popped, BATCH_SIZE);
        assert_eq!(output, items);
    }

    let duration = start.elapsed();
    let ops_per_sec = (NUM_BATCHES * BATCH_SIZE * 2) as f64 / duration.as_secs_f64();
    let avg_latency_ns = duration.as_nanos() / (NUM_BATCHES * 2) as u128;

    println!("SmallBatchRing performance:");
    println!("  Operations per second: {:.0}", ops_per_sec);
    println!("  Average latency per batch: {}ns", avg_latency_ns);

    // Should be faster than 500ns per batch operation
    assert!(
        avg_latency_ns < 500,
        "Latency too high: {}ns",
        avg_latency_ns
    );
}

// ============================================================================
// SmallBatchOrdersSoA Tests
// ============================================================================

#[test]
fn test_soa_basic_operations() {
    let mut soa = SmallBatchOrdersSoA::new();

    assert_eq!(soa.count, 0);

    // Add orders
    assert!(soa.add_order(1, 0x123, 0, 1, 1.5, 50000.0, 1000));
    assert!(soa.add_order(2, 0x456, 1, 0, 2.0, 3000.0, 2000));
    assert_eq!(soa.count, 2);

    // Test SIMD-friendly access
    let prices = soa.prices_simd();
    assert_eq!(prices.len(), 2);
    assert_eq!(prices[0], 50000.0);
    assert_eq!(prices[1], 3000.0);

    let quantities = soa.quantities_simd();
    assert_eq!(quantities.len(), 2);
    assert_eq!(quantities[0], 1.5);
    assert_eq!(quantities[1], 2.0);
}

#[test]
fn test_soa_capacity_limit() {
    let mut soa = SmallBatchOrdersSoA::new();

    // Add 8 orders (max capacity)
    for i in 0..8 {
        assert!(soa.add_order(i, 0, 0, 0, 1.0, 100.0, i));
    }

    // 9th order should fail
    assert!(!soa.add_order(9, 0, 0, 0, 1.0, 100.0, 9));
    assert_eq!(soa.count, 8);
}

#[test]
fn test_soa_notional_calculation() {
    let mut soa = SmallBatchOrdersSoA::new();

    soa.add_order(1, 0, 0, 1, 1.5, 50000.0, 1000);
    soa.add_order(2, 0, 1, 0, 2.0, 3000.0, 2000);
    soa.add_order(3, 0, 0, 1, 0.5, 100.0, 3000);

    let total = soa.calculate_total_notional_scalar();
    let expected = 1.5 * 50000.0 + 2.0 * 3000.0 + 0.5 * 100.0; // 75000 + 6000 + 50 = 81050
    assert!((total - expected).abs() < 1e-6);

    // Test SIMD version (if available)
    #[cfg(target_arch = "x86_64")]
    {
        let total_simd = soa.calculate_total_notional_simd();
        assert!((total_simd - expected).abs() < 1e-6);
    }
}

#[test]
fn test_soa_clear() {
    let mut soa = SmallBatchOrdersSoA::new();

    soa.add_order(1, 0, 0, 1, 1.0, 100.0, 1000);
    soa.add_order(2, 0, 1, 0, 2.0, 200.0, 2000);
    assert_eq!(soa.count, 2);

    soa.clear();
    assert_eq!(soa.count, 0);

    // Should be able to add again
    assert!(soa.add_order(3, 0, 0, 1, 3.0, 300.0, 3000));
    assert_eq!(soa.count, 1);
}

// ============================================================================
// SharedMemoryChannel Tests
// ============================================================================

#[test]
fn test_shared_memory_channel_creation() {
    let channel = SharedMemoryChannel::new(1024).expect("Failed to create channel");
    let stats = channel.get_stats();

    assert_eq!(stats.messages_sent, 0);
    assert_eq!(stats.messages_received, 0);
    assert_eq!(stats.send_failures, 0);
}

#[test]
fn test_shared_memory_channel_basic_send_receive() {
    let channel = SharedMemoryChannel::new(1024).expect("Failed to create channel");
    let message = HftMessage::new(1, [1, 2, 3, 4, 5, 6, 7, 8]);

    channel.send(message).unwrap();

    if let Some(received) = channel.try_receive() {
        assert_eq!(received.msg_type, 1);
        assert_eq!(received.payload, [1, 2, 3, 4, 5, 6, 7, 8]);
    } else {
        panic!("Message not received");
    }

    let stats = channel.get_stats();
    assert_eq!(stats.messages_sent, 1);
    assert_eq!(stats.messages_received, 1);
}

#[test]
fn test_shared_memory_channel_full_condition() {
    let channel = SharedMemoryChannel::new(4).expect("Failed to create channel");
    let message = HftMessage::new(1, [0; 8]);

    // Fill buffer to usable capacity (3 items for capacity-4 SPSC)
    // SharedMemoryChannel uses SPSC ring buffer which reserves one slot
    for _ in 0..3 {
        channel.send(message).unwrap();
    }

    // Should fail when full
    assert!(channel.send(message).is_err());

    let stats = channel.get_stats();
    assert_eq!(stats.messages_sent, 3);
    assert_eq!(stats.send_failures, 1);
}

#[test]
fn test_shared_memory_channel_latency_tracking() {
    let channel = SharedMemoryChannel::new(1024).expect("Failed to create channel");
    let message = HftMessage::new(1, [0; 8]);

    // Send multiple messages
    for _ in 0..100 {
        channel.send(message).expect("Send failed");
    }

    let stats = channel.get_stats();
    assert_eq!(stats.messages_sent, 100);
    assert!(stats.avg_latency_ns > 0);
    assert!(stats.max_latency_ns > 0);
    assert!(stats.max_latency_ns >= stats.avg_latency_ns);
}

#[test]
#[ignore = "Slow throughput test"]
fn test_shared_memory_channel_throughput() {
    let channel = SharedMemoryChannel::new(8192).expect("Failed to create channel");
    let message = HftMessage::new(1, [0; 8]);

    const NUM_MESSAGES: usize = 1_000; // Reduced for faster testing
    let start = Instant::now();

    for _ in 0..NUM_MESSAGES {
        while channel.send(message).is_err() {
            thread::yield_now();
        }
    }

    let duration = start.elapsed();
    let msgs_per_sec = NUM_MESSAGES as f64 / duration.as_secs_f64();

    println!(
        "SharedMemoryChannel throughput: {:.0} msgs/sec",
        msgs_per_sec
    );

    // Should handle >10K messages/sec (relaxed for test speed)
    assert!(
        msgs_per_sec > 10_000.0,
        "Throughput too low: {:.0} msgs/sec",
        msgs_per_sec
    );
}

// ============================================================================
// AtomicMetrics Tests
// ============================================================================

#[test]
fn test_atomic_metrics_basic() {
    let metrics = AtomicMetrics::new();

    metrics.record_operation(100);
    metrics.record_operation(200);
    metrics.record_operation(50);
    metrics.record_error();
    metrics.record_bytes(1024);

    let snapshot = metrics.snapshot();

    assert_eq!(snapshot.operations_count, 3);
    assert_eq!(snapshot.avg_latency_ns, (100 + 200 + 50) / 3);
    assert_eq!(snapshot.min_latency_ns, 50);
    assert_eq!(snapshot.max_latency_ns, 200);
    assert_eq!(snapshot.errors_count, 1);
    assert_eq!(snapshot.bytes_processed, 1024);
}

#[test]
fn test_atomic_metrics_reset() {
    let metrics = AtomicMetrics::new();

    metrics.record_operation(100);
    metrics.record_error();

    let snapshot1 = metrics.snapshot();
    assert_eq!(snapshot1.operations_count, 1);

    metrics.reset();

    let snapshot2 = metrics.snapshot();
    assert_eq!(snapshot2.operations_count, 0);
    assert_eq!(snapshot2.errors_count, 0);
    assert_eq!(snapshot2.min_latency_ns, u64::MAX);
    assert_eq!(snapshot2.max_latency_ns, 0);
}

#[test]
fn test_atomic_metrics_concurrent() {
    let metrics = Arc::new(AtomicMetrics::new());
    let num_threads = 8;
    let ops_per_thread = 1000;

    let mut handles = Vec::new();

    for _ in 0..num_threads {
        let metrics_clone = Arc::clone(&metrics);
        let handle = thread::spawn(move || {
            for i in 0..ops_per_thread {
                let latency = 100 + (i % 100) as u64;
                metrics_clone.record_operation(latency);
                if i % 100 == 0 {
                    metrics_clone.record_error();
                }
                metrics_clone.record_bytes(64);
            }
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().expect("Thread failed");
    }

    let snapshot = metrics.snapshot();
    assert_eq!(
        snapshot.operations_count,
        (num_threads * ops_per_thread) as u64
    );
    assert_eq!(
        snapshot.errors_count,
        (num_threads * (ops_per_thread / 100)) as u64
    );
    assert_eq!(
        snapshot.bytes_processed,
        (num_threads * ops_per_thread * 64) as u64
    );
}

#[test]
#[ignore = "Uses sleep - slow test"]
fn test_atomic_metrics_operations_per_second() {
    let metrics = AtomicMetrics::new();

    // Record operations over time
    for _ in 0..10 {
        metrics.record_operation(100);
        thread::sleep(Duration::from_millis(10));
    }

    let ops_per_sec = metrics.operations_per_second();
    println!("Operations per second: {:.0}", ops_per_sec);

    // Should be reasonable (not zero, not infinite)
    assert!(ops_per_sec > 0.0);
    assert!(ops_per_sec < 1_000_000.0);
}

// ============================================================================
// AtomicFlag Tests
// ============================================================================

#[test]
fn test_atomic_flag_basic() {
    let flag = AtomicFlag::new();

    assert!(!flag.is_set());

    flag.set();
    assert!(flag.is_set());

    flag.clear();
    assert!(!flag.is_set());
}

#[test]
fn test_atomic_flag_test_and_set() {
    let flag = AtomicFlag::new();

    // First test_and_set should return false (was not set)
    assert!(!flag.test_and_set());
    assert!(flag.is_set());

    // Second test_and_set should return true (was set)
    assert!(flag.test_and_set());
    assert!(flag.is_set());
}

#[test]
fn test_atomic_flag_compare_and_swap() {
    let flag = AtomicFlag::new_with(false);

    // Successful swap
    let prev = flag.compare_and_swap(false, true);
    assert!(!prev);
    assert!(flag.is_set());

    // Failed swap
    let prev2 = flag.compare_and_swap(false, true);
    assert!(prev2); // Returns current value on failure
    assert!(flag.is_set());
}

#[test]
fn test_atomic_flag_concurrent_race() {
    let flag = Arc::new(AtomicFlag::new());
    let num_threads = 10;

    let mut handles = Vec::new();

    for thread_id in 0..num_threads {
        let flag_clone = Arc::clone(&flag);
        let handle = thread::spawn(move || {
            // Each thread tries to be first
            let was_first = !flag_clone.test_and_set();
            (thread_id, was_first)
        });
        handles.push(handle);
    }

    let results: Vec<_> = handles
        .into_iter()
        .map(|h| h.join().expect("Thread failed"))
        .collect();

    // Exactly one thread should win
    let winners = results.iter().filter(|(_, was_first)| *was_first).count();
    assert_eq!(winners, 1);
    assert!(flag.is_set());
}

// ============================================================================
// SequenceGenerator Tests
// ============================================================================

#[test]
fn test_sequence_generator_basic() {
    let gen = SequenceGenerator::new();

    assert_eq!(gen.current(), 1);
    assert_eq!(gen.next(), 1);
    assert_eq!(gen.next(), 2);
    assert_eq!(gen.next(), 3);
    assert_eq!(gen.current(), 4);
}

#[test]
fn test_sequence_generator_custom_start() {
    let gen = SequenceGenerator::new_with_start(100);

    assert_eq!(gen.current(), 100);
    assert_eq!(gen.next(), 100);
    assert_eq!(gen.next(), 101);
}

#[test]
fn test_sequence_generator_reset() {
    let gen = SequenceGenerator::new();

    gen.next();
    gen.next();
    assert_eq!(gen.current(), 3);

    gen.reset(0);
    assert_eq!(gen.current(), 0);
    assert_eq!(gen.next(), 0);
}

#[test]
fn test_sequence_generator_concurrent_uniqueness() {
    let gen = Arc::new(SequenceGenerator::new());
    let num_threads = 8;
    let increments_per_thread = 1000;

    let mut handles = Vec::new();

    for _ in 0..num_threads {
        let gen_clone = Arc::clone(&gen);
        let handle = thread::spawn(move || {
            let mut sequences = Vec::new();
            for _ in 0..increments_per_thread {
                sequences.push(gen_clone.next());
            }
            sequences
        });
        handles.push(handle);
    }

    let mut all_sequences = Vec::new();
    for handle in handles {
        let sequences = handle.join().expect("Thread failed");
        all_sequences.extend(sequences);
    }

    // Verify all sequences are unique
    all_sequences.sort_unstable();
    assert_eq!(all_sequences.len(), num_threads * increments_per_thread);

    for window in all_sequences.windows(2) {
        assert_ne!(window[0], window[1], "Duplicate sequence found");
    }
}

// ============================================================================
// Performance Benchmarks
// ============================================================================

#[test]
#[ignore = "Slow benchmark - run with --ignored"]
fn benchmark_spsc_vs_crossbeam() {
    use std::sync::mpsc;

    const BENCH_ITEMS: usize = 100_000;

    // Our SPSC queue
    let our_queue = Arc::new(LockFreeRingBuffer::<u64>::new(1024).expect("Failed to create"));
    let our_consumer = Arc::clone(&our_queue);

    let start = Instant::now();
    let producer = thread::spawn(move || {
        for i in 0..BENCH_ITEMS {
            while our_queue.try_push(i as u64).is_err() {
                thread::yield_now();
            }
        }
    });

    let consumer = thread::spawn(move || {
        let mut count = 0;
        while count < BENCH_ITEMS {
            if our_consumer.try_pop().is_some() {
                count += 1;
            } else {
                thread::yield_now();
            }
        }
    });

    producer.join().unwrap();
    consumer.join().unwrap();
    let our_time = start.elapsed();

    // Stdlib mpsc channel
    let (tx, rx) = mpsc::channel();
    let start = Instant::now();

    let producer = thread::spawn(move || {
        for i in 0..BENCH_ITEMS {
            tx.send(i as u64).unwrap();
        }
    });

    let consumer = thread::spawn(move || {
        for _ in 0..BENCH_ITEMS {
            rx.recv().unwrap();
        }
    });

    producer.join().unwrap();
    consumer.join().unwrap();
    let mpsc_time = start.elapsed();

    println!("Performance comparison (100K items):");
    println!("  Our SPSC:     {:?}", our_time);
    println!("  Stdlib MPSC:  {:?}", mpsc_time);
    println!(
        "  Speedup:      {:.2}x",
        mpsc_time.as_secs_f64() / our_time.as_secs_f64()
    );

    // Our implementation should be competitive or faster
    #[cfg(not(debug_assertions))]
    assert!(
        our_time < mpsc_time * 2,
        "Our SPSC is too slow compared to stdlib"
    );
}

#[test]
#[ignore = "Slow benchmark - run with --ignored"]
fn benchmark_hft_latency_requirements() {
    let queue = LockFreeRingBuffer::<u64>::new(1024).expect("Failed to create");

    // Warm up
    for i in 0..1000 {
        queue.try_push(i).unwrap();
        queue.try_pop().unwrap();
    }

    // Measure minimum latency
    let mut min_latency_ns = u128::MAX;
    const SAMPLES: usize = 10_000;

    for i in 0..SAMPLES {
        let start = Instant::now();
        queue.try_push(i as u64).unwrap();
        queue.try_pop().unwrap();
        let latency = start.elapsed().as_nanos();

        if latency < min_latency_ns {
            min_latency_ns = latency;
        }
    }

    println!("HFT latency benchmark:");
    println!("  Minimum latency: {}ns (push + pop)", min_latency_ns);

    // HFT target: <1μs for release builds
    #[cfg(not(debug_assertions))]
    assert!(
        min_latency_ns < 1000,
        "Minimum latency too high: {}ns",
        min_latency_ns
    );
}

#[test]
#[ignore = "Slow benchmark - run with --ignored"]
fn benchmark_throughput_1m_ops() {
    let queue = Arc::new(LockFreeRingBuffer::<u64>::new(8192).expect("Failed to create"));
    let queue_consumer = Arc::clone(&queue);

    const TARGET_OPS: usize = 1_000_000;

    let start = Instant::now();

    let producer = thread::spawn(move || {
        for i in 0..TARGET_OPS {
            while queue.try_push(i as u64).is_err() {
                thread::yield_now();
            }
        }
    });

    let consumer = thread::spawn(move || {
        let mut count = 0;
        while count < TARGET_OPS {
            if queue_consumer.try_pop().is_some() {
                count += 1;
            } else {
                thread::yield_now();
            }
        }
    });

    producer.join().unwrap();
    consumer.join().unwrap();

    let duration = start.elapsed();
    let ops_per_sec = TARGET_OPS as f64 / duration.as_secs_f64();

    println!("Throughput benchmark (1M operations):");
    println!("  Time: {:?}", duration);
    println!("  Throughput: {:.0} ops/sec", ops_per_sec);

    // Should handle >1M ops/sec
    #[cfg(not(debug_assertions))]
    assert!(
        ops_per_sec > 1_000_000.0,
        "Throughput too low: {:.0} ops/sec",
        ops_per_sec
    );
}
