//! Test Utilities Module
//!
//! Comprehensive test utilities for safe, reliable testing patterns
//! across the Foxhunt HFT trading system.

pub mod hft_utils;
pub mod test_safety;

// Re-export commonly used items for convenience (macros are exported at crate root)
// DO NOT RE-EXPORT - Use explicit imports at usage sites

// Note: test_assert and test_assert_eq macros are exported at crate root automatically

// DO NOT RE-EXPORT - Use explicit imports at usage sites

/// Macro to create a test with automatic error handling and context
#[macro_export]
macro_rules! safe_test {
    ($test_name:ident, $test_fn:expr) => {
        #[tokio::test]
        async fn $test_name() {
            match $test_fn().await {
                Ok(()) => {},
                Err(e) => {
                    panic!("Test {} failed: {}", stringify!($test_name), e);
                },
            }
        }
    };
}

/// Macro to create a property based test
#[macro_export]
macro_rules! property_test {
    ($test_name:ident, $iterations:expr, $test_fn:expr) => {
        #[tokio::test]
        async fn $test_name() {
            use $crate::utils::test_safety::property;

            match property::run_property_test(stringify!($test_name), $iterations, $test_fn) {
                Ok(()) => {},
                Err(e) => {
                    panic!("Property test {} failed: {}", stringify!($test_name), e);
                },
            }
        }
    };
}

/// Macro to create a performance benchmark test
#[macro_export]
macro_rules! benchmark_test {
    ($test_name:ident, $operation:expr, $max_latency:expr) => {
        #[tokio::test]
        async fn $test_name() {
            use $crate::utils::hft_utils::performance;
            use std::time::Duration;

            let measurements = performance::benchmark_operation(
                $operation,
                10,  // warmup iterations
                100, // measurement iterations
                stringify!($test_name),
            )
            .await
            .expect("Benchmark should complete");

            let avg_latency = measurements.average().expect("Should have measurements");
            let p99_latency = measurements.percentile(0.99).expect("Should have p99");

            println!(
                "Benchmark {}: avg={:?}, p99={:?}, max={:?}",
                stringify!($test_name),
                avg_latency,
                p99_latency,
                measurements.max().unwrap_or_default()
            );

            if avg_latency > $max_latency {
                panic!(
                    "Benchmark {} failed: average latency {:?} exceeds maximum {:?}",
                    stringify!($test_name),
                    avg_latency,
                    $max_latency
                );
            }
        }
    };
}

/// Test configuration for different environments
#[derive(Debug, Clone)]
pub struct TestConfig {
    pub enable_chaos: bool,
    pub chaos_failure_rate: f64,
    pub default_timeout: std::time::Duration,
    pub hft_latency_requirement: std::time::Duration,
    pub enable_performance_validation: bool,
}

impl Default for TestConfig {
    fn default() -> Self {
        Self {
            enable_chaos: false,
            chaos_failure_rate: 0.1,
            default_timeout: std::time::Duration::from_secs(30),
            hft_latency_requirement: std::time::Duration::from_micros(50),
            enable_performance_validation: true,
        }
    }
}

impl TestConfig {
    pub fn for_unit_tests() -> Self {
        Self {
            enable_chaos: false,
            default_timeout: std::time::Duration::from_secs(5),
            ..Default::default()
        }
    }

    pub fn for_integration_tests() -> Self {
        Self {
            enable_chaos: false,
            default_timeout: std::time::Duration::from_secs(30),
            ..Default::default()
        }
    }

    pub fn for_chaos_tests() -> Self {
        Self {
            enable_chaos: true,
            chaos_failure_rate: 0.2,
            default_timeout: std::time::Duration::from_secs(60),
            ..Default::default()
        }
    }
}

/// Global test configuration accessor
static TEST_CONFIG: std::sync::OnceLock<TestConfig> = std::sync::OnceLock::new();

pub fn get_test_config() -> &'static TestConfig {
    TEST_CONFIG.get_or_init(|| {
        std::env::var("TEST_MODE")
            .map(|mode| match mode.as_str() {
                "unit" => TestConfig::for_unit_tests(),
                "integration" => TestConfig::for_integration_tests(),
                "chaos" => TestConfig::for_chaos_tests(),
                _ => TestConfig::default(),
            })
            .unwrap_or_default()
    })
}

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

    #[tokio::test]
    async fn test_config_default() {
        let config = TestConfig::default();
        assert!(!config.enable_chaos);
        assert_eq!(config.chaos_failure_rate, 0.1);
    }

    #[tokio::test]
    async fn test_config_access() {
        let config = get_test_config();
        assert!(config.default_timeout.as_secs() > 0);
    }
}
