use anyhow::Result;
use tokio::sync::mpsc;

use super::authenticated_client::*;
use crate::metrics::RequestMetric;

pub struct MixedWorkloadClient {
    client: AuthenticatedClient,
    client_id: usize,
    metrics_tx: mpsc::UnboundedSender<RequestMetric>,
}

impl MixedWorkloadClient {
    pub fn new(
        client: AuthenticatedClient,
        client_id: usize,
        metrics_tx: mpsc::UnboundedSender<RequestMetric>,
    ) -> Self {
        Self {
            client,
            client_id,
            metrics_tx,
        }
    }

    /// Run mixed workload with realistic distribution:
    /// - 60% order submissions
    ///
    /// - 30% position queries
    /// - 8% backtesting requests
    ///
    /// - 2% ML training requests
    pub async fn run_mixed_workload(&mut self, duration: std::time::Duration) -> Result<()> {
        use rand::Rng;
        let start = std::time::Instant::now();

        while start.elapsed() < duration {
            // Generate random number each iteration to avoid holding RNG across await
            let workload_type = {
                let mut rng = rand::thread_rng();
                rng.gen_range(0..100)
            };

            let metric = match workload_type {
                0..=59 => {
                    // 60% - Submit order
                    self.client
                        .submit_order(self.client_id, TestOrder::random())
                        .await?
                },
                60..=89 => {
                    // 30% - Query positions
                    self.client.get_positions(self.client_id).await?
                },
                90..=97 => {
                    // 8% - Run backtest
                    self.client
                        .run_backtest(self.client_id, BacktestConfig::default())
                        .await?
                },
                98..=99 => {
                    // 2% - Train model
                    self.client
                        .train_model(self.client_id, TrainingConfig::default())
                        .await?
                },
                _ => unreachable!(),
            };

            self.metrics_tx.send(metric)?;

            // Small random think time (1-50ms) to simulate realistic user behavior
            let think_time_ms = {
                let mut rng = rand::thread_rng();
                rng.gen_range(1..=50)
            };
            tokio::time::sleep(tokio::time::Duration::from_millis(think_time_ms)).await;
        }

        Ok(())
    }

}
