"""
Main application class that orchestrates all components and threads
"""

import sys
import time
import logging
import threading
import signal
from typing import Optional, Dict, Any
from pathlib import Path

from ..config.settings import AppSettings
from ..config.manager import ConfigManager
from ..database.manager import DatabaseManager
from .message_bus import MessageBus, Message, MessageType, MessageBuilder
from .thread_manager import ThreadManager
from .udp_broadcast import UDPBroadcastComponent

logger = logging.getLogger(__name__)


class MbetterClientApplication:
    """Main application class that coordinates all components"""
    
    def __init__(self, settings: AppSettings, start_timer: Optional[int] = None):
        self.settings = settings
        self.running = False
        self.shutdown_event = threading.Event()

        # Store the command line start_timer setting separately (not affected by database override)
        self._start_timer_minutes = start_timer
        
        # Core components
        self.db_manager: Optional[DatabaseManager] = None
        self.config_manager: Optional[ConfigManager] = None
        self.message_bus: Optional[MessageBus] = None
        self.thread_manager: Optional[ThreadManager] = None
        
        # Component references
        self.qt_player = None
        self.web_dashboard = None
        self.api_client = None
        self.template_watcher = None
        self.screen_cast = None
        self.games_thread = None
        self.match_timer = None
        self.udp_broadcast = None
        
        # Main loop thread
        self._main_loop_thread: Optional[threading.Thread] = None

        # Timer for automated game start
        self._game_start_timer: Optional[threading.Timer] = None
        self._original_timer_interval: Optional[int] = None  # Store original interval for retries

        logger.info("MbetterClient application initialized")
    
    def initialize(self) -> bool:
        """Initialize all application components"""
        try:
            logger.info("Initializing MbetterClient application...")
            
            # Ensure persistent directories exist first
            logger.info("Creating persistent directories...")
            self.settings.ensure_directories()
            
            # Initialize database manager
            if not self._initialize_database():
                return False
            
            # Initialize configuration manager
            if not self._initialize_config():
                return False
            
            # Initialize message bus
            if not self._initialize_message_bus():
                return False
            
            # Initialize thread manager
            if not self._initialize_thread_manager():
                return False
            
            # Initialize components based on settings
            if not self._initialize_components():
                return False
            
            logger.info("MbetterClient application initialized successfully")
            return True
            
        except Exception as e:
            logger.error(f"Failed to initialize application: {e}")
            return False
    
    def _initialize_database(self) -> bool:
        """Initialize database manager"""
        try:
            db_path = self.settings.database.get_absolute_path()
            self.db_manager = DatabaseManager(str(db_path))
            
            if not self.db_manager.initialize():
                logger.error("Database manager initialization failed")
                return False
            
            logger.info("Database manager initialized")
            return True
            
        except Exception as e:
            logger.error(f"Database initialization failed: {e}")
            return False
    
    def _initialize_config(self) -> bool:
        """Initialize configuration manager"""
        try:
            self.config_manager = ConfigManager(self.db_manager)
            
            if not self.config_manager.initialize():
                logger.error("Configuration manager initialization failed")
                return False
            
            # Update settings from database
            stored_settings = self.config_manager.get_settings()
            if stored_settings:
                # Preserve command-line rustdesk_id before merging
                command_line_rustdesk_id = getattr(self.settings.api, 'rustdesk_id', None)

                # Merge runtime settings with stored settings (command line overrides database)
                stored_settings.fullscreen = self.settings.fullscreen
                stored_settings.web_host = self.settings.web_host
                stored_settings.web_port = self.settings.web_port
                stored_settings.database_path = self.settings.database_path
                stored_settings.enable_qt = self.settings.enable_qt
                stored_settings.enable_web = self.settings.enable_web
                stored_settings.enable_screen_cast = self.settings.enable_screen_cast  # Preserve screen cast setting
                
                # Preserve command line Qt overlay setting
                stored_settings.qt.use_native_overlay = self.settings.qt.use_native_overlay

                # Preserve command line debug settings
                stored_settings.debug_overlay = self.settings.debug_overlay
                stored_settings.debug_player = self.settings.debug_player

                # Preserve command line SSL settings
                stored_settings.web.enable_ssl = self.settings.web.enable_ssl
                stored_settings.web.ssl_cert_path = self.settings.web.ssl_cert_path
                stored_settings.web.ssl_key_path = self.settings.web.ssl_key_path
                stored_settings.web.ssl_auto_generate = self.settings.web.ssl_auto_generate

                self.settings = stored_settings

                # Restore command-line rustdesk_id after settings merge
                if command_line_rustdesk_id is not None:
                    self.settings.api.rustdesk_id = command_line_rustdesk_id
                    logger.debug("APPLICATION: Restored command-line rustdesk_id: {}".format(command_line_rustdesk_id))
                
                # Re-sync runtime settings to component configs
                self.settings.qt.fullscreen = self.settings.fullscreen
                self.settings.web.host = self.settings.web_host
                self.settings.web.port = self.settings.web_port
                if self.settings.database_path:
                    self.settings.database.path = self.settings.database_path
            
            logger.info("Configuration manager initialized")
            return True
            
        except Exception as e:
            logger.error(f"Configuration initialization failed: {e}")
            return False
    
    def _initialize_message_bus(self) -> bool:
        """Initialize message bus"""
        try:
            self.message_bus = MessageBus(max_queue_size=1000, dev_message=self.settings.dev_message, debug_messages=self.settings.debug_messages)
            
            # Register core component
            self.message_bus.register_component("core")
            
            # Subscribe to system messages
            self.message_bus.subscribe("core", MessageType.SYSTEM_SHUTDOWN, self._handle_shutdown_message)
            self.message_bus.subscribe("core", MessageType.CONFIG_UPDATE, self._handle_config_update)
            self.message_bus.subscribe("core", MessageType.LOG_ENTRY, self._handle_log_entry)
            self.message_bus.subscribe("core", MessageType.GAME_STATUS, self._handle_game_status_response)
            
            logger.info("Message bus initialized")
            return True
            
        except Exception as e:
            logger.error(f"Message bus initialization failed: {e}")
            return False
    
    def _initialize_thread_manager(self) -> bool:
        """Initialize thread manager"""
        try:
            self.thread_manager = ThreadManager(
                message_bus=self.message_bus,
                settings=self.settings
            )
            
            logger.info("Thread manager initialized")
            return True
            
        except Exception as e:
            logger.error(f"Thread manager initialization failed: {e}")
            return False
    
    def _initialize_components(self) -> bool:
        """Initialize application components based on settings"""
        try:
            components_initialized = 0
            
            # Initialize template watcher
            if self._initialize_template_watcher():
                components_initialized += 1
            else:
                logger.error("Template watcher initialization failed")
                return False
            
            # Initialize PyQt video player
            if self.settings.enable_qt:
                if self._initialize_qt_player():
                    components_initialized += 1
                else:
                    logger.error("Qt player initialization failed")
                    return False
            
            # Initialize web dashboard
            if self.settings.enable_web:
                if self._initialize_web_dashboard():
                    components_initialized += 1
                else:
                    logger.error("Web dashboard initialization failed")
                    return False
            
            # Initialize API client
            if self.settings.enable_api_client:
                if self._initialize_api_client():
                    components_initialized += 1
                else:
                    logger.error("API client initialization failed")
                    return False
            
            # Initialize screen cast component
            if self.settings.enable_screen_cast:
                logger.info("Initializing screen cast component...")
                if self._initialize_screen_cast():
                    components_initialized += 1
                else:
                    logger.error("Screen cast initialization failed")
                    return False
            else:
                logger.info("Screen cast component disabled")

            # Initialize games thread
            if self._initialize_games_thread():
                components_initialized += 1
            else:
                logger.error("Games thread initialization failed")
                return False

            # Initialize match timer
            if self._initialize_match_timer():
                components_initialized += 1
            else:
                logger.error("Match timer initialization failed")
                return False

            # Initialize UDP broadcast component
            if self._initialize_udp_broadcast():
                components_initialized += 1
            else:
                logger.error("UDP broadcast initialization failed")
                return False
            
            if components_initialized == 0:
                logger.error("No components were initialized")
                return False
            
            logger.info(f"{components_initialized} components initialized")
            return True
            
        except Exception as e:
            logger.error(f"Component initialization failed: {e}")
            return False
    
    def _initialize_template_watcher(self) -> bool:
        """Initialize template file watcher"""
        try:
            from ..qt_player.template_watcher import TemplateWatcher
            
            # Built-in templates directory is in qt_player folder
            builtin_templates_dir = Path(__file__).parent.parent / "qt_player" / "templates"
            
            # Get persistent uploaded templates directory
            uploaded_templates_dir = self._get_persistent_templates_dir()
            uploaded_templates_dir.mkdir(parents=True, exist_ok=True)
            
            self.template_watcher = TemplateWatcher(
                message_bus=self.message_bus,
                templates_dir=str(builtin_templates_dir),
                uploaded_templates_dir=str(uploaded_templates_dir)
            )
            
            # Register with thread manager
            self.thread_manager.register_component("template_watcher", self.template_watcher)
            
            logger.info(f"Template watcher initialized - builtin: {builtin_templates_dir}, uploaded: {uploaded_templates_dir}")
            return True
            
        except Exception as e:
            logger.error(f"Template watcher initialization failed: {e}")
            return False
    
    def _get_persistent_templates_dir(self) -> Path:
        """Get persistent templates directory for user uploads"""
        try:
            # Use the consistent user config directory from settings
            return self.settings.get_user_config_dir() / "templates"
                
        except Exception as e:
            logger.error(f"Failed to determine persistent templates directory: {e}")
            # Fallback to local directory
            return Path.cwd() / "user_templates"
    
    def _initialize_qt_player(self) -> bool:
        """Initialize PyQt video player"""
        try:
            from ..qt_player.player import QtVideoPlayer
            
            self.qt_player = QtVideoPlayer(
                message_bus=self.message_bus,
                settings=self.settings.qt,
                debug_player=self.settings.debug_player,
                debug_overlay=self.settings.debug_overlay
            )
            
            # Don't register with thread manager since QtPlayer no longer inherits from ThreadedComponent
            # Instead, we'll handle it separately in the run method
            pass
            
            logger.info("Qt player initialized")
            return True
            
        except Exception as e:
            logger.error(f"Qt player initialization failed: {e}")
            return False
    
    def _initialize_web_dashboard(self) -> bool:
        """Initialize web dashboard"""
        try:
            from ..web_dashboard.app import WebDashboard
            
            self.web_dashboard = WebDashboard(
                message_bus=self.message_bus,
                db_manager=self.db_manager,
                config_manager=self.config_manager,
                settings=self.settings.web
            )
            
            # Set reference to main application for component access
            self.web_dashboard.set_main_application(self)
            
            # Register with thread manager
            self.thread_manager.register_component("web_dashboard", self.web_dashboard)
            
            logger.info("Web dashboard initialized")
            return True
            
        except Exception as e:
            logger.error(f"Web dashboard initialization failed: {e}")
            return False
    
    def _initialize_api_client(self) -> bool:
        """Initialize API client"""
        try:
            from ..api_client.client import APIClient
            
            self.api_client = APIClient(
                message_bus=self.message_bus,
                db_manager=self.db_manager,
                config_manager=self.config_manager,
                settings=self.settings.api
            )
            
            # Register with thread manager
            self.thread_manager.register_component("api_client", self.api_client)
            
            logger.info("API client initialized")
            return True
            
        except Exception as e:
            logger.error(f"API client initialization failed: {e}")
            return False
    
    def _initialize_screen_cast(self) -> bool:
        """Initialize screen cast component"""
        try:
            from .screen_cast import ScreenCastComponent

            # Use configuration from settings
            config = self.settings.screen_cast

            # Set output directory to user data dir if not specified
            output_dir = config.output_dir
            if not output_dir:
                output_dir = str(self.settings.get_user_data_dir() / "screen_cast")

            self.screen_cast = ScreenCastComponent(
                message_bus=self.message_bus,
                stream_port=config.stream_port,
                chromecast_name=config.chromecast_name,
                output_dir=output_dir
            )

            # Register with thread manager
            self.thread_manager.register_component("screen_cast", self.screen_cast)

            logger.info(f"Screen cast component initialized on port {config.stream_port}")
            return True

        except Exception as e:
            logger.error(f"Screen cast initialization failed: {e}")
            return False

    def _initialize_games_thread(self) -> bool:
        """Initialize games thread component"""
        try:
            from .games_thread import GamesThread

            self.games_thread = GamesThread(
                name="games_thread",
                message_bus=self.message_bus,
                db_manager=self.db_manager
            )

            # Register with thread manager
            self.thread_manager.register_component("games_thread", self.games_thread)

            logger.info("Games thread component initialized")
            return True

        except Exception as e:
            logger.error(f"Games thread initialization failed: {e}")
            return False

    def _initialize_match_timer(self) -> bool:
        """Initialize match timer component"""
        try:
            from .match_timer import MatchTimerComponent

            self.match_timer = MatchTimerComponent(
                message_bus=self.message_bus,
                db_manager=self.db_manager,
                config_manager=self.config_manager
            )

            # Register with thread manager
            self.thread_manager.register_component("match_timer", self.match_timer)

            logger.info("Match timer component initialized")
            return True

        except Exception as e:
            logger.error(f"Match timer initialization failed: {e}")
            return False

    def _initialize_udp_broadcast(self) -> bool:
        """Initialize UDP broadcast component"""
        try:
            self.udp_broadcast = UDPBroadcastComponent(
                message_bus=self.message_bus,
                broadcast_port=45123  # Default UDP broadcast port
            )

            # Register with thread manager
            self.thread_manager.register_component("udp_broadcast", self.udp_broadcast)

            logger.info("UDP broadcast component initialized")
            return True

        except Exception as e:
            logger.error(f"UDP broadcast initialization failed: {e}")
            return False
    
    def run(self) -> int:
        """Run the application"""
        try:
            logger.info("Starting MbetterClient application...")
            
            self.running = True
            
            # Initialize Qt player if enabled
            qt_player_initialized = False
            if self.settings.enable_qt and self.qt_player:
                if self.qt_player.initialize():
                    qt_player_initialized = True
                    logger.info("Qt player initialized successfully")
                else:
                    logger.error("Failed to initialize Qt player")
                    return 1
            
            # Start all other components
            if not self.thread_manager.start_all():
                logger.error("Failed to start components")
                return 1
            
            # Start main loop in separate thread
            self._main_loop_thread = threading.Thread(
                target=self._main_loop,
                name="MainLoop",
                daemon=True
            )
            self._main_loop_thread.start()
            
            # Send system ready message
            ready_message = MessageBuilder.system_status(
                sender="core",
                status="ready",
                details={
                    "components": self.thread_manager.get_component_names(),
                    "version": self.settings.version
                }
            )
            self.message_bus.publish(ready_message, broadcast=True)

            # Start automated game timer if specified on command line
            if self._start_timer_minutes is not None:
                logger.info(f"Command line timer enabled, starting {self._start_timer_minutes} minute timer")
                self._start_game_timer()

            logger.info("MbetterClient application started successfully")

            # If Qt player is enabled, run its event loop on the main thread
            if qt_player_initialized:
                logger.info("Running Qt player event loop on main thread")

                # Setup Qt-specific signal handling since Qt takes over the main thread
                if hasattr(self.qt_player, 'app') and self.qt_player.app:
                    # Connect Qt's aboutToQuit signal to our shutdown
                    self.qt_player.app.aboutToQuit.connect(self._qt_about_to_quit)
                    # Ensure Qt exits when last window closes
                    self.qt_player.app.setQuitOnLastWindowClosed(True)

                return self.qt_player.run()
            else:
                # No UI components - keep application running in background mode
                logger.info("No UI components enabled - running in background mode")
                # Wait for shutdown signal (Ctrl+C, etc.)
                while self.running and not self.shutdown_event.is_set():
                    self.shutdown_event.wait(timeout=1.0)
            
            logger.info("Application shutdown initiated")
            return self._cleanup()
            
        except KeyboardInterrupt:
            logger.info("Application interrupted by user (Ctrl+C)")
            self.shutdown()
            return self._cleanup()
        except Exception as e:
            logger.error(f"Application run failed: {e}")
            self.shutdown()
            return self._cleanup()
    
    def _main_loop(self):
        """Main application loop for message processing and coordination"""
        logger.info("Main loop started")
        
        last_stats_time = time.time()
        stats_interval = 60  # Log stats every minute
        
        try:
            while self.running and not self.shutdown_event.is_set():
                try:
                    # Process messages
                    message = self.message_bus.get_message("core", timeout=1.0)
                    if message:
                        self._process_core_message(message)
                    
                    # Periodic tasks
                    current_time = time.time()
                    
                    # Log statistics
                    if current_time - last_stats_time >= stats_interval:
                        self._log_statistics()
                        last_stats_time = current_time
                    
                    # Placeholder for additional tasks
                    self._run_additional_tasks()
                    
                    # Check component health
                    self._check_component_health()
                    
                except Exception as e:
                    logger.error(f"Main loop error: {e}")
                    time.sleep(1)  # Prevent tight error loop
                    
        except Exception as e:
            logger.error(f"Main loop fatal error: {e}")
        
        logger.info("Main loop ended")
    
    def _process_core_message(self, message: Message):
        """Process messages received by the core component"""
        try:
            # Suppress debug logging for VIDEO_PROGRESS messages to reduce log noise
            if message.type != MessageType.VIDEO_PROGRESS:
                logger.debug(f"Core processing message: {message}")

            if message.type == MessageType.SYSTEM_STATUS:
                self._handle_system_status(message)
            elif message.type == MessageType.SYSTEM_ERROR:
                self._handle_system_error(message)
            elif message.type == MessageType.CONFIG_REQUEST:
                self._handle_config_request(message)
            elif message.type == MessageType.START_GAME:
                self._handle_start_game_message(message)
            elif message.type == MessageType.GAME_STATUS:
                self._handle_game_status_response(message)
            elif message.type == MessageType.SYSTEM_SHUTDOWN:
                self._handle_shutdown_message(message)
            else:
                # Suppress debug logging for VIDEO_PROGRESS messages to reduce log noise
                if message.type != MessageType.VIDEO_PROGRESS:
                    logger.debug(f"Unhandled message type in core: {message.type}")

        except Exception as e:
            logger.error(f"Failed to process core message: {e}")
    
    def _handle_system_status(self, message: Message):
        """Handle system status messages"""
        try:
            status = message.data.get("status", "unknown")
            details = message.data.get("details", {})
            
            logger.info(f"System status from {message.sender}: {status}")
            
            if status == "error":
                logger.warning(f"Component error: {details}")
            elif status == "ready":
                logger.info(f"Component ready: {message.sender}")
                
        except Exception as e:
            logger.error(f"Failed to handle system status: {e}")
    
    def _handle_system_error(self, message: Message):
        """Handle system error messages"""
        try:
            error_msg = message.data.get("error", "Unknown error")
            details = message.data.get("details", {})
            
            logger.error(f"System error from {message.sender}: {error_msg}")
            logger.error(f"Error details: {details}")
            
            # TODO: Implement error recovery strategies
            
        except Exception as e:
            logger.error(f"Failed to handle system error: {e}")
    
    def _handle_config_request(self, message: Message):
        """Handle configuration requests"""
        try:
            requested_section = message.data.get("section", "all")
            
            if requested_section == "all":
                config_data = self.config_manager.get_web_config_dict()
            else:
                config_data = getattr(self.settings, requested_section, {})
                if hasattr(config_data, "__dict__"):
                    config_data = config_data.__dict__
            
            # Send response
            response = MessageBuilder.config_update(
                sender="core",
                config_section=requested_section,
                config_data=config_data
            )
            response.recipient = message.sender
            response.correlation_id = message.correlation_id
            
            self.message_bus.publish(response)
            
        except Exception as e:
            logger.error(f"Failed to handle config request: {e}")
    
    def _handle_shutdown_message(self, message: Message):
        """Handle shutdown message"""
        logger.info(f"Shutdown message received from {message.sender}")
        
        # If shutdown is requested from web dashboard, force immediate exit
        if message.sender == "web_dashboard":
            logger.info("Web dashboard requested shutdown - forcing immediate application exit")
            
            # Stop all background components quickly
            try:
                if self.thread_manager:
                    self.thread_manager.stop_all(timeout=1.0)
                if self.message_bus:
                    self.message_bus.shutdown()
                if self.db_manager:
                    self.db_manager.close()
            except Exception as e:
                logger.error(f"Error during forced shutdown: {e}")
            
            # Force immediate exit - don't try to interact with Qt
            logger.info("Forcing immediate application termination")
            import os
            os._exit(0)
        else:
            # For other senders (like Qt player), just set the shutdown event
            self.running = False
            self.shutdown_event.set()
    
    def _handle_config_update(self, message: Message):
        """Handle configuration update message"""
        try:
            config_section = message.data.get("config_section")
            config_data = message.data.get("config_data")
            
            logger.info(f"Configuration update for section: {config_section}")
            
            # Update configuration
            if self.config_manager.update_from_web(config_data):
                logger.info("Configuration updated successfully")
                
                # Broadcast update to all components
                update_message = MessageBuilder.config_update(
                    sender="core",
                    config_section=config_section,
                    config_data=config_data
                )
                self.message_bus.publish(update_message, broadcast=True)
            else:
                logger.error("Configuration update failed")
                
        except Exception as e:
            logger.error(f"Failed to handle config update: {e}")
    
    def _handle_log_entry(self, message: Message):
        """Handle log entry message"""
        try:
            level = message.data.get("level", "INFO")
            log_message = message.data.get("message", "")
            details = message.data.get("details", {})

            # Add to database log
            self.db_manager.add_log_entry(
                level=level,
                component=message.sender,
                message=log_message,
                details=details
            )

        except Exception as e:
            logger.error(f"Failed to handle log entry: {e}")

    def _handle_start_game_message(self, message: Message):
        """Handle START_GAME message - timer will be cancelled when game actually starts successfully"""
        try:
            # The timer will be cancelled when the game status indicates successful start
            # The actual START_GAME processing is done by games_thread
            logger.info("START_GAME message received - timer will be managed based on game start outcome")

        except Exception as e:
            logger.error(f"Failed to handle START_GAME message: {e}")

    def _handle_game_status_response(self, message: Message):
        """Handle GAME_STATUS responses, managing timer based on game start outcome"""
        try:
            status = message.data.get("status", "unknown")
            sender = message.sender

            # Only process responses that might be related to our timer-initiated START_GAME
            # We check if we have an active timer that might need restarting
            if self._game_start_timer is None and self._original_timer_interval is None:
                # No active timer management needed
                return

            # Check if this is a failure response that should trigger timer restart
            failure_statuses = ["waiting_for_downloads", "discarded", "error", "no_matches", "no_fixtures_available"]

            if status in failure_statuses:
                logger.info(f"START_GAME failed with status '{status}' from {sender} - restarting timer")

                # Cancel any existing timer
                self._cancel_game_timer()

                # Restart timer with original interval
                if self._original_timer_interval is not None:
                    logger.info(f"Restarting game start timer with original interval: {self._original_timer_interval} minutes")
                    self._start_game_timer_with_interval(self._original_timer_interval)
                else:
                    logger.warning("No original timer interval available for restart")
            elif status == "started":
                logger.info(f"START_GAME succeeded with status '{status}' from {sender} - cancelling timer")
                # Game started successfully, cancel the timer and clear timer state
                self._cancel_game_timer()
                self._original_timer_interval = None

        except Exception as e:
            logger.error(f"Failed to handle GAME_STATUS response: {e}")
    
    def _run_additional_tasks(self):
        """Placeholder for additional periodic tasks"""
        # TODO: Implement additional tasks as requested by user
        # This is where future extensions can be added
        pass

    def _start_game_timer(self):
        """Start the timer for automated game start"""
        if self._start_timer_minutes is None:
            return

        # Store the original interval for potential retries
        self._original_timer_interval = self._start_timer_minutes

        # Special case: --start-timer 0 means 10 seconds delay for system initialization
        if self._start_timer_minutes == 0:
            delay_seconds = 10
            logger.info(f"Starting command line game timer: --start-timer 0 = 10 seconds delay for system initialization")
        else:
            delay_seconds = self._start_timer_minutes * 60
            logger.info(f"Starting command line game timer: {self._start_timer_minutes} minutes ({delay_seconds} seconds)")

        self._game_start_timer = threading.Timer(delay_seconds, self._on_game_timer_expired)
        self._game_start_timer.daemon = True
        self._game_start_timer.start()

    def _start_game_timer_with_interval(self, minutes: int):
        """Start the game timer with a specific interval (used for retries)"""
        if minutes < 0:
            logger.error(f"Invalid timer interval: {minutes} minutes")
            return

        # Update stored interval
        self._original_timer_interval = minutes

        # Special case: timer 0 means 10 seconds delay for system initialization
        if minutes == 0:
            delay_seconds = 10
            logger.info(f"Restarting command line game timer: 0 minutes = 10 seconds delay for system initialization")
        else:
            delay_seconds = minutes * 60
            logger.info(f"Restarting command line game timer: {minutes} minutes ({delay_seconds} seconds)")

        self._game_start_timer = threading.Timer(delay_seconds, self._on_game_timer_expired)
        self._game_start_timer.daemon = True
        self._game_start_timer.start()

    def _on_game_timer_expired(self):
        """Called when the game start timer expires"""
        logger.info("Game start timer expired, sending START_GAME message")

        try:
            # Create and send START_GAME message
            start_game_message = MessageBuilder.start_game(
                sender="timer",
                fixture_id=None  # Let the games thread find the best fixture
            )
            self.message_bus.publish(start_game_message, broadcast=True)

            logger.info("START_GAME message sent successfully")
        except Exception as e:
            logger.error(f"Failed to send START_GAME message: {e}")

    def _cancel_game_timer(self):
        """Cancel the game start timer if it's running"""
        if self._game_start_timer and self._game_start_timer.is_alive():
            logger.info("Cancelling game start timer")
            self._game_start_timer.cancel()
            self._game_start_timer = None
            # Note: We keep _original_timer_interval for potential retries
    
    def _check_component_health(self):
        """Check health of all components"""
        try:
            if self.thread_manager:
                unhealthy_components = self.thread_manager.get_unhealthy_components()
                
                if unhealthy_components:
                    logger.warning(f"Unhealthy components detected: {unhealthy_components}")
                    
                    # TODO: Implement component restart logic
                    
        except Exception as e:
            logger.error(f"Component health check failed: {e}")
    
    def _log_statistics(self):
        """Log application statistics"""
        try:
            if self.message_bus and self.thread_manager:
                msg_stats = self.message_bus.get_statistics()
                thread_stats = self.thread_manager.get_statistics()
                
                logger.info(f"Message bus stats: {msg_stats['total_components']} components, "
                           f"{msg_stats['total_messages_in_history']} messages")
                logger.info(f"Thread manager stats: {thread_stats['total_threads']} threads, "
                           f"{thread_stats['running_threads']} running")
                
        except Exception as e:
            logger.error(f"Failed to log statistics: {e}")
    
    def shutdown(self):
        """Shutdown the application"""
        logger.info("Application shutdown requested")

        self.running = False
        self.shutdown_event.set()

        # Cancel game timer if running and clear timer state
        self._cancel_game_timer()
        self._original_timer_interval = None

        # Send shutdown message to all components
        if self.message_bus:
            shutdown_message = Message(
                type=MessageType.SYSTEM_SHUTDOWN,
                sender="core",
                data={"reason": "Application shutdown"}
            )
            self.message_bus.publish(shutdown_message, broadcast=True)

        # If Qt player is running, quit the QApplication
        if self.qt_player and hasattr(self.qt_player, 'app') and self.qt_player.app:
            try:
                logger.info("Requesting Qt application to quit")
                self.qt_player.app.quit()
            except Exception as e:
                logger.error(f"Failed to quit Qt application: {e}")
    
    def _qt_about_to_quit(self):
        """Handle Qt's aboutToQuit signal"""
        logger.info("Qt application is about to quit")
        self.running = False
        self.shutdown_event.set()
        
        # Force shutdown of all background threads when Qt quits
        try:
            logger.info("Shutting down all background components...")
            
            # Stop thread manager and all components with short timeout
            if self.thread_manager:
                self.thread_manager.stop_all(timeout=2.0)
            
            # Shutdown message bus
            if self.message_bus:
                self.message_bus.shutdown()
            
            # Close database
            if self.db_manager:
                self.db_manager.close()
                
            logger.info("Background components shutdown completed")
            
        except Exception as e:
            logger.error(f"Error shutting down background components: {e}")
        
        # Schedule a force exit in case daemon threads don't terminate quickly
        import threading
        def force_exit_after_delay():
            import time
            time.sleep(3)  # Give 3 seconds for graceful shutdown
            logger.warning("Force exit triggered - background threads not terminated")
            import os
            os._exit(0)
        
        force_exit_thread = threading.Thread(target=force_exit_after_delay, daemon=True)
        force_exit_thread.start()
    
    def _cleanup(self) -> int:
        """Cleanup application resources"""
        logger.info("Cleaning up application resources...")
        
        try:
            # Shutdown Qt player if it exists
            if self.qt_player:
                try:
                    self.qt_player.shutdown()
                    logger.info("Qt player shutdown completed")
                except Exception as e:
                    logger.error(f"Qt player shutdown failed: {e}")
            
            # Stop thread manager with shorter timeout
            if self.thread_manager:
                self.thread_manager.stop_all()
                self.thread_manager.wait_for_shutdown(timeout=3.0)
            
            # Wait for main loop thread with shorter timeout
            if self._main_loop_thread and self._main_loop_thread.is_alive():
                self._main_loop_thread.join(timeout=2.0)
                if self._main_loop_thread.is_alive():
                    logger.warning("Main loop thread did not shut down gracefully")
            
            # Shutdown message bus
            if self.message_bus:
                self.message_bus.shutdown()
            
            # Close database
            if self.db_manager:
                self.db_manager.close()
            
            logger.info("Application cleanup completed")
            return 0
            
        except Exception as e:
            logger.error(f"Cleanup failed: {e}")
            return 1
    
    def get_status(self) -> Dict[str, Any]:
        """Get current application status"""
        try:
            status = {
                "running": self.running,
                "version": self.settings.version,
                "components": {},
                "message_bus": {},
                "threads": {}
            }
            
            if self.thread_manager:
                status["threads"] = self.thread_manager.get_statistics()
                status["components"] = {
                    name: "running" if self.thread_manager.is_component_running(name) else "stopped"
                    for name in self.thread_manager.get_component_names()
                }
            
            if self.message_bus:
                status["message_bus"] = self.message_bus.get_statistics()
            
            return status
            
        except Exception as e:
            logger.error(f"Failed to get status: {e}")
            return {"error": str(e)}