import time
import logging
import MetaTrader5 as mt5
from datetime import datetime
import pytz
from data_handler import DataHandler

logger = logging.getLogger("TradingBot")

def run_trading_loop(config, mt5_interface, market_structure, entry_signals, 
                    liquidity_provider, macro_timing, execution_handler, notification_manager,
                    session_checker, shutdown_flag=None):
    """Core trading loop function."""
    
    # Initialize data handler
    data_handler = DataHandler(mt5_interface, config)
    if not data_handler.fetch_initial_data():
        logger.error("Failed to fetch initial data. Exiting trading loop.")
        return

    # Update all open trades' SL to the most recent swing low/high at startup
    try:
        execution_handler.update_all_open_sl_to_swing()
        logger.info("All open trades' SL updated to most recent swing at startup.")
    except Exception as e:
        logger.error(f"Failed to update open trades' SL at startup: {str(e)}")

    logger.info("Starting trading loop for intraday and scalping...")
    last_signal_check = time.time()
    check_interval = 0.1
    
    timeframes = config['trading'].get('timeframes', ["M15"])  # Use all timeframes from config

    while not (shutdown_flag and shutdown_flag.is_set()):
        try:
            current_time = time.time()
            
            # Only check for signals if enough time has passed
            if current_time - last_signal_check >= check_interval:
                # Get latest market data
                data_cache = data_handler.get_latest_data()
                if not data_cache:
                    logger.error("Failed to get latest data")
                    time.sleep(0.1)  # Reduced sleep time
                    continue
                
                # Quick market structure check
                start_time = time.time()
                structure_analysis = market_structure.analyze(data_cache)
                analysis_time = time.time() - start_time
                
                if analysis_time > 0.05:  # Log if analysis takes more than 50ms
                    logger.warning(f"Slow market structure analysis: {analysis_time:.3f}s")
                
                # --- Multi-timeframe signal search ---
                for tf in timeframes:
                    # For iFVG logic, pass both M5 and M1 data if available
                    data_m5 = data_cache.get("M5")
                    data_m1 = data_cache.get("M1")
                    if tf == "M5":
                        signal = entry_signals.find_signal(data_cache, structure_analysis, timeframe=tf, data_m1=data_m1)
                    else:
                        signal = entry_signals.find_signal(data_cache, structure_analysis, timeframe=tf)
                    if signal is not None:
                        logger.info(f"Signal found on {tf}: {signal}")
                        # Add timing score
                        signal["timing_score"] = macro_timing.get_timing_score(data_cache)
                        # Execute the trade
                        if execution_handler.execute_trade(signal):
                            notification_manager.send_notification(f"Trade executed: {signal}")
                
                # Manage existing positions
                try:
                    execution_handler.manage_open_positions()
                except Exception as e:
                    logger.error(f"Error managing positions: {str(e)}")
                
                # --- Analyze and adjust all active trades ---
                try:
                    open_positions = mt5_interface.get_open_positions(symbol=config['trading']['symbol'])
                    for position in open_positions:
                        execution_handler.analyze_and_adjust_position(position)
                except Exception as e:
                    logger.error(f"Error analyzing/adjusting open positions: {str(e)}")
                
                last_signal_check = current_time
            
            # Sleep for a very short time to prevent CPU overload
            time.sleep(0.01)
        except Exception as e:
            logger.error(f"Error in trading loop: {str(e)}")
            time.sleep(0.1)

    logger.info("Trading loop stopped.") 