"""Backtesting engine that coordinates the event-driven simulation.

This module contains the core engine that orchestrates the entire backtesting process
by managing the event loop, coordinating components, and ensuring proper chronological
processing of market data and trading events.
"""

import queue
from datetime import datetime

from .event import Event, StockEvent, SignalEvent, OrderEvent, FillEvent 
from .data import BaseDataHandler
from .strategy import BaseStrategy
from .portfolio import BasePortfolio
from .execution import BaseExecutionHandler


class BacktestEngine:
    """Core engine that runs the event-driven backtesting simulation.
    
    The BacktestEngine is the central coordinator that:
    1. Manages the main event loop
    2. Advances time by requesting new market data
    3. Processes events in the correct order
    4. Ensures proper communication between components
    5. Maintains chronological integrity (no look-ahead bias)
    
    The engine implements a two-phase loop:
    - **Time Advancement**: Get next market data from all symbols
    - **Event Processing**: Handle all events generated by that data
    
    This design ensures that:
    - All components see the same timestamp simultaneously
    - Events are processed in causal order (data → signal → order → fill)
    - No component can access future information
    
    Attributes:
        event_queue: Central queue for all inter-component communication
        data_handler: Streams historical market data chronologically
        strategy: Implements trading logic and generates signals
        portfolio: Manages positions, cash, and converts signals to orders
        execution_handler: Simulates order execution with realistic costs
    """

    def __init__(
        self,
        event_queue: queue.Queue,
        data_handler: BaseDataHandler,
        strategy: BaseStrategy,
        portfolio: BasePortfolio,
        execution_handler: BaseExecutionHandler,
    ):
        """Initialize the backtesting engine with all required components.
        
        Args:
            event_queue: Central event queue shared by all components
            data_handler: Provides chronological market data stream
            strategy: Trading strategy implementation
            portfolio: Portfolio management and position tracking
            execution_handler: Order execution simulation
        
        Note:
            All components must share the same event_queue instance to
            enable proper inter-component communication.
        """
        self.event_queue = event_queue
        self.data_handler = data_handler
        self.strategy = strategy
        self.portfolio = portfolio
        self.execution_handler = execution_handler

    def run(self):
        """Execute the complete backtesting simulation.
        
        This method implements the main event loop that drives the entire
        backtesting process. The loop operates in two phases:
        
        **Phase 1 - Time Advancement:**
        - Request next market data from data_handler
        - This puts StockEvent objects into the event queue
        - If no more data is available, StopIteration ends the backtest
        
        **Phase 2 - Event Processing:**
        - Process all events currently in the queue
        - Route each event to the appropriate component
        - Continue until queue is empty
        
        **Event Routing Logic:**
        - StockEvent → Strategy (for signal generation) + Portfolio (for valuation)
        - SignalEvent → Portfolio (to create orders)
        - OrderEvent → ExecutionHandler (to simulate fills)
        - FillEvent → Portfolio (to update positions)
        
        Returns:
            Portfolio: Final portfolio state containing:
                - equity_curve: Time series of portfolio values
                - trade_log: Complete history of executed trades
                - current_positions: Final position holdings
                - current_cash: Remaining cash balance
        
        Example:
            engine = BacktestEngine(queue, data, strategy, portfolio, execution)
            final_portfolio = engine.run()
            
            # Analyze results
            print(f"Final equity: ${final_portfolio.equity_curve[-1][1]:,.2f}")
            trades_df = get_trade_log_df(final_portfolio)
        
        Note:
            The engine processes events synchronously in a single thread.
            This ensures deterministic results and proper event ordering.
            
            The two-phase approach prevents infinite loops that could occur
            if new events were processed immediately as they're generated.
        """
        print(f"--- Backtest Started at {datetime.now()} ---")

        # Main simulation loop
        while True:
            # Phase 1: Advance time and get new market data
            try:
                self.data_handler.update_bars()
            except StopIteration:
                # No more historical data available
                break

            # Phase 2: Process all events generated by the new data
            while not self.event_queue.empty():
                try:
                    event = self.event_queue.get(block=False)
                except queue.Empty:
                    # Queue is empty, continue to next time step
                    break
                
                # Route events to appropriate handlers
                if isinstance(event, StockEvent):
                    # New market data: update strategy and portfolio
                    self.strategy.on_stock_event(event)
                    self.portfolio.on_stock_event(event)

                elif isinstance(event, SignalEvent):
                    # Trading signal: convert to order
                    self.portfolio.on_signal_event(event)

                elif isinstance(event, OrderEvent):
                    # Order placement: simulate execution
                    self.execution_handler.on_order_event(event)

                elif isinstance(event, FillEvent):
                    # Trade execution: update portfolio
                    self.portfolio.on_fill_event(event)

        print(f"--- Backtest Finished at {datetime.now()} ---")

        return self.portfolio





            






        

