//! Test Market Data Generator for E2E Testing
//!
//! This module provides a simple market data event generator for testing purposes.
//! It publishes mock market data events to the event_publisher so that tests can
//! validate market data streaming functionality without requiring real providers.

use crate::event_streaming::events::{EventSeverity, TradingEvent, TradingEventType};
use crate::event_streaming::publisher::EventPublisher;
use chrono::Utc;
use serde_json::json;
use std::sync::Arc;
use std::time::Duration;
use tokio::time::interval;
use tracing::{debug, info};

/// Test market data generator for E2E testing
pub struct TestMarketDataGenerator {
    event_publisher: Arc<EventPublisher>,
    symbols: Vec<String>,
    base_price: f64,
    running: Arc<tokio::sync::RwLock<bool>>,
}

impl TestMarketDataGenerator {
    /// Create a new test market data generator
    pub fn new(event_publisher: Arc<EventPublisher>, symbols: Vec<String>) -> Self {
        Self {
            event_publisher,
            symbols,
            base_price: 150.0,
            running: Arc::new(tokio::sync::RwLock::new(false)),
        }
    }

    /// Start generating market data events
    pub async fn start(&self) {
        let mut running = self.running.write().await;
        if *running {
            debug!("Market data generator already running");
            return;
        }
        *running = true;
        drop(running);

        info!(
            "Starting test market data generator for {} symbols",
            self.symbols.len()
        );

        let event_publisher = Arc::clone(&self.event_publisher);
        let symbols = self.symbols.clone();
        let base_price = self.base_price;
        let running = Arc::clone(&self.running);

        tokio::spawn(async move {
            let mut tick_interval = interval(Duration::from_millis(100)); // 10 Hz
            let mut sequence = 0u64;

            loop {
                // Check if we should stop
                {
                    let is_running = running.read().await;
                    if !*is_running {
                        info!("Market data generator stopped");
                        break;
                    }
                }

                tick_interval.tick().await;

                // Generate price updates for all symbols
                for symbol in &symbols {
                    let price = base_price + (sequence as f64 * 0.01) % 10.0;
                    let volume = 100.0 + (sequence as f64 * 10.0) % 1000.0;

                    // Create price update event
                    let event = TradingEvent {
                        id: uuid::Uuid::new_v4().to_string(),
                        event_type: TradingEventType::PriceUpdate,
                        timestamp: Utc::now(),
                        source: "test_market_data_generator".to_string(),
                        correlation_id: Some(format!("md-{}-{}", symbol, sequence)),
                        severity: EventSeverity::Info,
                        payload: json!({
                            "symbol": symbol,
                            "price": price,
                            "volume": volume,
                            "timestamp": Utc::now().timestamp(),
                            "sequence": sequence,
                        })
                        .to_string(),
                        metadata: std::collections::HashMap::new(),
                    };

                    // Publish event (ignore errors in test mode)
                    let _ = event_publisher.publish(event).await;
                }

                sequence += 1;
            }
        });
    }

    /// Stop generating market data events
    pub async fn stop(&self) {
        let mut running = self.running.write().await;
        *running = false;
        info!("Stopping test market data generator");
    }

    /// Check if generator is running
    pub async fn is_running(&self) -> bool {
        *self.running.read().await
    }

    /// Publish a single market data burst for testing
    pub async fn publish_burst(&self, symbol: &str, count: usize) -> Result<(), String> {
        info!("Publishing {} market data events for {}", count, symbol);

        for i in 0..count {
            let price = self.base_price + (i as f64 * 0.01);
            let volume = 100.0 + (i as f64);

            let event = TradingEvent {
                id: uuid::Uuid::new_v4().to_string(),
                event_type: TradingEventType::PriceUpdate,
                timestamp: Utc::now(),
                source: "test_market_data_generator".to_string(),
                correlation_id: Some(format!("md-{}-{}", symbol, i)),
                severity: EventSeverity::Info,
                payload: json!({
                    "symbol": symbol,
                    "price": price,
                    "volume": volume,
                    "timestamp": Utc::now().timestamp(),
                    "sequence": i,
                })
                .to_string(),
                metadata: std::collections::HashMap::new(),
            };

            self.event_publisher
                .publish(event)
                .await
                .map_err(|e| format!("Failed to publish event: {}", e))?;
        }

        Ok(())
    }
}

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

    #[tokio::test]
    async fn test_generator_lifecycle() {
        let (sender, _) = broadcast::channel(1000);
        let publisher = Arc::new(EventPublisher::new(sender));
        let generator = TestMarketDataGenerator::new(publisher, vec!["TEST_SYMBOL".to_string()]);

        assert!(!generator.is_running().await);

        generator.start().await;
        tokio::time::sleep(Duration::from_millis(50)).await;
        assert!(generator.is_running().await);

        generator.stop().await;
        tokio::time::sleep(Duration::from_millis(50)).await;
        assert!(!generator.is_running().await);
    }

    #[tokio::test]
    async fn test_publish_burst() {
        let (sender, mut receiver) = broadcast::channel(1000);
        let publisher = Arc::new(EventPublisher::new(sender));
        let generator = TestMarketDataGenerator::new(publisher, vec!["TEST_SYMBOL".to_string()]);

        generator.publish_burst("TEST_SYMBOL", 10).await.unwrap();

        // Verify we can receive events
        let mut count = 0;
        while let Ok(event) = receiver.try_recv() {
            assert_eq!(event.event_type, TradingEventType::PriceUpdate);
            count += 1;
        }
        assert_eq!(count, 10);
    }
}
