#![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 SIMD fallback paths and lock-free data structures
//!
//! This test suite ensures proper fallback behavior when CPU features are unavailable
//! and tests edge cases in concurrent data structures.

// use trading_engine::types::simd_optimizations::{CacheAlignedPriceArray, SIMDFinancialOps};
// use common::{Price, Quantity}; // Unused in current tests
use std::sync::Arc;
use std::thread;
use trading_engine::lockfree::mpsc_queue::{AtomicCounter, MPSCQueue};

// ============================================================================
// SIMD Fallback Path Tests
// ============================================================================
// Note: SIMD tests are disabled as simd_optimizations module is not implemented yet

/*
#[test]
fn test_simd_portfolio_value_empty_arrays() {
    let positions: Vec<Quantity> = vec![];
    let prices: Vec<Price> = vec![];

    let result = SIMDFinancialOps::portfolio_value_simd(&positions, &prices);
    assert_eq!(result, Price::ZERO);
}

#[test]
fn test_simd_portfolio_value_single_element() {
    let positions = vec![Quantity(100)];
    let prices = vec![Price::from_f64(50000.0).unwrap()];

    let result = SIMDFinancialOps::portfolio_value_simd(&positions, &prices);
    let expected = Price::from_f64(5_000_000.0).unwrap();

    // Use approximate comparison for floating point
    assert!((result.to_f64() - expected.to_f64()).abs() < 0.01);
}

#[test]
fn test_simd_portfolio_value_misaligned_length() {
    // Test with length that's not a multiple of 8
    let positions = vec![
        Quantity(100),
        Quantity(200),
        Quantity(150),
        Quantity(75),
        Quantity(300),
    ];

    let prices = vec![
        Price::from_f64(50000.0).unwrap(),
        Price::from_f64(3000.0).unwrap(),
        Price::from_f64(100.0).unwrap(),
        Price::from_f64(1.0).unwrap(),
        Price::from_f64(200.0).unwrap(),
    ];

    let result = SIMDFinancialOps::portfolio_value_simd(&positions, &prices);

    // Manual calculation: 100*50000 + 200*3000 + 150*100 + 75*1 + 300*200
    // = 5,000,000 + 600,000 + 15,000 + 75 + 60,000 = 5,675,075
    let expected = Price::from_f64(5_675_075.0).unwrap();

    assert!((result.to_f64() - expected.to_f64()).abs() < 0.01);
}

#[test]
fn test_simd_portfolio_value_exactly_8_elements() {
    // Test with exactly 8 elements (one SIMD register worth)
    let positions = vec![
        Quantity(100), Quantity(200), Quantity(150), Quantity(75),
        Quantity(300), Quantity(50), Quantity(125), Quantity(175),
    ];

    let prices: Vec<Price> = vec![
        Price::from_f64(1000.0).unwrap(),
        Price::from_f64(2000.0).unwrap(),
        Price::from_f64(3000.0).unwrap(),
        Price::from_f64(4000.0).unwrap(),
        Price::from_f64(5000.0).unwrap(),
        Price::from_f64(6000.0).unwrap(),
        Price::from_f64(7000.0).unwrap(),
        Price::from_f64(8000.0).unwrap(),
    ];

    let result = SIMDFinancialOps::portfolio_value_simd(&positions, &prices);

    // Manual: 100*1000 + 200*2000 + 150*3000 + 75*4000 + 300*5000 + 50*6000 + 125*7000 + 175*8000
    // = 100000 + 400000 + 450000 + 300000 + 1500000 + 300000 + 875000 + 1400000 = 5,325,000
    let expected = Price::from_f64(5_325_000.0).unwrap();

    assert!((result.to_f64() - expected.to_f64()).abs() < 0.01);
}

#[test]
fn test_simd_portfolio_value_large_array() {
    // Test with a large array (multiple SIMD registers)
    let mut positions = Vec::new();
    let mut prices = Vec::new();

    for i in 0..1000 {
        positions.push(Quantity(i + 1));
        prices.push(Price::from_f64((i + 1) as f64 * 100.0).unwrap());
    }

    let result = SIMDFinancialOps::portfolio_value_simd(&positions, &prices);

    // Verify result is reasonable (should be sum of i * i * 100 for i=1 to 1000)
    // Sum formula: sum(i^2 * 100) = 100 * (n * (n+1) * (2n+1) / 6)
    // For n=1000: 100 * (1000 * 1001 * 2001 / 6) = 333,833,500
    let expected = Price::from_f64(333_833_500.0).unwrap();

    assert!((result.to_f64() - expected.to_f64()).abs() < 100.0); // Allow some FP error
}

#[test]
fn test_simd_portfolio_value_zero_prices() {
    let positions = vec![Quantity(100), Quantity(200), Quantity(150)];
    let prices = vec![
        Price::from_f64(0.0).unwrap(),
        Price::from_f64(0.0).unwrap(),
        Price::from_f64(0.0).unwrap(),
    ];

    let result = SIMDFinancialOps::portfolio_value_simd(&positions, &prices);
    assert_eq!(result, Price::ZERO);
}

#[test]
fn test_simd_portfolio_value_negative_positions() {
    // Short positions (negative quantities)
    let positions = vec![Quantity(-100), Quantity(-200)];
    let prices = vec![
        Price::from_f64(50000.0).unwrap(),
        Price::from_f64(3000.0).unwrap(),
    ];

    let result = SIMDFinancialOps::portfolio_value_simd(&positions, &prices);

    // Result should be negative: -100*50000 + -200*3000 = -5,600,000
    let expected = Price::from_f64(-5_600_000.0).unwrap();

    assert!((result.to_f64() - expected.to_f64()).abs() < 0.01);
}

#[test]
fn test_cache_aligned_price_array() {
    let prices = [
        Price::from_f64(1.0).unwrap(),
        Price::from_f64(2.0).unwrap(),
        Price::from_f64(3.0).unwrap(),
        Price::from_f64(4.0).unwrap(),
        Price::from_f64(5.0).unwrap(),
        Price::from_f64(6.0).unwrap(),
        Price::from_f64(7.0).unwrap(),
        Price::from_f64(8.0).unwrap(),
    ];

    let aligned = CacheAlignedPriceArray::new(prices);

    let slice = aligned.as_slice();
    assert_eq!(slice.len(), 8);
    assert_eq!(slice[0], prices[0]);
    assert_eq!(slice[7], prices[7]);
}

#[test]
fn test_cache_aligned_price_array_mutation() {
    let prices = [Price::ZERO; 8];
    let mut aligned = CacheAlignedPriceArray::new(prices);

    let mut_slice = aligned.as_mut_slice();
    mut_slice[0] = Price::from_f64(100.0).unwrap();
    mut_slice[7] = Price::from_f64(200.0).unwrap();

    let slice = aligned.as_slice();
    assert_eq!(slice[0], Price::from_f64(100.0).unwrap());
    assert_eq!(slice[7], Price::from_f64(200.0).unwrap());
}
*/

// ============================================================================
// Lock-free MPSC Queue Edge Cases
// ============================================================================

#[test]
fn test_mpsc_queue_concurrent_push_pop() {
    let queue = Arc::new(MPSCQueue::<u64>::new());
    let num_producers = 8;
    let items_per_producer = 10000;

    // Spawn multiple producers
    let mut producer_handles = Vec::new();
    for producer_id in 0..num_producers {
        let queue_clone = Arc::clone(&queue);
        let handle = thread::spawn(move || {
            for i in 0..items_per_producer {
                let value = producer_id * items_per_producer + i;
                queue_clone.push(value);
            }
        });
        producer_handles.push(handle);
    }

    // Consumer thread
    let queue_consumer = Arc::clone(&queue);
    let consumer_handle = thread::spawn(move || {
        let mut received = Vec::new();
        let expected_total = (num_producers * items_per_producer) as usize;

        while received.len() < expected_total {
            if let Some(item) = queue_consumer.try_pop() {
                received.push(item);
            } else {
                thread::yield_now();
            }
        }
        received
    });

    // Wait for producers
    for handle in producer_handles {
        handle.join().expect("Producer thread failed");
    }

    // Wait for consumer
    let received = consumer_handle.join().expect("Consumer thread failed");

    // Verify all items received
    assert_eq!(
        received.len(),
        (num_producers * items_per_producer) as usize
    );

    // Verify queue is empty
    assert!(queue.is_empty());
}

#[test]
fn test_mpsc_queue_pop_from_empty() {
    let queue = MPSCQueue::<u64>::new();

    // Multiple pops from empty queue should return None
    assert_eq!(queue.try_pop(), None);
    assert_eq!(queue.try_pop(), None);
    assert_eq!(queue.try_pop(), None);

    assert!(queue.is_empty());
}

#[test]
fn test_mpsc_queue_push_pop_interleaved() {
    let queue = MPSCQueue::<u64>::new();

    // Interleave push and pop operations
    queue.push(1);
    assert_eq!(queue.try_pop(), Some(1));

    queue.push(2);
    queue.push(3);
    assert_eq!(queue.try_pop(), Some(2));

    queue.push(4);
    assert_eq!(queue.try_pop(), Some(3));
    assert_eq!(queue.try_pop(), Some(4));

    assert!(queue.is_empty());
}

#[test]
fn test_mpsc_queue_rapid_push() {
    let queue = Arc::new(MPSCQueue::<u64>::new());
    let queue_clone = Arc::clone(&queue);

    // Rapidly push 100,000 items
    let handle = thread::spawn(move || {
        for i in 0..100_000 {
            queue_clone.push(i);
        }
    });

    handle.join().expect("Producer thread failed");

    // Verify count
    assert_eq!(queue.len(), 100_000);

    // Pop all items and verify order
    let mut prev = None;
    let mut count = 0;

    while let Some(item) = queue.try_pop() {
        if let Some(p) = prev {
            assert_eq!(item, p + 1, "Items should be in order");
        }
        prev = Some(item);
        count += 1;
    }

    assert_eq!(count, 100_000);
}

#[test]
fn test_mpsc_queue_size_tracking() {
    let queue = MPSCQueue::<u64>::new();

    assert_eq!(queue.len(), 0);
    assert!(queue.is_empty());

    queue.push(1);
    assert_eq!(queue.len(), 1);
    assert!(!queue.is_empty());

    queue.push(2);
    queue.push(3);
    assert_eq!(queue.len(), 3);

    queue.try_pop();
    assert_eq!(queue.len(), 2);

    queue.try_pop();
    queue.try_pop();
    assert_eq!(queue.len(), 0);
    assert!(queue.is_empty());
}

// ============================================================================
// Atomic Counter Edge Cases
// ============================================================================

#[test]
fn test_atomic_counter_custom_increment() {
    let counter = AtomicCounter::new_with(100, 5);

    assert_eq!(counter.get(), 100);
    assert_eq!(counter.next(), 100);
    assert_eq!(counter.next(), 105);
    assert_eq!(counter.next(), 110);
    assert_eq!(counter.get(), 115);
}

#[test]
fn test_atomic_counter_reset() {
    let counter = AtomicCounter::new();

    counter.next();
    counter.next();
    counter.next();
    assert_eq!(counter.get(), 3);

    counter.reset(0);
    assert_eq!(counter.get(), 0);
    assert_eq!(counter.next(), 0);
}

#[test]
fn test_atomic_counter_add() {
    let counter = AtomicCounter::new();

    assert_eq!(counter.add(10), 0); // Returns old value
    assert_eq!(counter.get(), 10);

    assert_eq!(counter.add(5), 10); // Returns old value
    assert_eq!(counter.get(), 15);
}

#[test]
fn test_atomic_counter_concurrent_increments() {
    let counter = Arc::new(AtomicCounter::new());
    let num_threads = 16;
    let increments_per_thread = 10000;

    let mut handles = Vec::new();

    for _ in 0..num_threads {
        let counter_clone: Arc<AtomicCounter> = Arc::clone(&counter);
        let handle = thread::spawn(move || {
            for _ in 0..increments_per_thread {
                counter_clone.next();
            }
        });
        handles.push(handle);
    }

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

    // Final value should be num_threads * increments_per_thread
    assert_eq!(counter.get(), (num_threads * increments_per_thread) as u64);
}

#[test]
fn test_atomic_counter_wraparound() {
    let counter = AtomicCounter::new_with(u64::MAX - 5, 1);

    assert_eq!(counter.next(), u64::MAX - 5);
    assert_eq!(counter.next(), u64::MAX - 4);
    assert_eq!(counter.next(), u64::MAX - 3);
    assert_eq!(counter.next(), u64::MAX - 2);
    assert_eq!(counter.next(), u64::MAX - 1);
    assert_eq!(counter.next(), u64::MAX);
    // Next increment will wrap around to 0
    assert_eq!(counter.next(), 0);
}

#[test]
fn test_mpsc_queue_debug_output() {
    let queue = MPSCQueue::<u64>::new();
    queue.push(1);
    queue.push(2);

    let debug_str = format!("{:?}", queue);
    assert!(debug_str.contains("MPSCQueue"));
    assert!(debug_str.contains("size"));
}

#[test]
fn test_atomic_counter_debug_output() {
    let counter = AtomicCounter::new_with(42, 5);

    let debug_str = format!("{:?}", counter);
    assert!(debug_str.contains("AtomicCounter"));
    assert!(debug_str.contains("42"));
}

#[test]
fn test_mpsc_queue_with_large_items() {
    let queue = MPSCQueue::<Vec<u64>>::new();

    // Push large vectors
    for i in 0..100 {
        let vec = vec![i; 1000]; // 1000 elements each
        queue.push(vec);
    }

    // Pop and verify
    let mut count = 0;
    while let Some(vec) = queue.try_pop() {
        assert_eq!(vec.len(), 1000);
        assert_eq!(vec[0], count);
        count += 1;
    }

    assert_eq!(count, 100);
}
