//! Performance and load integration tests for TLI system
//!
//! This module tests system performance under various load conditions including
//! concurrent operations, high-frequency trading scenarios, and stress testing.

use futures::future::join_all;
use std::sync::{
    atomic::{AtomicUsize, Ordering},
    Arc,
};
use std::time::{Duration, Instant};
use tokio::sync::Semaphore;
use tokio::time::{sleep, timeout};
use uuid::Uuid;

use crate::integration::{TestConfig, TestUtilities};
use crate::mocks::grpc_server::{MockBacktestingServer, MockTradingServer};
use fxt::client::{BacktestingClient, TliClientBuilder, TradingClient};
use fxt::prelude::*;

/// Performance test configuration
#[derive(Debug, Clone)]
pub struct PerformanceTestConfig {
    pub base_test_config: TestConfig,
    pub max_concurrent_requests: usize,
    pub test_duration: Duration,
    pub warmup_duration: Duration,
    pub target_latency_p99: Duration,
    pub target_throughput_rps: f64,
    pub memory_limit_mb: usize,
}

impl Default for PerformanceTestConfig {
    fn default() -> Self {
        Self {
            base_test_config: TestConfig::default(),
            max_concurrent_requests: 100,
            test_duration: Duration::from_secs(30),
            warmup_duration: Duration::from_secs(5),
            target_latency_p99: Duration::from_millis(100),
            target_throughput_rps: 1000.0,
            memory_limit_mb: 512,
        }
    }
}

/// Performance metrics collector
#[derive(Debug, Clone)]
pub struct PerformanceMetrics {
    pub total_requests: usize,
    pub successful_requests: usize,
    pub failed_requests: usize,
    pub latencies: Vec<Duration>,
    pub start_time: Instant,
    pub end_time: Instant,
    pub peak_memory_mb: f64,
    pub cpu_usage_percent: f64,
}

impl PerformanceMetrics {
    pub fn new() -> Self {
        Self {
            total_requests: 0,
            successful_requests: 0,
            failed_requests: 0,
            latencies: Vec::new(),
            start_time: Instant::now(),
            end_time: Instant::now(),
            peak_memory_mb: 0.0,
            cpu_usage_percent: 0.0,
        }
    }

    pub fn add_request_result(&mut self, latency: Duration, success: bool) {
        self.total_requests += 1;
        self.latencies.push(latency);

        if success {
            self.successful_requests += 1;
        } else {
            self.failed_requests += 1;
        }
    }

    pub fn finalize(&mut self) {
        self.end_time = Instant::now();
        self.latencies.sort();
    }

    pub fn duration(&self) -> Duration {
        self.end_time.duration_since(self.start_time)
    }

    pub fn throughput_rps(&self) -> f64 {
        self.total_requests as f64 / self.duration().as_secs_f64()
    }

    pub fn success_rate(&self) -> f64 {
        if self.total_requests == 0 {
            0.0
        } else {
            self.successful_requests as f64 / self.total_requests as f64
        }
    }

    pub fn percentile_latency(&self, percentile: f64) -> Option<Duration> {
        if self.latencies.is_empty() {
            return None;
        }

        let index = ((percentile / 100.0) * (self.latencies.len() - 1) as f64) as usize;
        Some(self.latencies[index])
    }

    pub fn average_latency(&self) -> Option<Duration> {
        if self.latencies.is_empty() {
            return None;
        }

        let total_nanos: u64 = self.latencies.iter().map(|d| d.as_nanos() as u64).sum();
        let avg_nanos = total_nanos / self.latencies.len() as u64;
        Some(Duration::from_nanos(avg_nanos))
    }
}

/// Performance test environment
pub struct PerformanceTestEnvironment {
    config: PerformanceTestConfig,
    trading_client: Option<TradingClient>,
    backtesting_client: Option<BacktestingClient>,
    mock_servers: Vec<Box<dyn MockServer>>,
    metrics: Arc<tokio::sync::Mutex<PerformanceMetrics>>,
}

impl PerformanceTestEnvironment {
    pub fn new(config: PerformanceTestConfig) -> Self {
        Self {
            config,
            trading_client: None,
            backtesting_client: None,
            mock_servers: Vec::new(),
            metrics: Arc::new(tokio::sync::Mutex::new(PerformanceMetrics::new())),
        }
    }

    /// Setup high-performance test environment
    pub async fn setup(&mut self) -> FxtResult<()> {
        tracing::info!("Setting up performance test environment");

        // Start high-performance mock servers
        let mut trading_server =
            MockTradingServer::new_high_performance(self.config.base_test_config.mock_server_port)?;
        let trading_port = trading_server.start()?;
        self.mock_servers.push(Box::new(trading_server));

        let mut backtesting_server = MockBacktestingServer::new_high_performance(
            self.config.base_test_config.mock_server_port + 100,
        )?;
        let backtesting_port = backtesting_server.start()?;
        self.mock_servers.push(Box::new(backtesting_server));

        // Wait for services to be ready
        sleep(Duration::from_millis(500)).await;

        // Create optimized TLI client suite
        let client_suite = TliClientBuilder::new()
            .with_service_endpoint(
                "trading_service".to_string(),
                format!("http://localhost:{}", trading_port),
            )
            .with_service_endpoint(
                "backtesting_service".to_string(),
                format!("http://localhost:{}", backtesting_port),
            )
            .with_trading_config(create_high_performance_trading_config())
            .with_backtesting_config(create_high_performance_backtesting_config())
            .build()
            .await?;

        self.trading_client = client_suite.trading_client;
        self.backtesting_client = client_suite.backtesting_client;

        tracing::info!("Performance test environment setup complete");
        Ok(())
    }

    /// Cleanup test environment
    pub async fn teardown(&mut self) -> FxtResult<()> {
        tracing::info!("Tearing down performance test environment");

        // Shutdown clients
        if let Some(client) = self.trading_client.take() {
            client.shutdown().await;
        }
        if let Some(client) = self.backtesting_client.take() {
            client.shutdown().await;
        }

        // Stop mock servers
        for server in &mut self.mock_servers {
            let _ = server.stop();
        }
        self.mock_servers.clear();

        tracing::info!("Performance test environment teardown complete");
        Ok(())
    }

    pub async fn get_metrics(&self) -> PerformanceMetrics {
        self.metrics.lock().await.clone()
    }

    pub async fn record_request(&self, latency: Duration, success: bool) {
        let mut metrics = self.metrics.lock().await;
        metrics.add_request_result(latency, success);
    }
}

fn create_high_performance_trading_config() -> TradingClientConfig {
    TradingClientConfig {
        service_name: "trading_service".to_string(),
        request_timeout: Duration::from_millis(500),
        order_validation: OrderValidationConfig {
            enable_pre_trade_checks: true,
            max_order_value: 10000000.0,
            require_confirmation: false,
        },
        risk_management: RiskManagementConfig {
            enable_position_limits: true,
            max_position_size: 100000.0,
            max_daily_loss: 500000.0,
        },
        market_data: MarketDataConfig {
            subscription_timeout: Duration::from_secs(10),
            reconnect_interval: Duration::from_millis(500),
            max_reconnect_attempts: 3,
        },
        monitoring: MonitoringConfig {
            enable_health_checks: false, // Disable for performance testing
            health_check_interval: Duration::from_secs(60),
            enable_circuit_breaker: false, // Disable for performance testing
            circuit_breaker_threshold: 10,
        },
        event_streaming: EventStreamConfig {
            buffer_size: 10000,
            reconnect_policy: ReconnectPolicy::Immediate,
            max_reconnect_attempts: 1,
        },
    }
}

fn create_high_performance_backtesting_config() -> BacktestingClientConfig {
    BacktestingClientConfig {
        service_name: "backtesting_service".to_string(),
        request_timeout: Duration::from_secs(10),
        long_running_timeout: Duration::from_secs(60),
        retry_config: RetryConfig {
            max_attempts: 1, // Minimal retries for performance
            initial_delay: Duration::from_millis(10),
            max_delay: Duration::from_millis(100),
            backoff_multiplier: 1.5,
        },
    }
}

/// Concurrent request performance tests
#[cfg(test)]
mod concurrent_request_tests {
    use super::*;

    #[tokio::test]
    async fn test_concurrent_order_submission() {
        let config = PerformanceTestConfig {
            max_concurrent_requests: 50,
            test_duration: Duration::from_secs(10),
            ..Default::default()
        };

        let mut test_env = PerformanceTestEnvironment::new(config.clone());
        test_env
            .setup()
            .await
            .expect("Failed to setup test environment");

        let trading_client = test_env
            .trading_client
            .as_ref()
            .expect("Trading client not available");

        // Warmup period
        tracing::info!("Starting warmup period");
        let warmup_start = Instant::now();
        while warmup_start.elapsed() < config.warmup_duration {
            let order_request = create_test_order_request();
            let _ = trading_client.submit_order(order_request).await;
            sleep(Duration::from_millis(10)).await;
        }

        tracing::info!("Starting concurrent order submission test");
        let semaphore = Arc::new(Semaphore::new(config.max_concurrent_requests));
        let start_time = Instant::now();
        let mut handles = Vec::new();

        // Start metrics collection
        {
            let mut metrics = test_env.metrics.lock().await;
            metrics.start_time = start_time;
        }

        while start_time.elapsed() < config.test_duration {
            let permit = semaphore.clone().acquire_owned().await.unwrap();
            let client = trading_client.clone();
            let metrics = test_env.metrics.clone();

            let handle = tokio::spawn(async move {
                let request_start = Instant::now();
                let order_request = create_test_order_request();

                let result = client.submit_order(order_request).await;
                let latency = request_start.elapsed();

                {
                    let mut m = metrics.lock().await;
                    m.add_request_result(latency, result.is_ok());
                }

                drop(permit);
            });

            handles.push(handle);

            // Control request rate
            sleep(Duration::from_micros(100)).await;
        }

        // Wait for all requests to complete
        tracing::info!(
            "Waiting for {} concurrent requests to complete",
            handles.len()
        );
        join_all(handles).await;

        // Finalize metrics
        {
            let mut metrics = test_env.metrics.lock().await;
            metrics.finalize();
        }

        let final_metrics = test_env.get_metrics().await;

        // Performance assertions
        assert!(
            final_metrics.total_requests > 0,
            "Should have processed requests"
        );
        assert!(
            final_metrics.success_rate() > 0.95,
            "Success rate should be > 95%"
        );

        if let Some(p99_latency) = final_metrics.percentile_latency(99.0) {
            assert!(
                p99_latency < config.target_latency_p99,
                "P99 latency {} should be < target {}",
                p99_latency.as_millis(),
                config.target_latency_p99.as_millis()
            );
        }

        tracing::info!("Concurrent test results:");
        tracing::info!("  Total requests: {}", final_metrics.total_requests);
        tracing::info!(
            "  Success rate: {:.2}%",
            final_metrics.success_rate() * 100.0
        );
        tracing::info!("  Throughput: {:.2} RPS", final_metrics.throughput_rps());
        tracing::info!("  Average latency: {:?}", final_metrics.average_latency());
        tracing::info!(
            "  P99 latency: {:?}",
            final_metrics.percentile_latency(99.0)
        );

        test_env
            .teardown()
            .await
            .expect("Failed to teardown test environment");
    }

    #[tokio::test]
    async fn test_mixed_operation_load() {
        let config = PerformanceTestConfig {
            max_concurrent_requests: 30,
            test_duration: Duration::from_secs(15),
            ..Default::default()
        };

        let mut test_env = PerformanceTestEnvironment::new(config.clone());
        test_env
            .setup()
            .await
            .expect("Failed to setup test environment");

        let trading_client = test_env
            .trading_client
            .as_ref()
            .expect("Trading client not available");

        tracing::info!("Starting mixed operation load test");
        let semaphore = Arc::new(Semaphore::new(config.max_concurrent_requests));
        let start_time = Instant::now();
        let mut handles = Vec::new();

        // Operation counters
        let order_count = Arc::new(AtomicUsize::new(0));
        let position_count = Arc::new(AtomicUsize::new(0));
        let analytics_count = Arc::new(AtomicUsize::new(0));

        {
            let mut metrics = test_env.metrics.lock().await;
            metrics.start_time = start_time;
        }

        while start_time.elapsed() < config.test_duration {
            let permit = semaphore.clone().acquire_owned().await.unwrap();
            let client = trading_client.clone();
            let metrics = test_env.metrics.clone();
            let order_counter = order_count.clone();
            let position_counter = position_count.clone();
            let analytics_counter = analytics_count.clone();

            let handle = tokio::spawn(async move {
                let request_start = Instant::now();

                // Randomly choose operation type
                let operation_type = rand::random::<u8>() % 3;
                let result = match operation_type {
                    0 => {
                        // Order submission (60% of operations)
                        order_counter.fetch_add(1, Ordering::Relaxed);
                        let order_request = create_test_order_request();
                        client.submit_order(order_request).await.map(|_| ())
                    }
                    1 => {
                        // Position query (30% of operations)
                        position_counter.fetch_add(1, Ordering::Relaxed);
                        let position_request = GetPositionsRequest {
                            account_id: Some("test_account".to_string()),
                            symbol_filter: None,
                            include_zero_positions: false,
                        };
                        client.get_positions(position_request).await.map(|_| ())
                    }
                    2 => {
                        // Portfolio analytics (10% of operations)
                        analytics_counter.fetch_add(1, Ordering::Relaxed);
                        let analytics_request = PortfolioAnalyticsRequest {
                            account_id: "test_account".to_string(),
                            calculation_date: chrono::Utc::now().timestamp(),
                            include_realized_pnl: true,
                            include_unrealized_pnl: true,
                            include_risk_metrics: false, // Disable for performance
                        };
                        client
                            .get_portfolio_analytics(analytics_request)
                            .await
                            .map(|_| ())
                    }
                    _ => unreachable!(),
                };

                let latency = request_start.elapsed();

                {
                    let mut m = metrics.lock().await;
                    m.add_request_result(latency, result.is_ok());
                }

                drop(permit);
            });

            handles.push(handle);
            sleep(Duration::from_micros(200)).await;
        }

        // Wait for completion
        join_all(handles).await;

        let final_metrics = test_env.get_metrics().await;
        let final_order_count = order_count.load(Ordering::Relaxed);
        let final_position_count = position_count.load(Ordering::Relaxed);
        let final_analytics_count = analytics_count.load(Ordering::Relaxed);

        tracing::info!("Mixed operation test results:");
        tracing::info!("  Order operations: {}", final_order_count);
        tracing::info!("  Position queries: {}", final_position_count);
        tracing::info!("  Analytics queries: {}", final_analytics_count);
        tracing::info!("  Total operations: {}", final_metrics.total_requests);
        tracing::info!(
            "  Success rate: {:.2}%",
            final_metrics.success_rate() * 100.0
        );
        tracing::info!("  Throughput: {:.2} RPS", final_metrics.throughput_rps());

        assert!(
            final_metrics.success_rate() > 0.90,
            "Mixed operation success rate should be > 90%"
        );
        assert!(final_order_count > 0, "Should have processed orders");
        assert!(
            final_position_count > 0,
            "Should have processed position queries"
        );

        test_env
            .teardown()
            .await
            .expect("Failed to teardown test environment");
    }

    fn create_test_order_request() -> SubmitOrderRequest {
        let symbols = ["AAPL", "GOOGL", "MSFT", "TSLA", "AMZN"];
        let symbol = symbols[rand::random::<usize>() % symbols.len()];

        SubmitOrderRequest {
            symbol: TestUtilities::generate_test_symbol(symbol),
            side: if rand::random::<bool>() {
                OrderSide::Buy
            } else {
                OrderSide::Sell
            } as i32,
            order_type: OrderType::Market as i32,
            quantity: (rand::random::<u32>() % 1000 + 1) as f64,
            price: Some(100.0 + (rand::random::<f64>() * 100.0)),
            stop_price: None,
            time_in_force: "DAY".to_string(),
            client_order_id: Uuid::new_v4().to_string(),
        }
    }
}

/// High-frequency trading simulation tests
#[cfg(test)]
mod hft_simulation_tests {
    use super::*;

    #[tokio::test]
    async fn test_high_frequency_order_flow() {
        let config = PerformanceTestConfig {
            max_concurrent_requests: 20,
            test_duration: Duration::from_secs(5),
            target_latency_p99: Duration::from_millis(10), // Very low latency requirement
            target_throughput_rps: 2000.0,
            ..Default::default()
        };

        let mut test_env = PerformanceTestEnvironment::new(config.clone());
        test_env
            .setup()
            .await
            .expect("Failed to setup test environment");

        let trading_client = test_env
            .trading_client
            .as_ref()
            .expect("Trading client not available");

        tracing::info!("Starting high-frequency trading simulation");
        let start_time = Instant::now();
        let mut handles = Vec::new();

        {
            let mut metrics = test_env.metrics.lock().await;
            metrics.start_time = start_time;
        }

        // Simulate HFT pattern: rapid order submission and cancellation
        while start_time.elapsed() < config.test_duration {
            // Submit order
            let client = trading_client.clone();
            let metrics = test_env.metrics.clone();

            let submit_handle = tokio::spawn(async move {
                let request_start = Instant::now();
                let order_request = create_hft_order_request();

                let result = client.submit_order(order_request).await;
                let latency = request_start.elapsed();

                {
                    let mut m = metrics.lock().await;
                    m.add_request_result(latency, result.is_ok());
                }

                result
            });

            handles.push(submit_handle);

            // Minimal delay for HFT simulation
            sleep(Duration::from_micros(500)).await;
        }

        // Wait for all operations to complete
        let results = join_all(handles).await;

        let final_metrics = test_env.get_metrics().await;

        // HFT performance requirements
        assert!(
            final_metrics.success_rate() > 0.98,
            "HFT success rate should be > 98%"
        );
        assert!(
            final_metrics.throughput_rps() > config.target_throughput_rps * 0.8,
            "Throughput should be within 80% of target"
        );

        if let Some(p99_latency) = final_metrics.percentile_latency(99.0) {
            tracing::info!("HFT P99 latency: {:?}", p99_latency);
            // Note: In real systems, this would be much stricter (microseconds)
        }

        tracing::info!("HFT simulation results:");
        tracing::info!("  Total operations: {}", final_metrics.total_requests);
        tracing::info!(
            "  Success rate: {:.3}%",
            final_metrics.success_rate() * 100.0
        );
        tracing::info!("  Throughput: {:.2} RPS", final_metrics.throughput_rps());
        tracing::info!("  Average latency: {:?}", final_metrics.average_latency());

        test_env
            .teardown()
            .await
            .expect("Failed to teardown test environment");
    }

    #[tokio::test]
    async fn test_market_data_streaming_performance() {
        let config = PerformanceTestConfig {
            test_duration: Duration::from_secs(10),
            ..Default::default()
        };

        let mut test_env = PerformanceTestEnvironment::new(config.clone());
        test_env
            .setup()
            .await
            .expect("Failed to setup test environment");

        let trading_client = test_env
            .trading_client
            .as_ref()
            .expect("Trading client not available");

        // Subscribe to high-frequency market data
        let subscription_request = MarketDataSubscriptionRequest {
            symbols: vec![
                "AAPL".to_string(),
                "GOOGL".to_string(),
                "MSFT".to_string(),
                "TSLA".to_string(),
                "AMZN".to_string(),
                "META".to_string(),
            ],
            data_types: vec![MarketDataType::Quote as i32, MarketDataType::Trade as i32],
            include_level2: true,
        };

        let mut stream = trading_client
            .subscribe_market_data(subscription_request)
            .await
            .expect("Failed to subscribe to market data");

        let start_time = Instant::now();
        let mut updates_received = 0;
        let mut total_latency = Duration::from_nanos(0);

        tracing::info!("Starting market data streaming performance test");

        while start_time.elapsed() < config.test_duration {
            match timeout(Duration::from_millis(100), stream.recv()).await {
                Ok(Some(update)) => {
                    updates_received += 1;

                    // Calculate latency (mock server timestamps should be close to current time)
                    let update_time = chrono::DateTime::from_timestamp_nanos(update.timestamp);
                    if let Some(update_time) = update_time {
                        let latency = chrono::Utc::now().signed_duration_since(update_time);
                        if latency.num_milliseconds() >= 0 {
                            total_latency +=
                                Duration::from_millis(latency.num_milliseconds() as u64);
                        }
                    }

                    // Log progress periodically
                    if updates_received % 1000 == 0 {
                        tracing::info!("Received {} market data updates", updates_received);
                    }
                }
                Ok(None) => break,
                Err(_) => {
                    // Timeout - continue
                    continue;
                }
            }
        }

        let duration = start_time.elapsed();
        let updates_per_second = updates_received as f64 / duration.as_secs_f64();
        let average_latency = if updates_received > 0 {
            total_latency / updates_received as u32
        } else {
            Duration::from_nanos(0)
        };

        tracing::info!("Market data streaming results:");
        tracing::info!("  Updates received: {}", updates_received);
        tracing::info!("  Updates per second: {:.2}", updates_per_second);
        tracing::info!("  Average latency: {:?}", average_latency);

        assert!(
            updates_received > 0,
            "Should have received market data updates"
        );
        assert!(
            updates_per_second > 100.0,
            "Should process > 100 updates/second"
        );

        test_env
            .teardown()
            .await
            .expect("Failed to teardown test environment");
    }

    fn create_hft_order_request() -> SubmitOrderRequest {
        SubmitOrderRequest {
            symbol: "AAPL".to_string(), // Use consistent symbol for HFT
            side: if rand::random::<bool>() {
                OrderSide::Buy
            } else {
                OrderSide::Sell
            } as i32,
            order_type: OrderType::Limit as i32,
            quantity: 100.0, // Standard lot size
            price: Some(150.0 + (rand::random::<f64>() - 0.5) * 0.20), // Tight price range
            stop_price: None,
            time_in_force: "IOC".to_string(), // Immediate or Cancel for HFT
            client_order_id: Uuid::new_v4().to_string(),
        }
    }
}

/// Stress testing and resource limits
#[cfg(test)]
mod stress_tests {
    use super::*;

    #[tokio::test]
    async fn test_memory_usage_under_load() {
        let config = PerformanceTestConfig {
            max_concurrent_requests: 100,
            test_duration: Duration::from_secs(20),
            memory_limit_mb: 256,
            ..Default::default()
        };

        let mut test_env = PerformanceTestEnvironment::new(config.clone());
        test_env
            .setup()
            .await
            .expect("Failed to setup test environment");

        let trading_client = test_env
            .trading_client
            .as_ref()
            .expect("Trading client not available");

        tracing::info!("Starting memory usage stress test");

        // Monitor initial memory usage
        let initial_memory = get_memory_usage_mb();
        tracing::info!("Initial memory usage: {:.2} MB", initial_memory);

        let start_time = Instant::now();
        let mut handles = Vec::new();

        {
            let mut metrics = test_env.metrics.lock().await;
            metrics.start_time = start_time;
        }

        // Generate sustained load
        while start_time.elapsed() < config.test_duration {
            // Batch of concurrent requests
            for _ in 0..config.max_concurrent_requests {
                let client = trading_client.clone();
                let metrics = test_env.metrics.clone();

                let handle = tokio::spawn(async move {
                    let request_start = Instant::now();

                    // Create large order batch to test memory usage
                    let mut batch_orders = Vec::new();
                    for i in 0..10 {
                        batch_orders.push(SubmitOrderRequest {
                            symbol: format!("TEST{:04}", i),
                            side: OrderSide::Buy as i32,
                            order_type: OrderType::Limit as i32,
                            quantity: 1000.0,
                            price: Some(100.0 + i as f64),
                            stop_price: None,
                            time_in_force: "DAY".to_string(),
                            client_order_id: Uuid::new_v4().to_string(),
                        });
                    }

                    let batch_request = SubmitBatchOrdersRequest {
                        orders: batch_orders,
                        all_or_none: false,
                        max_acceptable_failures: 2,
                    };

                    let result = client.submit_batch_orders(batch_request).await;
                    let latency = request_start.elapsed();

                    {
                        let mut m = metrics.lock().await;
                        m.add_request_result(latency, result.is_ok());
                    }
                });

                handles.push(handle);
            }

            // Check memory usage periodically
            let current_memory = get_memory_usage_mb();
            tracing::debug!("Current memory usage: {:.2} MB", current_memory);

            if current_memory > config.memory_limit_mb as f64 {
                tracing::warn!(
                    "Memory usage {} MB exceeds limit {} MB",
                    current_memory,
                    config.memory_limit_mb
                );
            }

            // Wait for batch to complete before starting next batch
            let batch_timeout = timeout(Duration::from_secs(5), join_all(handles.drain(..))).await;
            if batch_timeout.is_err() {
                tracing::warn!("Batch requests timed out");
                break;
            }

            sleep(Duration::from_millis(100)).await;
        }

        let final_memory = get_memory_usage_mb();
        let final_metrics = test_env.get_metrics().await;

        tracing::info!("Memory stress test results:");
        tracing::info!("  Initial memory: {:.2} MB", initial_memory);
        tracing::info!("  Final memory: {:.2} MB", final_memory);
        tracing::info!("  Memory increase: {:.2} MB", final_memory - initial_memory);
        tracing::info!("  Total requests: {}", final_metrics.total_requests);
        tracing::info!(
            "  Success rate: {:.2}%",
            final_metrics.success_rate() * 100.0
        );

        // Memory usage should be reasonable
        let memory_increase = final_memory - initial_memory;
        assert!(
            memory_increase < config.memory_limit_mb as f64 * 0.5,
            "Memory increase should be < 50% of limit"
        );

        test_env
            .teardown()
            .await
            .expect("Failed to teardown test environment");
    }

    #[tokio::test]
    async fn test_connection_pool_limits() {
        let config = PerformanceTestConfig {
            max_concurrent_requests: 200, // Exceed typical connection pool limits
            test_duration: Duration::from_secs(10),
            ..Default::default()
        };

        let mut test_env = PerformanceTestEnvironment::new(config.clone());
        test_env
            .setup()
            .await
            .expect("Failed to setup test environment");

        let trading_client = test_env
            .trading_client
            .as_ref()
            .expect("Trading client not available");

        tracing::info!("Starting connection pool stress test");

        let start_time = Instant::now();
        let mut handles = Vec::new();
        let connection_errors = Arc::new(AtomicUsize::new(0));

        {
            let mut metrics = test_env.metrics.lock().await;
            metrics.start_time = start_time;
        }

        // Launch many concurrent requests to stress connection pool
        for i in 0..config.max_concurrent_requests {
            let client = trading_client.clone();
            let metrics = test_env.metrics.clone();
            let error_counter = connection_errors.clone();

            let handle = tokio::spawn(async move {
                let request_start = Instant::now();
                let order_request = SubmitOrderRequest {
                    symbol: format!("STRESS{:03}", i % 50), // Cycle through symbols
                    side: OrderSide::Buy as i32,
                    order_type: OrderType::Market as i32,
                    quantity: 100.0,
                    price: Some(100.0),
                    stop_price: None,
                    time_in_force: "DAY".to_string(),
                    client_order_id: format!("stress_order_{}", i),
                };

                let result = client.submit_order(order_request).await;
                let latency = request_start.elapsed();

                let success = match &result {
                    Ok(_) => true,
                    Err(FxtError::Connection(_)) => {
                        error_counter.fetch_add(1, Ordering::Relaxed);
                        false
                    }
                    Err(_) => false,
                };

                {
                    let mut m = metrics.lock().await;
                    m.add_request_result(latency, success);
                }

                // Hold connection briefly to stress pool
                sleep(Duration::from_millis(50)).await;
            });

            handles.push(handle);

            // Small delay to control request rate
            sleep(Duration::from_millis(2)).await;
        }

        // Wait for all requests to complete
        join_all(handles).await;

        let final_metrics = test_env.get_metrics().await;
        let final_connection_errors = connection_errors.load(Ordering::Relaxed);

        tracing::info!("Connection pool stress test results:");
        tracing::info!("  Total requests: {}", final_metrics.total_requests);
        tracing::info!(
            "  Success rate: {:.2}%",
            final_metrics.success_rate() * 100.0
        );
        tracing::info!("  Connection rejections: {}", final_connection_errors);
        tracing::info!("  Throughput: {:.2} RPS", final_metrics.throughput_rps());

        // Should handle connection pool pressure gracefully
        assert!(
            final_metrics.success_rate() > 0.80,
            "Should maintain > 80% success rate under stress"
        );
        assert!(
            final_connection_errors < config.max_concurrent_requests / 2,
            "Connection errors should be < 50% of requests"
        );

        test_env
            .teardown()
            .await
            .expect("Failed to teardown test environment");
    }

    fn get_memory_usage_mb() -> f64 {
        // In a real implementation, this would use system APIs to get actual memory usage
        // For testing, we'll simulate with a simple estimation
        use std::alloc::{GlobalAlloc, Layout, System};

        // This is a simplified approximation
        // In production, you'd use platform-specific APIs or libraries like `sysinfo`

        // Estimate based on allocator (very rough approximation)
        static mut ALLOCATED: usize = 0;

        // SAFETY: Allocator operations use valid layout with correct alignment and size
        unsafe {
            // This is just for demonstration - real memory tracking would be more sophisticated
            let layout = Layout::from_size_align(1024, 8).unwrap();
            let ptr = System.alloc(layout);
            if !ptr.is_null() {
                ALLOCATED += 1024;
                System.dealloc(ptr, layout);
            }

            (ALLOCATED as f64) / (1024.0 * 1024.0) + 50.0 // Base memory usage
        }
    }
}

/// Backtesting performance tests
#[cfg(test)]
mod backtesting_performance_tests {
    use super::*;

    #[tokio::test]
    async fn test_concurrent_backtest_execution() {
        let config = PerformanceTestConfig {
            max_concurrent_requests: 10, // Backtests are resource-intensive
            test_duration: Duration::from_secs(30),
            ..Default::default()
        };

        let mut test_env = PerformanceTestEnvironment::new(config.clone());
        test_env
            .setup()
            .await
            .expect("Failed to setup test environment");

        let backtesting_client = test_env
            .backtesting_client
            .as_ref()
            .expect("Backtesting client not available");

        tracing::info!("Starting concurrent backtest execution test");

        let start_time = Instant::now();
        let mut handles = Vec::new();
        let completed_backtests = Arc::new(AtomicUsize::new(0));

        // Create multiple concurrent backtests
        for i in 0..config.max_concurrent_requests {
            let client = backtesting_client.clone();
            let completed_counter = completed_backtests.clone();

            let handle = tokio::spawn(async move {
                let backtest_request = CreateBacktestRequest {
                    name: format!("Concurrent Backtest {}", i),
                    strategy_id: "performance_test_strategy".to_string(),
                    start_date: "2024-01-01".to_string(),
                    end_date: "2024-01-31".to_string(),
                    initial_capital: 100000.0,
                    symbols: vec![
                        format!("SYM{:02}", i % 10), // Distribute across symbols
                    ],
                    parameters: std::collections::HashMap::from([
                        ("param1".to_string(), format!("{}", i * 10)),
                        ("param2".to_string(), "test_value".to_string()),
                    ]),
                };

                // Create backtest
                match client.create_backtest(backtest_request).await {
                    Ok(create_response) => {
                        if create_response.success {
                            let backtest_id = create_response.backtest_id;

                            // Start backtest
                            let start_request = StartBacktestRequest {
                                backtest_id: backtest_id.clone(),
                                async_execution: true,
                            };

                            if let Ok(start_response) = client.start_backtest(start_request).await {
                                if start_response.success {
                                    // Monitor until completion (simplified)
                                    let mut checks = 0;
                                    while checks < 20 {
                                        let status_request = GetBacktestStatusRequest {
                                            backtest_id: backtest_id.clone(),
                                        };

                                        if let Ok(status_response) =
                                            client.get_backtest_status(status_request).await
                                        {
                                            if status_response.status
                                                == BacktestStatus::Completed as i32
                                            {
                                                completed_counter.fetch_add(1, Ordering::Relaxed);
                                                break;
                                            }
                                        }

                                        checks += 1;
                                        sleep(Duration::from_millis(100)).await;
                                    }
                                }
                            }
                        }
                    }
                    Err(e) => {
                        tracing::warn!("Backtest creation failed: {:?}", e);
                    }
                }
            });

            handles.push(handle);
            sleep(Duration::from_millis(100)).await; // Stagger backtest creation
        }

        // Wait for all backtests to complete or timeout
        let completion_timeout = timeout(Duration::from_secs(60), join_all(handles)).await;

        let final_completed = completed_backtests.load(Ordering::Relaxed);
        let duration = start_time.elapsed();

        tracing::info!("Concurrent backtest test results:");
        tracing::info!("  Backtests started: {}", config.max_concurrent_requests);
        tracing::info!("  Backtests completed: {}", final_completed);
        tracing::info!(
            "  Completion rate: {:.1}%",
            (final_completed as f64 / config.max_concurrent_requests as f64) * 100.0
        );
        tracing::info!("  Total duration: {:?}", duration);

        // Should complete at least some backtests
        assert!(final_completed > 0, "Should complete at least one backtest");
        assert!(completion_timeout.is_ok(), "Should not timeout");

        test_env
            .teardown()
            .await
            .expect("Failed to teardown test environment");
    }

    #[tokio::test]
    async fn test_large_dataset_backtest_performance() {
        let config = PerformanceTestConfig::default();

        let mut test_env = PerformanceTestEnvironment::new(config.clone());
        test_env
            .setup()
            .await
            .expect("Failed to setup test environment");

        let backtesting_client = test_env
            .backtesting_client
            .as_ref()
            .expect("Backtesting client not available");

        tracing::info!("Starting large dataset backtest performance test");

        // Create backtest with large dataset
        let backtest_request = CreateBacktestRequest {
            name: "Large Dataset Performance Test".to_string(),
            strategy_id: "performance_test_strategy".to_string(),
            start_date: "2023-01-01".to_string(),
            end_date: "2024-12-31".to_string(), // 2 years of data
            initial_capital: 1000000.0,
            symbols: vec![
                "AAPL".to_string(),
                "GOOGL".to_string(),
                "MSFT".to_string(),
                "TSLA".to_string(),
                "AMZN".to_string(),
                "META".to_string(),
                "NVDA".to_string(),
                "NFLX".to_string(),
                "AMD".to_string(),
                "CRM".to_string(), // 10 symbols for comprehensive test
            ],
            parameters: std::collections::HashMap::from([
                ("lookback_days".to_string(), "252".to_string()), // 1 year lookback
                ("rebalance_freq".to_string(), "weekly".to_string()),
            ]),
        };

        let creation_start = Instant::now();
        let create_response = backtesting_client
            .create_backtest(backtest_request)
            .await
            .expect("Failed to create large backtest");

        assert!(
            create_response.success,
            "Large backtest creation should succeed"
        );
        let creation_time = creation_start.elapsed();

        let backtest_id = create_response.backtest_id;

        // Start backtest execution
        let start_request = StartBacktestRequest {
            backtest_id: backtest_id.clone(),
            async_execution: true,
        };

        let execution_start = Instant::now();
        let start_response = backtesting_client
            .start_backtest(start_request)
            .await
            .expect("Failed to start large backtest");

        assert!(
            start_response.success,
            "Large backtest start should succeed"
        );

        // Monitor execution progress
        let mut progress_checks = 0;
        let max_progress_checks = 100; // Extended timeout for large dataset
        let mut last_progress = 0.0;

        while progress_checks < max_progress_checks {
            let status_request = GetBacktestStatusRequest {
                backtest_id: backtest_id.clone(),
            };

            match backtesting_client.get_backtest_status(status_request).await {
                Ok(status_response) => {
                    let progress = status_response.progress_percentage;

                    if progress > last_progress {
                        tracing::info!("Backtest progress: {:.1}%", progress);
                        last_progress = progress;
                    }

                    if status_response.status == BacktestStatus::Completed as i32 {
                        break;
                    }

                    if status_response.status == BacktestStatus::Failed as i32 {
                        panic!(
                            "Large backtest failed: {}",
                            status_response.error_message.unwrap_or_default()
                        );
                    }
                }
                Err(e) => {
                    tracing::warn!("Status check failed: {:?}", e);
                }
            }

            progress_checks += 1;
            sleep(Duration::from_millis(200)).await;
        }

        let execution_time = execution_start.elapsed();

        tracing::info!("Large dataset backtest performance results:");
        tracing::info!("  Creation time: {:?}", creation_time);
        tracing::info!("  Execution time: {:?}", execution_time);
        tracing::info!("  Progress checks: {}", progress_checks);

        // Performance expectations for large dataset
        assert!(
            creation_time < Duration::from_secs(10),
            "Creation should be < 10 seconds"
        );
        assert!(
            execution_time < Duration::from_secs(120),
            "Execution should be < 2 minutes for test"
        );
        assert!(
            progress_checks < max_progress_checks,
            "Should complete within timeout"
        );

        test_env
            .teardown()
            .await
            .expect("Failed to teardown test environment");
    }
}
