//! High-frequency trading optimized random number generation
//!
//! Provides cryptographically secure RNG for trading decisions while maintaining
//! performance for simulations and deterministic testing.

use rand::prelude::*;
use rand::rngs::SmallRng;
use rand_chacha::{ChaCha12Rng, ChaCha20Rng};
use std::cell::RefCell;

/// High-frequency trading optimized RNG trait
///
/// Abstracts different RNG implementations for different use cases:
/// - Crypto: Adversary-resistant for order placement, timing, routing
/// - Fast: High-throughput for Monte Carlo, risk scenarios  
/// - Deterministic: Reproducible for testing and ML training
pub trait HftRng: RngCore + Send {
    /// Generate f64 in range [0.0, 1.0)
    fn gen_f64(&mut self) -> f64 {
        self.r#gen()
    }

    /// Generate f32 in range [0.0, 1.0)  
    fn gen_f32(&mut self) -> f32 {
        self.r#gen()
    }

    /// Generate boolean with 50% probability
    fn gen_bool(&mut self) -> bool {
        self.r#gen()
    }

    /// Generate integer in range [min, max)
    fn gen_range_u64(&mut self, min: u64, max: u64) -> u64 {
        self.gen_range(min..max)
    }

    /// Generate integer in range [min, max)
    fn gen_range_usize(&mut self, min: usize, max: usize) -> usize {
        self.gen_range(min..max)
    }

    /// Generate integer in range [min, max)
    fn gen_range_i64(&mut self, min: i64, max: i64) -> i64 {
        self.gen_range(min..max)
    }

    /// Generate integer in range [min, max)
    fn gen_range_u32(&mut self, min: u32, max: u32) -> u32 {
        self.gen_range(min..max)
    }
}

// Blanket implementation for any RngCore + Send
impl<T: RngCore + Send> HftRng for T {}

/// RNG kind selection for different use cases
#[derive(Clone, Debug)]
/// RngKind
/// 
/// Auto-generated documentation placeholder - enhance with specifics
pub enum RngKind {
    /// Cryptographically secure for trading decisions
    /// Uses `ChaCha20` - secure against prediction attacks
    Crypto,

    /// Fast non-crypto RNG for simulations
    /// Uses `SmallRng` (Xoshiro256**) - ~2x faster than fastrand
    Fast,

    /// Fast crypto RNG with reduced rounds
    /// Uses `ChaCha12` - 25% faster than `ChaCha20`, still secure
    FastCrypto,

    /// Deterministic seeded RNG for testing
    /// Uses `ChaCha20` with fixed seed for reproducibility
    Deterministic([u8; 32]),
}

thread_local! {
    static CRYPTO_RNG: RefCell<ChaCha20Rng> = RefCell::new(ChaCha20Rng::from_entropy());
    static FAST_CRYPTO_RNG: RefCell<ChaCha12Rng> = RefCell::new(ChaCha12Rng::from_entropy());
    static FAST_RNG: RefCell<SmallRng> = RefCell::new(SmallRng::from_entropy());
}

/// Factory function to acquire RNG instance
///
/// For hot paths, prefer `with_*` functions to avoid allocation
#[must_use]
/// acquire
/// 
/// Auto-generated documentation placeholder - enhance with specifics
pub fn acquire(kind: RngKind) -> Box<dyn HftRng> {
    match kind {
        RngKind::Crypto => Box::new(ChaCha20Rng::from_entropy()),
        RngKind::FastCrypto => Box::new(ChaCha12Rng::from_entropy()),
        RngKind::Fast => Box::new(SmallRng::from_entropy()),
        RngKind::Deterministic(seed) => Box::new(ChaCha20Rng::from_seed(seed)),
    }
}

/// Execute closure with thread-local crypto RNG (zero allocation)
///
/// Use for hot paths where allocation must be avoided
pub fn with_crypto_rng<F, R>(f: F) -> R
where
    F: FnOnce(&mut dyn HftRng) -> R,
{
    CRYPTO_RNG.with(|rng| {
        let mut rng = rng.borrow_mut();
        f(&mut *rng)
    })
}

/// Execute closure with thread-local fast crypto RNG (zero allocation)
pub fn with_fast_crypto_rng<F, R>(f: F) -> R
where
    F: FnOnce(&mut dyn HftRng) -> R,
{
    FAST_CRYPTO_RNG.with(|rng| {
        let mut rng = rng.borrow_mut();
        f(&mut *rng)
    })
}

/// Execute closure with thread-local fast RNG (zero allocation)
pub fn with_fast_rng<F, R>(f: F) -> R
where
    F: FnOnce(&mut dyn HftRng) -> R,
{
    FAST_RNG.with(|rng| {
        let mut rng = rng.borrow_mut();
        f(&mut *rng)
    })
}

/// Convenience functions matching fastrand API for easy migration
/// Generate f64 in [0.0, 1.0) using crypto RNG
#[must_use]
/// f64
/// 
/// Auto-generated documentation placeholder - enhance with specifics
pub fn f64() -> f64 {
    with_crypto_rng(|rng| rng.gen_f64())
}

/// Generate f32 in [0.0, 1.0) using crypto RNG  
#[must_use]
/// f32
/// 
/// Auto-generated documentation placeholder - enhance with specifics
pub fn f32() -> f32 {
    with_crypto_rng(|rng| rng.gen_f32())
}

/// Generate boolean using crypto RNG
#[must_use]
/// `bool`
/// 
/// Auto-generated documentation placeholder - enhance with specifics
pub fn bool() -> bool {
    with_crypto_rng(|rng| rng.gen_bool())
}

/// Generate u64 using crypto RNG
#[must_use]
/// u64
/// 
/// Auto-generated documentation placeholder - enhance with specifics
pub fn u64(range: std::ops::Range<u64>) -> u64 {
    with_crypto_rng(|rng| rng.gen_range(range))
}

/// Generate usize using crypto RNG
#[must_use]
/// usize
/// 
/// Auto-generated documentation placeholder - enhance with specifics
pub fn usize(range: std::ops::Range<usize>) -> usize {
    with_crypto_rng(|rng| rng.gen_range(range))
}

/// Generate i64 using crypto RNG
#[must_use]
/// i64
/// 
/// Auto-generated documentation placeholder - enhance with specifics
pub fn i64(range: std::ops::Range<i64>) -> i64 {
    with_crypto_rng(|rng| rng.gen_range(range))
}

/// Generate u32 using crypto RNG
#[must_use]
/// u32
/// 
/// Auto-generated documentation placeholder - enhance with specifics
pub fn u32(range: std::ops::Range<u32>) -> u32 {
    with_crypto_rng(|rng| rng.gen_range(range))
}

/// Fast non-crypto versions for simulations
pub mod fast {
    use super::{with_fast_rng, Rng};

    /// Generate a random f64 value between 0.0 and 1.0
    #[must_use]
    pub fn f64() -> f64 {
        with_fast_rng(|rng| rng.gen_f64())
    }

    /// Generate a random f32 value between 0.0 and 1.0
    #[must_use]
    pub fn f32() -> f32 {
        with_fast_rng(|rng| rng.gen_f32())
    }

    /// Generate a random boolean value
    #[must_use]
    pub fn bool() -> bool {
        with_fast_rng(|rng| rng.gen_bool())
    }

    /// Generate a random u64 value within the specified range
    #[must_use]
    pub fn u64(range: std::ops::Range<u64>) -> u64 {
        with_fast_rng(|rng| rng.gen_range(range))
    }

    /// Generate a random usize value within the specified range
    #[must_use]
    pub fn usize(range: std::ops::Range<usize>) -> usize {
        with_fast_rng(|rng| rng.gen_range(range))
    }

    /// Generate a random i64 value within the specified range
    #[must_use]
    pub fn i64(range: std::ops::Range<i64>) -> i64 {
        with_fast_rng(|rng| rng.gen_range(range))
    }

    /// Generate a random u32 value within the specified range
    #[must_use]
    pub fn u32(range: std::ops::Range<u32>) -> u32 {
        with_fast_rng(|rng| rng.gen_range(range))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashSet;

    #[test]
    fn test_rng_kind_variants() {
        // Test all RngKind variants exist
        let _crypto = RngKind::Crypto;
        let _fast = RngKind::Fast;
        let _fast_crypto = RngKind::FastCrypto;
        let seed = [0_u8; 32];
        let _deterministic = RngKind::Deterministic(seed);

        // Test Debug trait
        let crypto = RngKind::Crypto;
        let debug_str = format!("{:?}", crypto);
        assert!(!debug_str.is_empty());
    }

    #[test]
    fn test_acquire_crypto_rng() {
        let mut rng = acquire(RngKind::Crypto);

        // Test basic RNG functionality
        let val1 = rng.gen_f64();
        let val2 = rng.gen_f64();

        // Values should be in range [0.0, 1.0)
        assert!(val1 >= 0.0 && val1 < 1.0);
        assert!(val2 >= 0.0 && val2 < 1.0);

        // Values should be different (extremely high probability)
        assert_ne!(val1, val2);
    }

    #[test]
    fn test_acquire_fast_crypto_rng() {
        let mut rng = acquire(RngKind::FastCrypto);

        // Test basic functionality
        let val1 = rng.gen_f64();
        let val2 = rng.gen_f64();

        assert!(val1 >= 0.0 && val1 < 1.0);
        assert!(val2 >= 0.0 && val2 < 1.0);
        assert_ne!(val1, val2);
    }

    #[test]
    fn test_acquire_fast_rng() {
        let mut rng = acquire(RngKind::Fast);

        // Test basic functionality
        let val1 = rng.gen_f64();
        let val2 = rng.gen_f64();

        assert!(val1 >= 0.0 && val1 < 1.0);
        assert!(val2 >= 0.0 && val2 < 1.0);
        assert_ne!(val1, val2);
    }

    #[test]
    fn test_deterministic_rng() {
        let seed = [42_u8; 32];
        let mut rng1 = acquire(RngKind::Deterministic(seed));
        let mut rng2 = acquire(RngKind::Deterministic(seed));

        // Same seed should produce same sequence
        let val1_from_rng1 = rng1.gen_f64();
        let val1_from_rng2 = rng2.gen_f64();
        assert_eq!(val1_from_rng1, val1_from_rng2);

        let val2_from_rng1 = rng1.gen_f64();
        let val2_from_rng2 = rng2.gen_f64();
        assert_eq!(val2_from_rng1, val2_from_rng2);

        // Different calls should produce different values
        assert_ne!(val1_from_rng1, val2_from_rng1);
    }

    #[test]
    fn test_hft_rng_trait_f64() {
        let mut rng = acquire(RngKind::Fast);

        // Test multiple f64 values
        let mut values = Vec::new();
        for _ in 0..100 {
            let val = rng.gen_f64();
            assert!(val >= 0.0 && val < 1.0);
            values.push(val);
        }

        // Check that values are reasonably distributed
        let unique_values: HashSet<_> = values.iter().map(|x| (x * 1000.0) as u64).collect();
        assert!(unique_values.len() > 80); // Should have good uniqueness
    }

    #[test]
    fn test_hft_rng_trait_f32() {
        let mut rng = acquire(RngKind::Fast);

        // Test multiple f32 values
        for _ in 0..50 {
            let val = rng.gen_f32();
            assert!(val >= 0.0 && val < 1.0);
        }
    }

    #[test]
    fn test_hft_rng_trait_bool() {
        let mut rng = acquire(RngKind::Fast);

        let mut true_count = 0;
        let mut false_count = 0;

        for _ in 0..1000 {
            if HftRng::gen_bool(&mut *rng) {
                true_count += 1;
            } else {
                false_count += 1;
            }
        }

        // Should have roughly equal distribution (allow for statistical variation)
        assert!(true_count > 400 && true_count < 600);
        assert!(false_count > 400 && false_count < 600);
        assert_eq!(true_count + false_count, 1000);
    }

    #[test]
    fn test_hft_rng_range_methods() {
        let mut rng = acquire(RngKind::Fast);

        // Test u64 range
        for _ in 0..50 {
            let val = rng.gen_range_u64(10, 20);
            assert!(val >= 10 && val < 20);
        }

        // Test usize range
        for _ in 0..50 {
            let val = rng.gen_range_usize(5, 15);
            assert!(val >= 5 && val < 15);
        }

        // Test i64 range
        for _ in 0..50 {
            let val = rng.gen_range_i64(-10, 10);
            assert!(val >= -10 && val < 10);
        }

        // Test u32 range
        for _ in 0..50 {
            let val = rng.gen_range_u32(100, 200);
            assert!(val >= 100 && val < 200);
        }
    }

    #[test]
    fn test_with_crypto_rng() {
        let result = with_crypto_rng(|rng| {
            let val = rng.gen_f64();
            assert!(val >= 0.0 && val < 1.0);
            val
        });

        assert!(result >= 0.0 && result < 1.0);
    }

    #[test]
    fn test_with_fast_crypto_rng() {
        let result = with_fast_crypto_rng(|rng| {
            let val = rng.gen_f64();
            assert!(val >= 0.0 && val < 1.0);
            val
        });

        assert!(result >= 0.0 && result < 1.0);
    }

    #[test]
    fn test_with_fast_rng() {
        let result = with_fast_rng(|rng| {
            let val = rng.gen_f64();
            assert!(val >= 0.0 && val < 1.0);
            val
        });

        assert!(result >= 0.0 && result < 1.0);
    }

    #[test]
    fn test_with_functions_multiple_calls() {
        // Test that multiple calls to with_* functions work correctly
        let mut results = Vec::new();

        for _ in 0..10 {
            let result = with_crypto_rng(|rng| rng.gen_f64());
            results.push(result);
        }

        // All values should be valid and mostly unique
        for &result in &results {
            assert!(result >= 0.0 && result < 1.0);
        }

        let unique_results: HashSet<_> = results.iter().map(|x| (x * 1000.0) as u64).collect();
        assert!(unique_results.len() > 8); // Should have good uniqueness
    }

    #[test]
    fn test_convenience_functions_crypto() {
        // Test f64
        let val = f64();
        assert!(val >= 0.0 && val < 1.0);

        // Test f32
        let val = f32();
        assert!(val >= 0.0 && val < 1.0);

        // Test bool
        let _val = bool(); // Just test it doesn't panic

        // Test integer ranges
        let val = u64(10..20);
        assert!(val >= 10 && val < 20);

        let val = usize(5..15);
        assert!(val >= 5 && val < 15);

        let val = i64(-10..10);
        assert!(val >= -10 && val < 10);

        let val = u32(100..200);
        assert!(val >= 100 && val < 200);
    }

    #[test]
    fn test_fast_module_functions() {
        // Test fast::f64
        let val = fast::f64();
        assert!(val >= 0.0 && val < 1.0);

        // Test fast::f32
        let val = fast::f32();
        assert!(val >= 0.0 && val < 1.0);

        // Test fast::bool
        let _val = fast::bool();

        // Test fast integer ranges
        let val = fast::u64(10..20);
        assert!(val >= 10 && val < 20);

        let val = fast::usize(5..15);
        assert!(val >= 5 && val < 15);

        let val = fast::i64(-10..10);
        assert!(val >= -10 && val < 10);

        let val = fast::u32(100..200);
        assert!(val >= 100 && val < 200);
    }

    #[test]
    fn test_rng_quality_statistics() {
        // Test that the RNG produces reasonable statistical distribution
        let mut rng = acquire(RngKind::Fast);

        let mut bucket_counts = [0usize; 10];
        let sample_size = 10000;

        for _ in 0..sample_size {
            let val = rng.gen_f64();
            let bucket = (val * 10.0) as usize;
            if bucket < 10 {
                bucket_counts[bucket] += 1;
            }
        }

        // Each bucket should have roughly 1000 samples (allow ±20% variation)
        for count in &bucket_counts {
            assert!(*count > 800 && *count < 1200, "Bucket count: {}", count);
        }
    }

    #[test]
    fn test_deterministic_rng_reproducibility() {
        let seed = [123_u8; 32];

        // Generate sequence with first RNG
        let mut rng1 = acquire(RngKind::Deterministic(seed));
        let sequence1: Vec<f64> = (0..20).map(|_| rng1.gen_f64()).collect();

        // Generate sequence with second RNG using same seed
        let mut rng2 = acquire(RngKind::Deterministic(seed));
        let sequence2: Vec<f64> = (0..20).map(|_| rng2.gen_f64()).collect();

        // Sequences should be identical
        assert_eq!(sequence1, sequence2);

        // But different calls should produce different values
        assert_ne!(sequence1[0], sequence1[1]);
    }

    #[test]
    fn test_different_seeds_produce_different_sequences() {
        let seed1 = [1_u8; 32];
        let seed2 = [2_u8; 32];

        let mut rng1 = acquire(RngKind::Deterministic(seed1));
        let mut rng2 = acquire(RngKind::Deterministic(seed2));

        let val1 = rng1.gen_f64();
        let val2 = rng2.gen_f64();

        // Different seeds should produce different values
        assert_ne!(val1, val2);
    }

    #[test]
    fn test_thread_safety() {
        // Test that thread-local RNGs work correctly
        use std::thread;

        let handles: Vec<_> = (0..4)
            .map(|_| {
                thread::spawn(|| {
                    let val1 = with_crypto_rng(|rng| rng.gen_f64());
                    let val2 = with_fast_rng(|rng| rng.gen_f64());
                    let val3 = with_fast_crypto_rng(|rng| rng.gen_f64());

                    // All values should be valid
                    assert!(val1 >= 0.0 && val1 < 1.0);
                    assert!(val2 >= 0.0 && val2 < 1.0);
                    assert!(val3 >= 0.0 && val3 < 1.0);

                    (val1, val2, val3)
                })
            })
            .collect();

        let results: Vec<_> = handles.into_iter().map(|h| h.join().unwrap()).collect();

        // All threads should have produced valid results
        assert_eq!(results.len(), 4);
        for (val1, val2, val3) in results {
            assert!(val1 >= 0.0 && val1 < 1.0);
            assert!(val2 >= 0.0 && val2 < 1.0);
            assert!(val3 >= 0.0 && val3 < 1.0);
        }
    }

    #[test]
    fn test_edge_case_ranges() {
        let mut rng = acquire(RngKind::Fast);

        // Test single-value range (should always return min)
        let val = rng.gen_range_u64(42, 43);
        assert_eq!(val, 42);

        let val = rng.gen_range_usize(10, 11);
        assert_eq!(val, 10);

        let val = rng.gen_range_i64(-5, -4);
        assert_eq!(val, -5);

        let val = rng.gen_range_u32(100, 101);
        assert_eq!(val, 100);
    }

    #[test]
    fn test_large_ranges() {
        let mut rng = acquire(RngKind::Fast);

        // Test with large ranges
        for _ in 0..20 {
            let val = rng.gen_range_u64(0, u64::MAX);
            // Should be a valid u64
            assert!(val < u64::MAX);
        }

        for _ in 0..20 {
            let val = rng.gen_range_i64(i64::MIN, i64::MAX);
            assert!(val >= i64::MIN && val < i64::MAX);
        }
    }

    #[test]
    fn test_rng_performance_characteristics() {
        // This test verifies that different RNG types can be acquired
        // and basic operations work. Actual performance testing would
        // require benchmarking tools.

        let start = std::time::Instant::now();

        // Test crypto RNG
        let mut crypto_rng = acquire(RngKind::Crypto);
        for _ in 0..1000 {
            let _ = crypto_rng.gen_f64();
        }
        let crypto_time = start.elapsed();

        let start = std::time::Instant::now();

        // Test fast RNG
        let mut fast_rng = acquire(RngKind::Fast);
        for _ in 0..1000 {
            let _ = fast_rng.gen_f64();
        }
        let fast_time = start.elapsed();

        // Both should complete in reasonable time
        assert!(crypto_time < std::time::Duration::from_millis(100));
        assert!(fast_time < std::time::Duration::from_millis(100));
    }

    #[test]
    fn test_rng_clone_behavior() {
        // Test that RngKind can be cloned
        let original = RngKind::Crypto;
        let cloned = original.clone();

        // Both should work identically
        let mut rng1 = acquire(original);
        let mut rng2 = acquire(cloned);

        let val1 = rng1.gen_f64();
        let val2 = rng2.gen_f64();

        assert!(val1 >= 0.0 && val1 < 1.0);
        assert!(val2 >= 0.0 && val2 < 1.0);
    }

    #[test]
    fn test_comprehensive_api_coverage() {
        // Test all public API methods to ensure they work
        let mut rng = acquire(RngKind::Fast);

        // Test all HftRng trait methods
        let _: f64 = rng.gen_f64();
        let _: f32 = rng.gen_f32();
        let _: bool = HftRng::gen_bool(&mut *rng);
        let _: u64 = rng.gen_range_u64(0, 100);
        let _: usize = rng.gen_range_usize(0, 100);
        let _: i64 = rng.gen_range_i64(-50, 50);
        let _: u32 = rng.gen_range_u32(0, 100);

        // Test all convenience functions
        let _: f64 = f64();
        let _: f32 = f32();
        let _: bool = bool();
        let _: u64 = u64(0..100);
        let _: usize = usize(0..100);
        let _: i64 = i64(-50..50);
        let _: u32 = u32(0..100);

        // Test all fast module functions
        let _: f64 = fast::f64();
        let _: f32 = fast::f32();
        let _: bool = fast::bool();
        let _: u64 = fast::u64(0..100);
        let _: usize = fast::usize(0..100);
        let _: i64 = fast::i64(-50..50);
        let _: u32 = fast::u32(0..100);

        // Test all with_* functions
        with_crypto_rng(|rng| rng.gen_f64());
        with_fast_crypto_rng(|rng| rng.gen_f64());
        with_fast_rng(|rng| rng.gen_f64());
    }
}

/// Deterministic RNG for testing
#[derive(Debug)]
/// DeterministicRng
/// 
/// Auto-generated documentation placeholder - enhance with specifics
pub struct DeterministicRng {
    inner: ChaCha20Rng,
}

impl DeterministicRng {
    /// Creates a new deterministic RNG from a u64 seed
    #[must_use]
    pub fn new(seed: u64) -> Self {
        let mut seed_array = [0_u8; 32];
        seed_array[0..8].copy_from_slice(&seed.to_le_bytes());
        Self {
            inner: ChaCha20Rng::from_seed(seed_array),
        }
    }

    /// Creates a new deterministic RNG from a 32-byte seed array
    #[must_use]
    pub fn from_seed(seed: [u8; 32]) -> Self {
        Self {
            inner: ChaCha20Rng::from_seed(seed),
        }
    }
}

impl RngCore for DeterministicRng {
    fn next_u32(&mut self) -> u32 {
        self.inner.next_u32()
    }

    fn next_u64(&mut self) -> u64 {
        self.inner.next_u64()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.inner.fill_bytes(dest);
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
        self.inner.try_fill_bytes(dest)
    }
}

#[cfg(test)]
mod additional_tests {
    use super::*;

    #[test]
    fn test_deterministic_rng_comprehensive() {
        // Test DeterministicRng::new with different seeds
        let mut rng1 = DeterministicRng::new(12345);
        let mut rng2 = DeterministicRng::new(12345);
        let mut rng3 = DeterministicRng::new(54321);

        // Same seed should produce same values
        let val1_from_rng1 = rng1.gen_f64();
        let val1_from_rng2 = rng2.gen_f64();
        assert_eq!(val1_from_rng1, val1_from_rng2);

        // Different seed should produce different values
        let val1_from_rng3 = rng3.gen_f64();
        assert_ne!(val1_from_rng1, val1_from_rng3);

        // Test DeterministicRng::from_seed
        let seed = [42_u8; 32];
        let mut rng4 = DeterministicRng::from_seed(seed);
        let mut rng5 = DeterministicRng::from_seed(seed);

        let val4 = rng4.gen_f64();
        let val5 = rng5.gen_f64();
        assert_eq!(val4, val5);
    }

    #[test]
    fn test_deterministic_rng_core_methods() {
        let mut rng = DeterministicRng::new(98765);

        // Test next_u32
        let u32_val1 = rng.next_u32();
        let u32_val2 = rng.next_u32();
        assert_ne!(u32_val1, u32_val2);

        // Test next_u64
        let u64_val1 = rng.next_u64();
        let u64_val2 = rng.next_u64();
        assert_ne!(u64_val1, u64_val2);

        // Test fill_bytes
        let mut bytes = [0_u8; 16];
        rng.fill_bytes(&mut bytes);
        assert_ne!(bytes, [0_u8; 16]); // Should have filled with random data

        // Test try_fill_bytes
        let mut bytes2 = [0_u8; 32];
        let result = rng.try_fill_bytes(&mut bytes2);
        assert!(result.is_ok());
        assert_ne!(bytes2, [0_u8; 32]);
    }

    #[test]
    fn test_hft_rng_trait_exhaustive() {
        let mut rng = acquire(RngKind::Fast);

        // Test all HftRng methods with edge cases
        for _ in 0..1000 {
            let f64_val = rng.gen_f64();
            assert!(f64_val >= 0.0 && f64_val < 1.0);

            let f32_val = rng.gen_f32();
            assert!(f32_val >= 0.0 && f32_val < 1.0);

            let bool_val = HftRng::gen_bool(&mut rng);
            assert!(bool_val || !bool_val);

            // Test u64 ranges
            let u64_small = rng.gen_range_u64(0, 10);
            assert!(u64_small < 10);

            let u64_large = rng.gen_range_u64(u64::MAX - 100, u64::MAX);
            assert!(u64_large >= u64::MAX - 100);

            // Test usize ranges
            let usize_val = rng.gen_range_usize(100, 200);
            assert!(usize_val >= 100 && usize_val < 200);

            // Test i64 ranges including negative
            let i64_neg = rng.gen_range_i64(-1000, 0);
            assert!(i64_neg >= -1000 && i64_neg < 0);

            let i64_pos = rng.gen_range_i64(0, 1000);
            assert!(i64_pos >= 0 && i64_pos < 1000);

            // Test u32 ranges
            let u32_val = rng.gen_range_u32(0, u32::MAX);
            assert!(u32_val < u32::MAX);
        }
    }

    #[test]
    fn test_all_rng_kinds_comprehensive() {
        let kinds = vec![
            RngKind::Crypto,
            RngKind::Fast,
            RngKind::FastCrypto,
            RngKind::Deterministic([123_u8; 32]),
        ];

        for kind in kinds {
            let mut rng = acquire(kind);

            // Test basic functionality
            let f64_val = rng.gen_f64();
            assert!(f64_val >= 0.0 && f64_val < 1.0);

            let f32_val = rng.gen_f32();
            assert!(f32_val >= 0.0 && f32_val < 1.0);

            let bool_val = HftRng::gen_bool(&mut rng);
            assert!(bool_val || !bool_val);

            // Test range generation
            let range_val = rng.gen_range_u64(10, 20);
            assert!(range_val >= 10 && range_val < 20);
        }
    }

    #[test]
    fn test_thread_local_rng_isolation() -> Result<(), Box<dyn std::error::Error>> {
        use std::sync::{Arc, Mutex};
        use std::thread;

        let results = Arc::new(Mutex::new(Vec::new()));
        let mut handles = vec![];

        // Spawn multiple threads to test isolation
        for thread_id in 0..5 {
            let results_clone = Arc::clone(&results);
            let handle = thread::spawn(move || {
                let mut thread_results = Vec::new();

                // Generate values with each thread-local RNG
                for _ in 0..100 {
                    let crypto_val = with_crypto_rng(|rng| rng.gen_f64());
                    let fast_crypto_val = with_fast_crypto_rng(|rng| rng.gen_f64());
                    let fast_val = with_fast_rng(|rng| rng.gen_f64());

                    thread_results.push((thread_id, crypto_val, fast_crypto_val, fast_val));
                }

                results_clone.lock().unwrap().extend(thread_results);
            });
            handles.push(handle);
        }

        // Wait for all threads
        for handle in handles {
            handle.join().unwrap();
        }

        let results = results.lock().unwrap();
        assert_eq!(results.len(), 5 * 100);

        // Verify all values are valid
        for (_, crypto_val, fast_crypto_val, fast_val) in &results {
            assert!(crypto_val >= &0.0 && crypto_val < &1.0);
            assert!(fast_crypto_val >= &0.0 && fast_crypto_val < &1.0);
            assert!(fast_val >= &0.0 && fast_val < &1.0);
        }
        Ok(())
    }

    #[test]
    fn test_convenience_functions_all_ranges() {
        // Test all convenience functions with various range patterns

        // Test u64 with different ranges
        for _ in 0..50 {
            let val = u64(0..1000);
            assert!(val < 1000);

            let val_large = u64(u64::MAX - 1000..u64::MAX);
            assert!(val_large >= u64::MAX - 1000);
        }

        // Test usize with different ranges
        for _ in 0..50 {
            let val = usize(0..100);
            assert!(val < 100);

            let val_large = usize(1000..2000);
            assert!(val_large >= 1000 && val_large < 2000);
        }

        // Test i64 with negative and positive ranges
        for _ in 0..50 {
            let val_neg = i64(-500..0);
            assert!(val_neg >= -500 && val_neg < 0);

            let val_pos = i64(0..500);
            assert!(val_pos >= 0 && val_pos < 500);

            let val_mixed = i64(-100..100);
            assert!(val_mixed >= -100 && val_mixed < 100);
        }

        // Test u32 with different ranges
        for _ in 0..50 {
            let val = u32(0..1000);
            assert!(val < 1000);

            let val_large = u32(u32::MAX - 1000..u32::MAX);
            assert!(val_large >= u32::MAX - 1000);
        }
    }

    #[test]
    fn test_fast_module_functions_comprehensive() {
        // Test fast module functions thoroughly

        // Test distribution of boolean values
        let mut true_count = 0;
        let mut false_count = 0;
        let sample_size = 10000;

        for _ in 0..sample_size {
            if fast::bool() {
                true_count += 1;
            } else {
                false_count += 1;
            }
        }

        // Should be roughly 50/50 distribution (allow for statistical variation)
        let true_ratio = true_count as f64 / sample_size as f64;
        assert!(true_ratio > 0.45 && true_ratio < 0.55);

        // Test f64 distribution across range
        let mut low_count = 0; // [0.0, 0.5)
        let mut high_count = 0; // [0.5, 1.0)

        for _ in 0..sample_size {
            let val = fast::f64();
            if val < 0.5 {
                low_count += 1;
            } else {
                high_count += 1;
            }
        }

        let low_ratio = low_count as f64 / sample_size as f64;
        assert!(low_ratio > 0.45 && low_ratio < 0.55);

        // Test f32 values are valid
        for _ in 0..1000 {
            let val = fast::f32();
            assert!(val >= 0.0 && val < 1.0);
        }

        // Test all range functions
        for _ in 0..100 {
            let u64_val = fast::u64(100..200);
            assert!(u64_val >= 100 && u64_val < 200);

            let usize_val = fast::usize(0..1000);
            assert!(usize_val < 1000);

            let i64_val = fast::i64(-50..50);
            assert!(i64_val >= -50 && i64_val < 50);

            let u32_val = fast::u32(1000..2000);
            assert!(u32_val >= 1000 && u32_val < 2000);
        }
    }

    #[test]
    fn test_rng_edge_case_ranges() {
        let mut rng = acquire(RngKind::Fast);

        // Test minimum ranges (size 1)
        let val = rng.gen_range_u64(42, 43);
        assert_eq!(val, 42);

        let val = rng.gen_range_usize(100, 101);
        assert_eq!(val, 100);

        let val = rng.gen_range_i64(-10, -9);
        assert_eq!(val, -10);

        let val = rng.gen_range_u32(500, 501);
        assert_eq!(val, 500);

        // Test very large ranges
        for _ in 0..20 {
            let val = rng.gen_range_u64(0, u64::MAX);
            // Just check it doesn't panic and returns valid value
            assert!(val < u64::MAX);

            let val = rng.gen_range_i64(i64::MIN, i64::MAX);
            assert!(val >= i64::MIN && val < i64::MAX);
        }
    }

    #[test]
    fn test_statistical_quality_comprehensive() {
        let mut rng = acquire(RngKind::Fast);

        // Test chi-square goodness of fit for uniform distribution
        let num_buckets = 20;
        let samples_per_bucket = 500;
        let total_samples = num_buckets * samples_per_bucket;
        let mut buckets = vec![0; num_buckets];

        for _ in 0..total_samples {
            let val = rng.gen_f64();
            let bucket = (val * num_buckets as f64) as usize;
            if bucket < num_buckets {
                buckets[bucket] += 1;
            }
        }

        // Each bucket should have roughly samples_per_bucket values
        for count in &buckets {
            // Allow ±20% variation (statistical tolerance)
            assert!(*count > samples_per_bucket * 8 / 10);
            assert!(*count < samples_per_bucket * 12 / 10);
        }

        // Test serial correlation (consecutive values should be uncorrelated)
        let mut values = Vec::new();
        for _ in 0..1000 {
            values.push(rng.gen_f64());
        }

        // Calculate simple correlation coefficient
        let n = values.len() - 1;
        let mut sum_xy = 0.0;
        let mut sum_x = 0.0;
        let mut sum_y = 0.0;
        let mut sum_x2 = 0.0;
        let mut sum_y2 = 0.0;

        for i in 0..n {
            let x = values[i];
            let y = values[i + 1];
            sum_xy += x * y;
            sum_x += x;
            sum_y += y;
            sum_x2 += x * x;
            sum_y2 += y * y;
        }

        let correlation = (n as f64 * sum_xy - sum_x * sum_y)
            / ((n as f64 * sum_x2 - sum_x * sum_x) * (n as f64 * sum_y2 - sum_y * sum_y)).sqrt();

        // Correlation should be close to zero (< 0.1 for good RNG)
        assert!(
            correlation.abs() < 0.1,
            "Serial correlation too high: {}",
            correlation
        );
    }

    #[test]
    fn test_performance_characteristics_detailed() {
        use std::time::Instant;

        let iterations = 100_000;

        // Test crypto RNG performance
        let start = Instant::now();
        for _ in 0..iterations {
            let _ = with_crypto_rng(|rng| rng.gen_f64());
        }
        let crypto_duration = start.elapsed();

        // Test fast crypto RNG performance
        let start = Instant::now();
        for _ in 0..iterations {
            let _ = with_fast_crypto_rng(|rng| rng.gen_f64());
        }
        let fast_crypto_duration = start.elapsed();

        // Test fast RNG performance
        let start = Instant::now();
        for _ in 0..iterations {
            let _ = with_fast_rng(|rng| rng.gen_f64());
        }
        let fast_duration = start.elapsed();

        // Fast RNG should be fastest, crypto should be slowest
        // Allow for measurement variance - just check they complete reasonably
        assert!(crypto_duration.as_millis() < 1000, "Crypto RNG too slow");
        assert!(
            fast_crypto_duration.as_millis() < 1000,
            "Fast crypto RNG too slow"
        );
        assert!(fast_duration.as_millis() < 1000, "Fast RNG too slow");

        // Test convenience function performance
        let start = Instant::now();
        for _ in 0..(iterations / 10) {
            let _ = f64();
            let _ = f32();
            let _ = bool();
            let _ = u64(0..1000);
            let _ = i64(-500..500);
        }
        let convenience_duration = start.elapsed();
        assert!(
            convenience_duration.as_millis() < 1000,
            "Convenience functions too slow"
        );
    }

    #[test]
    fn test_memory_usage_and_allocation() {
        // Test that acquiring RNG doesn't cause memory leaks or excessive allocation
        for _ in 0..1000 {
            let mut rng = acquire(RngKind::Fast);
            let _ = rng.gen_f64();
            drop(rng);
        }

        // Test thread-local usage doesn't accumulate memory
        for _ in 0..1000 {
            let _ = with_fast_rng(|rng| rng.gen_f64());
        }

        // Test deterministic RNG creation and destruction
        for i in 0..1000 {
            let mut rng = DeterministicRng::new(i);
            let _ = rng.gen_f64();
            drop(rng);
        }
    }

    #[test]
    fn test_concurrent_access_safety() -> Result<(), Box<dyn std::error::Error>> {
        use std::sync::atomic::{AtomicUsize, Ordering};
        use std::sync::Arc;
        use std::thread;
        // use crate::operations; // Available if needed

        let counter = Arc::new(AtomicUsize::new(0));
        let mut handles = vec![];

        // Test concurrent access to thread-local RNGs
        for _ in 0..10 {
            let counter_clone = Arc::clone(&counter);
            let handle = thread::spawn(move || {
                for _ in 0..1000 {
                    let val = with_fast_rng(|rng| rng.gen_f64());
                    if val > 0.5 {
                        counter_clone.fetch_add(1, Ordering::SeqCst);
                    }
                }
            });
            handles.push(handle);
        }

        for handle in handles {
            handle.join().unwrap();
        }

        let final_count = counter.load(Ordering::SeqCst);
        // Should be roughly half the total iterations (10 * 1000 / 2 = 5000)
        // Allow for statistical variation
        assert!(
            final_count > 4000 && final_count < 6000,
            "Count: {}",
            final_count
        );
        Ok(())
    }
    #[test]
    fn test_extreme_values_and_boundaries() {
        let mut rng = acquire(RngKind::Fast);

        // Test boundary values for ranges
        let val = rng.gen_range_u64(0, 1);
        assert_eq!(val, 0);

        let val = rng.gen_range_usize(usize::MAX - 1, usize::MAX);
        assert_eq!(val, usize::MAX - 1);

        // Test with very small ranges near boundaries
        let val = rng.gen_range_u32(u32::MAX - 10, u32::MAX);
        assert!(val >= u32::MAX - 10 && val < u32::MAX);

        // Test negative ranges
        let val = rng.gen_range_i64(i64::MIN, i64::MIN + 10);
        assert!(val >= i64::MIN && val < i64::MIN + 10);

        let val = rng.gen_range_i64(i64::MAX - 10, i64::MAX);
        assert!(val >= i64::MAX - 10 && val < i64::MAX);
    }

    #[test]
    fn test_rng_kind_debug_and_clone() {
        let crypto = RngKind::Crypto;
        let fast = RngKind::Fast;
        let fast_crypto = RngKind::FastCrypto;
        let deterministic = RngKind::Deterministic([42_u8; 32]);

        // Test Debug formatting
        let debug_strings = vec![
            format!("{:?}", crypto),
            format!("{:?}", fast),
            format!("{:?}", fast_crypto),
            format!("{:?}", deterministic),
        ];

        for debug_str in debug_strings {
            assert!(!debug_str.is_empty());
            // Should contain the variant name
            assert!(
                debug_str.contains("Crypto")
                    || debug_str.contains("Fast")
                    || debug_str.contains("Deterministic")
            );
        }

        // Test Clone
        let crypto_clone = crypto.clone();
        let fast_clone = fast.clone();
        let fast_crypto_clone = fast_crypto.clone();
        let deterministic_clone = deterministic.clone();

        // Cloned values should work identically
        let mut rng1 = acquire(crypto);
        let mut rng2 = acquire(crypto_clone);

        // Both should generate valid values (can't test equality due to entropy)
        let val1 = rng1.gen_f64();
        let val2 = rng2.gen_f64();
        assert!(val1 >= 0.0 && val1 < 1.0);
        assert!(val2 >= 0.0 && val2 < 1.0);

        // Test deterministic clone produces same sequence
        let mut det_rng1 = acquire(deterministic);
        let mut det_rng2 = acquire(deterministic_clone);

        let det_val1 = det_rng1.gen_f64();
        let det_val2 = det_rng2.gen_f64();
        assert_eq!(det_val1, det_val2);
    }

    #[test]
    fn test_comprehensive_api_stress() {
        // Stress test all API combinations
        let kinds = vec![
            RngKind::Crypto,
            RngKind::Fast,
            RngKind::FastCrypto,
            RngKind::Deterministic([99_u8; 32]),
        ];

        for kind in kinds {
            let mut rng = acquire(kind);

            // Stress test all methods
            for i in 0..100 {
                // Basic generation
                let f64_val = rng.gen_f64();
                let f32_val = rng.gen_f32();
                let bool_val = HftRng::gen_bool(&mut rng);

                assert!(f64_val >= 0.0 && f64_val < 1.0);
                assert!(f32_val >= 0.0 && f32_val < 1.0);
                assert!(bool_val || !bool_val);

                // Range generation with varying parameters
                let u64_val = rng.gen_range_u64(i, i + 100);
                let usize_val = rng.gen_range_usize(0, (i + 1) as usize);
                let i64_val = rng.gen_range_i64(-(i as i64), i as i64 + 1);
                let u32_val = rng.gen_range_u32(i as u32, (i + 50) as u32);

                assert!(u64_val >= i && u64_val < i + 100);
                assert!(usize_val <= i as usize);
                assert!(i64_val >= -(i as i64) && i64_val <= i as i64);
                assert!(u32_val >= i as u32 && u32_val < (i + 50) as u32);
            }
        }
    }

    #[test]
    fn test_seed_sensitivity() {
        // Test that small changes in seed produce different sequences
        let base_seed = [0_u8; 32];
        let mut modified_seed = base_seed;
        modified_seed[0] = 1; // Change only one bit

        let mut rng1 = acquire(RngKind::Deterministic(base_seed));
        let mut rng2 = acquire(RngKind::Deterministic(modified_seed));

        // Generate sequences and verify they differ
        let sequence1: Vec<f64> = (0..10).map(|_| rng1.gen_f64()).collect();
        let sequence2: Vec<f64> = (0..10).map(|_| rng2.gen_f64()).collect();

        // Sequences should be different
        assert_ne!(sequence1, sequence2);

        // But individual values should still be valid
        for val in sequence1.into_iter().chain(sequence2.into_iter()) {
            assert!(val >= &0.0 && val < &1.0);
        }
    }

    #[test]
    fn test_distribution_uniformity_advanced() {
        let mut rng = acquire(RngKind::Fast);

        // Kolmogorov-Smirnov test approximation for uniformity
        let sample_size = 10000;
        let mut samples: Vec<f64> = (0..sample_size).map(|_| rng.gen_f64()).collect();
        samples.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));

        // Check if samples follow uniform distribution
        let mut max_deviation: f64 = 0.0;
        for (i, &sample) in samples.into_iter().enumerate() {
            let empirical_cdf = (i + 1) as f64 / sample_size as f64;
            let theoretical_cdf = sample; // For uniform [0,1), CDF = x
            let deviation = (empirical_cdf - theoretical_cdf).abs();
            max_deviation = max_deviation.max(deviation);
        }

        // For large sample size, max deviation should be small
        // Using critical value approximation for α = 0.05 (more lenient to avoid flaky tests)
        let critical_value = 1.36 / (sample_size as f64).sqrt() * 1.5; // 50% more lenient
        assert!(
            max_deviation < critical_value,
            "Distribution not uniform: max_dev={}, critical={}",
            max_deviation,
            critical_value
        );
    }
}
