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

/// Live trading engine - connects to real brokers
pub struct LiveEngine {
    broker: String,
    account_id: String,
    broker_connection: Arc<dyn BrokerConnection>,
    is_running: Arc<RwLock<bool>>,
    shutdown_tx: Option<mpsc::Sender<()>>,
}

/// Trait for broker connections
#[async_trait]
pub trait BrokerConnection: Send + Sync {
    async fn connect(&mut self, account_id: &str) -> Result<(), String>;
    async fn disconnect(&mut self) -> Result<(), String>;
    async fn subscribe_market_data(&mut self, symbols: Vec<String>) -> Result<(), String>;
    async fn submit_order(&self, order: &Order) -> Result<String, String>;
    async fn cancel_order(&self, order_id: &str) -> Result<(), String>;
    async fn get_order_status(&self, order_id: &str) -> Result<OrderStatus, String>;
    async fn get_positions(&self) -> Result<Vec<crate::Position>, String>;
    async fn get_account_info(&self) -> Result<AccountInfo, String>;
}

#[derive(Debug, Clone)]
pub struct AccountInfo {
    pub cash: f64,
    pub buying_power: f64,
    pub portfolio_value: f64,
    pub day_trades_remaining: Option<u32>,
}

impl LiveEngine {
    pub fn new(
        broker: String,
        account_id: String,
        broker_connection: Arc<dyn BrokerConnection>,
    ) -> Self {
        Self {
            broker,
            account_id,
            broker_connection,
            is_running: Arc::new(RwLock::new(false)),
            shutdown_tx: None,
        }
    }
}

#[async_trait]
impl TradingEngine for LiveEngine {
    async fn start(&mut self, event_bus: &mut EventBus) -> Result<(), String> {
        *self.is_running.write() = true;
        
        // Connect to broker
        self.broker_connection.connect(&self.account_id).await?;
        
        // Get initial account info
        let account_info = self.broker_connection.get_account_info().await?;
        
        let (shutdown_tx, mut shutdown_rx) = mpsc::channel(1);
        self.shutdown_tx = Some(shutdown_tx);
        
        // Emit start event
        event_bus.publish(Event {
            event_type: EventType::SystemStart,
            timestamp: Utc::now(),
            data: serde_json::json!({
                "mode": "live",
                "broker": self.broker,
                "account_id": self.account_id,
                "account_info": {
                    "cash": account_info.cash,
                    "buying_power": account_info.buying_power,
                    "portfolio_value": account_info.portfolio_value,
                },
            }),
        }).await;
        
        // Main live trading loop
        loop {
            tokio::select! {
                _ = shutdown_rx.recv() => {
                    break;
                }
                _ = tokio::time::sleep(std::time::Duration::from_secs(1)) => {
                    // Periodic tasks (e.g., check positions, risk)
                    if !*self.is_running.read() {
                        break;
                    }
                    
                    // Could emit periodic status updates here
                }
            }
        }
        
        // Disconnect from broker
        self.broker_connection.disconnect().await?;
        
        // Emit stop event
        event_bus.publish(Event {
            event_type: EventType::SystemStop,
            timestamp: Utc::now(),
            data: serde_json::json!({
                "reason": "live_trading_stopped",
            }),
        }).await;
        
        Ok(())
    }
    
    async fn stop(&mut self) -> Result<(), String> {
        *self.is_running.write() = false;
        if let Some(tx) = self.shutdown_tx.take() {
            let _ = tx.send(()).await;
        }
        Ok(())
    }
    
    fn get_execution_handler(&self) -> Arc<dyn ExecutionHandler> {
        Arc::new(LiveExecutor {
            broker_connection: self.broker_connection.clone(),
        })
    }
    
    fn get_time_provider(&self) -> Arc<dyn TimeProvider> {
        Arc::new(RealTimeProvider)
    }
}

/// Live order executor - delegates to broker
#[derive(Clone)]
struct LiveExecutor {
    broker_connection: Arc<dyn BrokerConnection>,
}

#[async_trait]
impl ExecutionHandler for LiveExecutor {
    async fn submit_order(&self, order: &Order) -> Result<String, String> {
        // Validate order
        if order.quantity <= 0.0 {
            return Err("Invalid order quantity".to_string());
        }
        
        // Submit to broker
        self.broker_connection.submit_order(order).await
    }
    
    async fn cancel_order(&self, order_id: &str) -> Result<(), String> {
        self.broker_connection.cancel_order(order_id).await
    }
    
    async fn get_order_status(&self, order_id: &str) -> Result<OrderStatus, String> {
        self.broker_connection.get_order_status(order_id).await
    }
}

/// Real-time provider for live trading
struct RealTimeProvider;

impl TimeProvider for RealTimeProvider {
    fn now(&self) -> DateTime<Utc> {
        Utc::now()
    }
    
    fn sleep_until(&self, target: DateTime<Utc>) -> Result<(), String> {
        let now = Utc::now();
        if target > now {
            let duration = target.signed_duration_since(now);
            std::thread::sleep(duration.to_std().unwrap_or_default());
        }
        Ok(())
    }
}

// Example broker implementations would go here
// For now, we'll create a mock broker for testing

/// Mock broker for testing
pub struct MockBroker {
    is_connected: bool,
    orders: Arc<RwLock<Vec<(Order, OrderStatus)>>>,
}

impl MockBroker {
    pub fn new() -> Self {
        Self {
            is_connected: false,
            orders: Arc::new(RwLock::new(Vec::new())),
        }
    }
}

#[async_trait]
impl BrokerConnection for MockBroker {
    async fn connect(&mut self, _account_id: &str) -> Result<(), String> {
        self.is_connected = true;
        Ok(())
    }
    
    async fn disconnect(&mut self) -> Result<(), String> {
        self.is_connected = false;
        Ok(())
    }
    
    async fn subscribe_market_data(&mut self, _symbols: Vec<String>) -> Result<(), String> {
        if !self.is_connected {
            return Err("Not connected".to_string());
        }
        Ok(())
    }
    
    async fn submit_order(&self, order: &Order) -> Result<String, String> {
        if !self.is_connected {
            return Err("Not connected".to_string());
        }
        
        let order_id = order.id.clone();
        self.orders.write().push((order.clone(), OrderStatus::Pending));
        
        // Simulate order being filled after a delay
        let orders = self.orders.clone();
        let order_id_clone = order_id.clone();
        tokio::spawn(async move {
            tokio::time::sleep(std::time::Duration::from_millis(100)).await;
            let mut orders = orders.write();
            if let Some(pos) = orders.iter().position(|(o, _)| o.id == order_id_clone) {
                orders[pos].1 = OrderStatus::Filled;
            }
        });
        
        Ok(order_id)
    }
    
    async fn cancel_order(&self, order_id: &str) -> Result<(), String> {
        if !self.is_connected {
            return Err("Not connected".to_string());
        }
        
        let mut orders = self.orders.write();
        if let Some(pos) = orders.iter().position(|(o, _)| o.id == order_id) {
            orders[pos].1 = OrderStatus::Cancelled;
            Ok(())
        } else {
            Err("Order not found".to_string())
        }
    }
    
    async fn get_order_status(&self, order_id: &str) -> Result<OrderStatus, String> {
        if !self.is_connected {
            return Err("Not connected".to_string());
        }
        
        let orders = self.orders.read();
        if let Some((_, status)) = orders.iter().find(|(o, _)| o.id == order_id) {
            Ok(status.clone())
        } else {
            Err("Order not found".to_string())
        }
    }
    
    async fn get_positions(&self) -> Result<Vec<crate::Position>, String> {
        if !self.is_connected {
            return Err("Not connected".to_string());
        }
        Ok(Vec::new())
    }
    
    async fn get_account_info(&self) -> Result<AccountInfo, String> {
        if !self.is_connected {
            return Err("Not connected".to_string());
        }
        Ok(AccountInfo {
            cash: 100_000.0,
            buying_power: 400_000.0,
            portfolio_value: 100_000.0,
            day_trades_remaining: Some(3),
        })
    }
}