//! Chaos engineering tests for Foxhunt HFT system.

use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration;
use tokio::time::sleep;
use rand::{Rng, SeedableRng};
use rand::rngs::StdRng;

/// Test system behavior under random failures
#[tokio::test]
async fn test_random_service_failures() {
    let success_count = Arc::new(AtomicUsize::new(0));
    let failure_count = Arc::new(AtomicUsize::new(0));
    
    let mut handles = vec![];
    
    // Spawn multiple concurrent tasks that randomly fail
    for i in 0..10 {
        let success_count = Arc::clone(&success_count);
        let failure_count = Arc::clone(&failure_count);
        
        let handle = tokio::spawn(async move {
            let mut rng = StdRng::from_entropy();
            sleep(Duration::from_millis(rng.gen_range(1..100))).await;
            
            // Randomly fail 30% of the time
            if rng.gen_bool(0.3) {
                failure_count.fetch_add(1, Ordering::Relaxed);
                panic!("Simulated chaos failure in task {}", i);
            } else {
                success_count.fetch_add(1, Ordering::Relaxed);
            }
        });
        
        handles.push(handle);
    }
    
    // Wait for all tasks to complete
    for handle in handles {
        let _ = handle.await; // Ignore panics
    }
    
    let successes = success_count.load(Ordering::Relaxed);
    let failures = failure_count.load(Ordering::Relaxed);
    
    // Verify we had both successes and failures (chaos)
    println!("Chaos test results: {} successes, {} failures", successes, failures);
    assert!(successes + failures == 10);
}

/// Test system resilience under high load
#[tokio::test] 
async fn test_load_resilience() {
    let request_count = Arc::new(AtomicUsize::new(0));
    let mut handles = vec![];
    
    // Simulate high concurrent load
    for _ in 0..50 {
        let request_count = Arc::clone(&request_count);
        
        let handle = tokio::spawn(async move {
            // Simulate work
            let mut rng = StdRng::from_entropy();
            sleep(Duration::from_millis(rng.gen_range(1..20))).await;
            request_count.fetch_add(1, Ordering::Relaxed);
        });
        
        handles.push(handle);
    }
    
    // Wait for all requests to complete
    for handle in handles {
        handle.await.expect("Task should not panic under load");
    }
    
    assert_eq!(request_count.load(Ordering::Relaxed), 50);
}

/// Test resource exhaustion scenarios
#[tokio::test]
async fn test_resource_limits() {
    // Simulate memory pressure by creating many allocations
    let mut allocations = Vec::new();
    
    for i in 0..1000 {
        let data = vec![i; 1000]; // 1KB allocation
        allocations.push(data);
        
        // Add some delay to prevent overwhelming the system
        if i % 100 == 0 {
            tokio::task::yield_now().await;
        }
    }
    
    // Verify we can still function under memory pressure
    assert_eq!(allocations.len(), 1000);
    
    // Clean up
    allocations.clear();
}