use async_trait::async_trait;
use chrono::{DateTime, Utc};
use std::sync::Arc;
use parking_lot::RwLock;
use crate::{
    MarketDataSource, ExecutionHandler, TimeProvider, FillSimulator,
    MarketUpdate, Order, OrderStatus, Fill, OrderBookSnapshot,
};
use crate::events::EventBus;
use crate::domain::{Event, EventType};
use super::TradingEngine;

/// Backtest-specific trading engine
pub struct BacktestEngine {
    start_time: DateTime<Utc>,
    end_time: DateTime<Utc>,
    current_time: DateTime<Utc>,
    speed_multiplier: f64,
    market_data: Box<dyn MarketDataSource>,
    execution: BacktestExecutor,
    is_running: Arc<RwLock<bool>>,
}

impl BacktestEngine {
    pub fn new(
        start_time: DateTime<Utc>,
        end_time: DateTime<Utc>,
        speed_multiplier: f64,
        market_data: Box<dyn MarketDataSource>,
    ) -> Self {
        Self {
            start_time,
            end_time,
            current_time: start_time,
            speed_multiplier,
            market_data,
            execution: BacktestExecutor::new(),
            is_running: Arc::new(RwLock::new(false)),
        }
    }
}

#[async_trait]
impl TradingEngine for BacktestEngine {
    async fn start(&mut self, event_bus: &mut EventBus) -> Result<(), String> {
        *self.is_running.write() = true;
        self.current_time = self.start_time;
        
        // Seek market data to start time
        self.market_data.seek_to_time(self.start_time)?;
        
        // Emit start event
        event_bus.publish(Event {
            event_type: EventType::SystemStart,
            timestamp: self.current_time,
            data: serde_json::json!({
                "mode": "backtest",
                "start_time": self.start_time,
                "end_time": self.end_time,
            }),
        }).await;
        
        // Main backtest loop
        while *self.is_running.read() && self.current_time < self.end_time {
            // Get next market update
            if let Some(update) = self.market_data.get_next_update().await {
                // Update current time
                self.current_time = update.timestamp;
                
                // Publish market data event
                event_bus.publish(Event {
                    event_type: EventType::MarketData(update.clone()),
                    timestamp: self.current_time,
                    data: serde_json::Value::Null,
                }).await;
                
                // Process any pending orders
                self.execution.process_orders(&update, event_bus).await?;
            } else {
                // No more data
                break;
            }
            
            // Simulate time passing (for UI updates, etc.)
            if self.speed_multiplier > 0.0 {
                tokio::time::sleep(std::time::Duration::from_millis(
                    (10.0 / self.speed_multiplier) as u64
                )).await;
            }
        }
        
        // Emit stop event
        event_bus.publish(Event {
            event_type: EventType::SystemStop,
            timestamp: self.current_time,
            data: serde_json::json!({
                "reason": "backtest_complete",
                "end_time": self.current_time,
            }),
        }).await;
        
        Ok(())
    }
    
    async fn stop(&mut self) -> Result<(), String> {
        *self.is_running.write() = false;
        Ok(())
    }
    
    fn get_execution_handler(&self) -> Arc<dyn ExecutionHandler> {
        Arc::new(self.execution.clone())
    }
    
    fn get_time_provider(&self) -> Arc<dyn TimeProvider> {
        Arc::new(BacktestTimeProvider {
            current_time: self.current_time,
        })
    }
}

/// Backtest order executor
#[derive(Clone)]
struct BacktestExecutor {
    pending_orders: Arc<RwLock<Vec<Order>>>,
    order_history: Arc<RwLock<Vec<(Order, OrderStatus)>>>,
    fill_simulator: BacktestFillSimulator,
}

impl BacktestExecutor {
    fn new() -> Self {
        Self {
            pending_orders: Arc::new(RwLock::new(Vec::new())),
            order_history: Arc::new(RwLock::new(Vec::new())),
            fill_simulator: BacktestFillSimulator::new(),
        }
    }
    
    async fn process_orders(
        &self,
        market_update: &MarketUpdate,
        event_bus: &mut EventBus,
    ) -> Result<(), String> {
        let mut orders = self.pending_orders.write();
        let mut filled_indices = Vec::new();
        
        for (idx, order) in orders.iter().enumerate() {
            if order.symbol != market_update.symbol {
                continue;
            }
            
            // Try to fill the order
            if let Some(fill) = self.fill_simulator.try_fill(order, market_update) {
                // Emit fill event
                event_bus.publish(Event {
                    event_type: EventType::OrderFill {
                        order_id: order.id.clone(),
                        fill: fill.clone(),
                    },
                    timestamp: market_update.timestamp,
                    data: serde_json::Value::Null,
                }).await;
                
                filled_indices.push(idx);
            }
        }
        
        // Remove filled orders
        for idx in filled_indices.into_iter().rev() {
            let order = orders.remove(idx);
            self.order_history.write().push((order, OrderStatus::Filled));
        }
        
        Ok(())
    }
}

#[async_trait]
impl ExecutionHandler for BacktestExecutor {
    async fn submit_order(&self, order: &Order) -> Result<String, String> {
        let order_id = order.id.clone();
        self.pending_orders.write().push(order.clone());
        Ok(order_id)
    }
    
    async fn cancel_order(&self, order_id: &str) -> Result<(), String> {
        let mut orders = self.pending_orders.write();
        if let Some(pos) = orders.iter().position(|o| o.id == order_id) {
            let order = orders.remove(pos);
            self.order_history.write().push((order, OrderStatus::Cancelled));
            Ok(())
        } else {
            Err("Order not found".to_string())
        }
    }
    
    async fn get_order_status(&self, order_id: &str) -> Result<OrderStatus, String> {
        // Check pending orders
        if self.pending_orders.read().iter().any(|o| o.id == order_id) {
            return Ok(OrderStatus::Pending);
        }
        
        // Check history
        if let Some((_, status)) = self.order_history.read()
            .iter()
            .find(|(o, _)| o.id == order_id) {
            return Ok(status.clone());
        }
        
        Err("Order not found".to_string())
    }
}

/// Backtest time provider
struct BacktestTimeProvider {
    current_time: DateTime<Utc>,
}

impl TimeProvider for BacktestTimeProvider {
    fn now(&self) -> DateTime<Utc> {
        self.current_time
    }
    
    fn sleep_until(&self, _target: DateTime<Utc>) -> Result<(), String> {
        // In backtest, we don't actually sleep
        Ok(())
    }
}

/// Backtest fill simulator
#[derive(Clone)]
struct BacktestFillSimulator {
    commission_rate: f64,
    slippage_bps: f64,
}

impl BacktestFillSimulator {
    fn new() -> Self {
        Self {
            commission_rate: 0.001, // 0.1%
            slippage_bps: 5.0, // 5 basis points
        }
    }
    
    fn try_fill(&self, order: &Order, market_update: &MarketUpdate) -> Option<Fill> {
        match &market_update.data {
            crate::MarketDataType::Quote(quote) => {
                self.simulate_fill(order, quote.bid, quote.ask - quote.bid)
            }
            crate::MarketDataType::Trade(trade) => {
                self.simulate_fill(order, trade.price, 0.0001 * trade.price) // 1bp spread estimate
            }
            crate::MarketDataType::Bar(bar) => {
                // Use close price with estimated spread
                self.simulate_fill(order, bar.close, 0.0002 * bar.close) // 2bp spread estimate
            }
        }
    }
}

impl FillSimulator for BacktestFillSimulator {
    fn simulate_fill(&self, order: &Order, market_price: f64, spread: f64) -> Option<Fill> {
        let fill_price = match order.order_type {
            crate::OrderType::Market => {
                // Fill at market with slippage
                let slippage = market_price * self.slippage_bps / 10000.0;
                match order.side {
                    crate::Side::Buy => market_price + spread/2.0 + slippage,
                    crate::Side::Sell => market_price - spread/2.0 - slippage,
                }
            }
            crate::OrderType::Limit { price } => {
                // Check if limit price is satisfied
                match order.side {
                    crate::Side::Buy if price >= market_price + spread/2.0 => price,
                    crate::Side::Sell if price <= market_price - spread/2.0 => price,
                    _ => return None, // Limit not satisfied
                }
            }
            _ => return None, // Other order types not implemented yet
        };
        
        let commission = fill_price * order.quantity * self.commission_rate;
        
        Some(Fill {
            timestamp: chrono::Utc::now(), // Will be overridden by engine
            price: fill_price,
            quantity: order.quantity,
            commission,
        })
    }
}