use crate::{MarketUpdate, MarketDataType, Quote, Trade, Bar, Side};
use chrono::{DateTime, Utc, Duration};
use rand::{Rng, SeedableRng};
use rand::rngs::StdRng;
use rand_distr::{Normal, Distribution};

pub struct MockDataGenerator {
    rng: StdRng,
    base_price: f64,
    volatility: f64,
    spread_bps: f64,
    volume_mean: f64,
    volume_std: f64,
}

impl MockDataGenerator {
    pub fn new(seed: u64) -> Self {
        Self {
            rng: StdRng::seed_from_u64(seed),
            base_price: 100.0,
            volatility: 0.02, // 2% daily volatility
            spread_bps: 5.0,  // 5 basis points spread
            volume_mean: 1_000_000.0,
            volume_std: 200_000.0,
        }
    }

    pub fn with_params(seed: u64, base_price: f64, volatility: f64, spread_bps: f64) -> Self {
        Self {
            rng: StdRng::seed_from_u64(seed),
            base_price,
            volatility,
            spread_bps,
            volume_mean: 1_000_000.0,
            volume_std: 200_000.0,
        }
    }

    pub fn generate_quotes(
        &mut self,
        symbol: String,
        start_time: DateTime<Utc>,
        end_time: DateTime<Utc>,
        interval_ms: i64,
    ) -> Vec<MarketUpdate> {
        let mut updates = Vec::new();
        let mut current_time = start_time;
        let mut price = self.base_price;
        
        let price_dist = Normal::new(0.0, self.volatility).unwrap();
        let volume_dist = Normal::new(self.volume_mean, self.volume_std).unwrap();
        
        while current_time <= end_time {
            // Generate price movement
            let return_pct = price_dist.sample(&mut self.rng) / 100.0;
            price *= 1.0 + return_pct;
            price = price.max(0.01); // Ensure positive price
            
            // Calculate bid/ask
            let half_spread = price * self.spread_bps / 20000.0;
            let bid = price - half_spread;
            let ask = price + half_spread;
            
            // Generate volume
            let volume = volume_dist.sample(&mut self.rng).max(0.0) as u32;
            
            updates.push(MarketUpdate {
                symbol: symbol.clone(),
                timestamp: current_time,
                data: MarketDataType::Quote(Quote {
                    bid,
                    ask,
                    bid_size: (volume / 10) as f64,
                    ask_size: (volume / 10) as f64,
                }),
            });
            
            current_time = current_time + Duration::milliseconds(interval_ms);
        }
        
        updates
    }

    pub fn generate_trades(
        &mut self,
        symbol: String,
        start_time: DateTime<Utc>,
        end_time: DateTime<Utc>,
        trades_per_minute: u32,
    ) -> Vec<MarketUpdate> {
        let mut updates = Vec::new();
        let mut current_time = start_time;
        let mut price = self.base_price;
        
        let price_dist = Normal::new(0.0, self.volatility / 100.0).unwrap();
        let volume_dist = Normal::new(100.0, 50.0).unwrap();
        
        let interval_ms = 60_000 / trades_per_minute as i64;
        
        while current_time <= end_time {
            // Generate price movement
            let return_pct = price_dist.sample(&mut self.rng);
            price *= 1.0 + return_pct;
            price = price.max(0.01);
            
            // Generate trade size
            let raw_size: f64 = volume_dist.sample(&mut self.rng);
            let size = raw_size.max(1.0) as u32;
            
            // Random buy/sell
            let is_buy = self.rng.gen_bool(0.5);
            
            updates.push(MarketUpdate {
                symbol: symbol.clone(),
                timestamp: current_time,
                data: MarketDataType::Trade(Trade {
                    price,
                    size: size as f64,
                    side: if is_buy { Side::Buy } else { Side::Sell },
                }),
            });
            
            current_time = current_time + Duration::milliseconds(interval_ms);
        }
        
        updates
    }

    pub fn generate_bars(
        &mut self,
        symbol: String,
        start_time: DateTime<Utc>,
        end_time: DateTime<Utc>,
        timeframe: &str,
    ) -> Vec<MarketUpdate> {
        let mut updates = Vec::new();
        let mut current_time = start_time;
        let mut price = self.base_price;
        
        let interval = match timeframe {
            "1m" => Duration::minutes(1),
            "5m" => Duration::minutes(5),
            "15m" => Duration::minutes(15),
            "1h" => Duration::hours(1),
            "1d" => Duration::days(1),
            _ => Duration::minutes(1),
        };
        
        let price_dist = Normal::new(0.0, self.volatility).unwrap();
        let volume_dist = Normal::new(self.volume_mean, self.volume_std).unwrap();
        
        while current_time <= end_time {
            // Generate OHLC
            let open = price;
            let mut high = open;
            let mut low = open;
            
            // Simulate intrabar movements
            for _ in 0..4 {
                let move_pct = price_dist.sample(&mut self.rng) / 100.0;
                price *= 1.0 + move_pct;
                price = price.max(0.01);
                high = high.max(price);
                low = low.min(price);
            }
            
            let close = price;
            let volume = volume_dist.sample(&mut self.rng).max(0.0) as u64;
            
            updates.push(MarketUpdate {
                symbol: symbol.clone(),
                timestamp: current_time,
                data: MarketDataType::Bar(Bar {
                    open,
                    high,
                    low,
                    close,
                    volume: volume as f64,
                    vwap: Some((open + high + low + close) / 4.0),
                }),
            });
            
            current_time = current_time + interval;
        }
        
        updates
    }

    pub fn generate_mixed_data(
        &mut self,
        symbol: String,
        start_time: DateTime<Utc>,
        end_time: DateTime<Utc>,
    ) -> Vec<MarketUpdate> {
        let mut all_updates = Vec::new();
        
        // Generate quotes every 100ms
        let quotes = self.generate_quotes(
            symbol.clone(),
            start_time,
            end_time,
            100
        );
        all_updates.extend(quotes);
        
        // Generate trades
        let trades = self.generate_trades(
            symbol.clone(),
            start_time,
            end_time,
            20 // 20 trades per minute
        );
        all_updates.extend(trades);
        
        // Generate 1-minute bars
        let bars = self.generate_bars(
            symbol,
            start_time,
            end_time,
            "1m"
        );
        all_updates.extend(bars);
        
        // Sort by timestamp
        all_updates.sort_by_key(|update| update.timestamp);
        
        all_updates
    }
}