//! Core Trading Engine
//!
//! This is the main trading engine that handles all business logic.
//! TLI delegates to this engine via clean service boundaries.

use chrono::Utc;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::broadcast;
use tracing::info;
use uuid::Uuid;

use super::{
    account_manager::AccountManager,
    broker_client::BrokerClient,
    data_interface::{DataProvider, DataType, Subscription},
    order_manager::OrderManager,
    position_manager::PositionManager,
};
use crate::trading_operations::{
    ArbitrageOpportunity, ExecutionResult, TradingOperations, TradingOrder, TradingStats,
};
use common::{MarketDataEvent, Position};
use common::{OrderId, OrderSide, OrderStatus, OrderType, TimeInForce};
use rust_decimal::Decimal;

/// Core Trading Engine that handles all trading business logic
#[derive(Debug)]
/// TradingEngine
///
/// Auto-generated documentation placeholder - enhance with specifics
pub struct TradingEngine {
    /// Order management
    order_manager: Arc<OrderManager>,
    /// Position management  
    position_manager: Arc<PositionManager>,
    /// Account management
    account_manager: Arc<AccountManager>,
    /// Broker client for execution
    broker_client: Arc<BrokerClient>,
    /// Trading operations metrics
    trading_ops: Arc<TradingOperations>,
    /// Data provider for market data
    data_provider: Arc<dyn DataProvider>,
}

impl TradingEngine {
    /// Create a new trading engine
    pub fn new(data_provider: Arc<dyn DataProvider>) -> Self {
        let order_manager = Arc::new(OrderManager::new());
        let position_manager = Arc::new(PositionManager::new());
        let account_manager = Arc::new(AccountManager::new());
        let broker_client = Arc::new(BrokerClient::new());
        let trading_ops = Arc::new(TradingOperations::new());

        Self {
            order_manager,
            position_manager,
            account_manager,
            broker_client,
            trading_ops,
            data_provider,
        }
    }

    /// Submit a new order through the trading engine
    pub async fn submit_order(
        &self,
        symbol: String,
        side: OrderSide,
        order_type: OrderType,
        quantity: Decimal,
        price: Option<Decimal>,
        _stop_price: Option<Decimal>,
    ) -> Result<String, String> {
        // Generate order ID
        let _order_id = format!("ORD_{}", Uuid::new_v4().simple());

        info!(
            "Trading engine submitting order: {} {} {} @ {:?}",
            side, quantity, symbol, price
        );

        // Create trading order
        let order = TradingOrder {
            id: OrderId::new(),
            symbol: symbol.clone(),
            side,
            order_type,
            quantity,
            price: price.unwrap_or(Decimal::ZERO),
            time_in_force: TimeInForce::Day,
            account_id: None,
            metadata: HashMap::new(),
            created_at: Utc::now(),
            submitted_at: None,
            executed_at: None,
            status: OrderStatus::Created,
            fill_quantity: Decimal::ZERO,
            average_fill_price: None,
        };

        // Atomic validate + add (prevents duplicate order ID race condition)
        self.order_manager
            .validate_and_add_order(order.clone())
            .await?;

        // Check account requirements
        self.account_manager.check_buying_power(&order).await?;

        // Submit to trading operations for metrics tracking
        let order_id = self.trading_ops.submit_order(order.clone()).await?;

        // Send to broker for execution
        self.broker_client
            .submit_order(order)
            .await
            .map_err(|e| e.to_string())?;

        info!(
            "Order {} submitted successfully through trading engine",
            order_id
        );

        // Ok variant
        Ok(order_id)
    }

    /// Cancel an existing order
    pub async fn cancel_order(&self, order_id: OrderId) -> Result<(), String> {
        info!("Trading engine cancelling order: {}", order_id);

        // Get order from manager
        let order = self
            .order_manager
            .get_order(&order_id)
            .await
            .ok_or("Order not found")?;

        // Check if cancellable
        if matches!(order.status, OrderStatus::Filled) {
            return Err("Cannot cancel filled order".to_owned());
        }

        // Send cancel to broker
        self.broker_client
            .cancel_order(&order_id)
            .await
            .map_err(|e| e.to_string())?;

        // Update order manager
        self.order_manager
            .update_order_status(&order_id, OrderStatus::Cancelled)
            .await?;

        info!("Order {} cancelled successfully", order_id);

        Ok(())
    }

    /// Get order status
    pub async fn get_order_status(&self, order_id: OrderId) -> Result<TradingOrder, String> {
        self.order_manager
            .get_order(&order_id)
            .await
            .ok_or("Order not found".to_owned())
    }

    /// Get account information
    pub async fn get_account_info(&self, account_id: String) -> Result<AccountInfo, String> {
        self.account_manager.get_account_info(&account_id).await
    }

    /// Get positions
    pub async fn get_positions(
        &self,
        symbol_filter: Option<String>,
    ) -> Result<Vec<Position>, String> {
        self.position_manager.get_positions(symbol_filter)
    }

    /// Subscribe to market data events
    pub async fn subscribe_market_data(
        &self,
        symbols: Vec<String>,
    ) -> Result<broadcast::Receiver<MarketDataEvent>, String> {
        info!(
            "Trading engine subscribing to market data for symbols: {:?}",
            symbols
        );

        // Subscribe via data provider
        let subscription = Subscription {
            symbols: symbols.clone(),
            data_types: vec![DataType::Trades, DataType::Quotes],
            exchanges: None,
            extended_hours: false,
        };

        self.data_provider
            .subscribe_market_data(subscription)
            .await
            .map_err(|e| format!("Failed to subscribe to market data: {}", e))?;

        // Return the broadcast receiver
        Ok(self.data_provider.subscribe_market_data_events())
    }

    /// Subscribe to order update events
    pub async fn subscribe_order_updates(
        &self,
        account_id: Option<String>,
    ) -> Result<broadcast::Receiver<MarketDataEvent>, String> {
        info!(
            "Trading engine subscribing to order updates for account: {:?}",
            account_id
        );

        // Return the broadcast receiver
        Ok(self.data_provider.subscribe_order_update_events())
    }

    /// Process order execution from broker
    pub async fn process_execution(&self, execution: ExecutionResult) -> Result<(), String> {
        info!(
            "Trading engine processing execution: {} {} @ {}",
            execution.executed_quantity, execution.symbol, execution.execution_price
        );

        // Process through trading operations for metrics
        self.trading_ops
            .process_execution(execution.clone())
            .await?;

        // Update order manager
        self.order_manager.process_execution(&execution).await?;

        // Update position manager
        self.position_manager.update_position(&execution)?;

        // Update account manager
        self.account_manager
            .update_from_execution(&execution)
            .await?;

        Ok(())
    }

    /// Get trading statistics
    pub async fn get_trading_stats(&self) -> TradingStats {
        self.trading_ops.get_trading_stats().await
    }

    /// Update market making quotes
    pub async fn update_market_making_quotes(
        &self,
        symbol: String,
        bid_price: Decimal,
        ask_price: Decimal,
        bid_quantity: Decimal,
        ask_quantity: Decimal,
    ) -> Result<(), String> {
        self.trading_ops
            .update_market_making_quotes(&symbol, bid_price, ask_price, bid_quantity, ask_quantity)
            .await
    }

    /// Detect arbitrage opportunities
    pub async fn detect_arbitrage_opportunity(
        &self,
        symbol: String,
        exchange1_price: Decimal,
        exchange2_price: Decimal,
        min_profit_bps: f64,
    ) -> Option<ArbitrageOpportunity> {
        self.trading_ops
            .detect_arbitrage_opportunity(&symbol, exchange1_price, exchange2_price, min_profit_bps)
            .await
    }

    /// Get broker client (test-only accessor)
    ///
    /// **WARNING: This method should ONLY be used in test code.**
    pub fn broker_client(&self) -> &Arc<BrokerClient> {
        &self.broker_client
    }
}

/// Account information structure
#[derive(Debug, Clone)]
/// AccountInfo
///
/// Auto-generated documentation placeholder - enhance with specifics
pub struct AccountInfo {
    /// Account Id
    pub account_id: String,
    /// Total Value
    pub total_value: Decimal,
    /// Cash Balance
    pub cash_balance: Decimal,
    /// Buying Power
    pub buying_power: Decimal,
    /// Maintenance Margin
    pub maintenance_margin: Decimal,
    /// Day Trading Buying Power
    pub day_trading_buying_power: Decimal,
}

/// Position structure
// CANONICAL Position type imported from types::basic
// Removed pub use - import Position directly where needed
#[cfg(test)]
#[allow(clippy::assertions_on_constants)]
mod tests {

    #[tokio::test]
    async fn test_trading_engine_creation() {
        // This would need a proper DataManager mock for real testing
        // For now, just test the structure
        assert!(true); // Production until DataManager mock is available
    }

    #[tokio::test]
    async fn test_order_submission_flow() {
        // Test the order submission workflow
        // This would require proper mocking of all dependencies
        assert!(true); // Production
    }
}
