"""
Flask web dashboard application for MbetterClient
"""

import time
import logging
from pathlib import Path
from typing import Optional, Dict, Any, List
from flask import Flask, request, jsonify, render_template, redirect, url_for, session, g
from flask_login import LoginManager, login_required, current_user
from flask_jwt_extended import JWTManager, create_access_token, jwt_required as flask_jwt_required
from flask_socketio import SocketIO, emit
from flask_cors import CORS
from werkzeug.serving import make_server
import threading

from ..core.thread_manager import ThreadedComponent
from ..core.message_bus import MessageBus, Message, MessageType, MessageBuilder
from ..config.settings import WebConfig
from ..config.manager import ConfigManager
from ..database.manager import DatabaseManager
from ..utils.ssl_utils import get_ssl_certificate_paths, create_ssl_context
from flask_cors import CORS
from .auth import AuthManager
from .api import DashboardAPI
from .routes import main_bp, auth_bp, api_bp
from .screen_cast_routes import screen_cast_bp

logger = logging.getLogger(__name__)


class WebDashboard(ThreadedComponent):
    """Flask web dashboard component"""
    
    def __init__(self, message_bus: MessageBus, db_manager: DatabaseManager,
                 config_manager: ConfigManager, settings: WebConfig):
        super().__init__("web_dashboard", message_bus)
        self.db_manager = db_manager
        self.config_manager = config_manager
        self.settings = settings
        
        # Flask app and server
        self.app: Optional[Flask] = None
        self.socketio: Optional[SocketIO] = None
        self.server: Optional = None
        self.ssl_context: Optional = None  # SSL context for HTTPS
        self.auth_manager: Optional[AuthManager] = None
        self.api: Optional[DashboardAPI] = None
        self.main_application = None  # Will be set by the main application

        # Timer state storage
        self.current_timer_state: Dict[str, Any] = {
            "running": False,
            "remaining_seconds": 0,
            "total_seconds": 0,
            "fixture_id": None,
            "match_id": None,
            "start_time": None
        }

        # Client notification queue for long-polling clients
        self.notification_queue: List[Dict[str, Any]] = []
        self.notification_lock = threading.Lock()
        self.waiting_clients: List[threading.Event] = []  # Events for waiting long-poll clients
        self.waiting_clients_lock = threading.Lock()
        
        # Register message queue
        self.message_queue = self.message_bus.register_component(self.name)
        
        logger.info("WebDashboard initialized")
    
    def set_main_application(self, app):
        """Set reference to main application for component access"""
        self.main_application = app
    
    def initialize(self) -> bool:
        """Initialize Flask application"""
        try:
            # Create Flask app
            self.app = self._create_flask_app()
            
            # Initialize auth manager
            self.auth_manager = AuthManager(self.db_manager, self.app)
            
            # Initialize API
            self.api = DashboardAPI(self.db_manager, self.config_manager, self.message_bus)
            
            # Setup routes
            self._setup_routes()
            
            # Create HTTP server
            self._create_server()
            
            # Subscribe to messages
            self.message_bus.subscribe(self.name, MessageType.CONFIG_UPDATE, self._handle_config_update)
            self.message_bus.subscribe(self.name, MessageType.SYSTEM_STATUS, self._handle_system_status)
            self.message_bus.subscribe(self.name, MessageType.CUSTOM, self._handle_custom_message)
            # Subscribe to messages for client notifications
            self.message_bus.subscribe(self.name, MessageType.START_GAME, self._handle_client_notification)
            self.message_bus.subscribe(self.name, MessageType.MATCH_START, self._handle_client_notification)
            self.message_bus.subscribe(self.name, MessageType.GAME_STATUS, self._handle_client_notification)
            
            logger.info("WebDashboard initialized successfully")
            return True
            
        except Exception as e:
            logger.error(f"WebDashboard initialization failed: {e}")
            return False
    
    def _create_flask_app(self) -> Flask:
        """Create and configure Flask application"""
        # Template and static directories
        template_dir = Path(__file__).parent / 'templates'
        static_dir = Path(__file__).parent / 'static'
        
        # Create Flask app
        app = Flask(__name__,
                    template_folder=str(template_dir),
                    static_folder=str(static_dir))

        # Initialize CORS
        CORS(app, resources={
            r"/api/*": {
                "origins": ["*"],
                "methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
                "allow_headers": ["Content-Type", "Authorization", "X-Requested-With"],
                "expose_headers": ["Content-Range", "X-Content-Range"],
                "supports_credentials": False
            }
        })

        # Initialize SocketIO (disabled for PyInstaller compatibility)
        try:
            socketio = SocketIO(app, cors_allowed_origins="*", async_mode='threading')
        except Exception as e:
            logger.warning(f"SocketIO initialization failed: {e}, disabling WebSocket support")
            socketio = None

        # Configuration
        app.config.update({
            'SECRET_KEY': self.settings.secret_key,
            'JWT_SECRET_KEY': self.settings.jwt_secret_key,
            'JWT_ACCESS_TOKEN_EXPIRES': self.settings.jwt_expiration_hours * 3600,
            'SESSION_COOKIE_HTTPONLY': True,
            'SESSION_COOKIE_SECURE': self.settings.enable_ssl,  # True when using HTTPS
            'PERMANENT_SESSION_LIFETIME': self.settings.session_timeout_hours * 3600,
            'WTF_CSRF_ENABLED': True,
            'WTF_CSRF_TIME_LIMIT': None,
        })
        
        # Initialize extensions
        login_manager = LoginManager()
        login_manager.init_app(app)
        login_manager.login_view = 'auth.login'
        login_manager.login_message = 'Please log in to access this page.'

        jwt_manager = JWTManager(app)

        # Initialize CORS
        CORS(app, resources={
            r"/api/*": {
                "origins": ["file://", "http://127.0.0.1:*", "http://localhost:*"],
                "methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
                "allow_headers": ["Content-Type", "Authorization"],
                "supports_credentials": False
            }
        })
        
        # User loader for Flask-Login
        @login_manager.user_loader
        def load_user(user_id):
            from .auth import AuthenticatedUser
            user_model = self.db_manager.get_user_by_id(int(user_id))
            if user_model:
                return AuthenticatedUser(
                    user_id=user_model.id,
                    username=user_model.username,
                    email=user_model.email,
                    is_admin=user_model.is_admin,
                    role=getattr(user_model, 'role', 'normal')
                )
            return None
        
        # JWT error handlers
        @jwt_manager.expired_token_loader
        def expired_token_callback(jwt_header, jwt_payload):
            return jsonify({'error': 'Token has expired'}), 401
        
        @jwt_manager.invalid_token_loader
        def invalid_token_callback(error):
            return jsonify({'error': 'Invalid token'}), 401
        
        @jwt_manager.unauthorized_loader
        def unauthorized_callback(error):
            return jsonify({'error': 'Authorization required'}), 401
        
        # Request context setup
        @app.before_request
        def before_request():
            g.db_manager = self.db_manager
            g.config_manager = self.config_manager
            g.message_bus = self.message_bus
            g.auth_manager = self.auth_manager
            g.api = self.api
            g.main_app = self.main_application  # Provide access to main app
        
        # Template context processors
        @app.context_processor
        def inject_globals():
            return {
                'app_name': 'MbetterClient',
                'app_version': '1.0.13',
                'current_time': time.time(),
            }
        
        # Error handlers
        @app.errorhandler(404)
        def not_found_error(error):
            return render_template('errors/404.html'), 404
        
        @app.errorhandler(500)
        def internal_error(error):
            return render_template('errors/500.html'), 500
        
        @app.errorhandler(403)
        def forbidden_error(error):
            return render_template('errors/403.html'), 403
        
        # Store socketio instance in class
        self.socketio = socketio

        # Setup SocketIO event handlers if SocketIO is available
        if self.socketio:
            self._setup_socketio_handlers()
        else:
            logger.warning("SocketIO not available, WebSocket features will be disabled")

        return app

    def _setup_socketio_handlers(self):
        """Setup SocketIO event handlers"""
        @self.socketio.on('connect')
        def handle_connect():
            logger.info(f"Client connected: {request.sid}")
            emit('connected', {'status': 'connected'})

        @self.socketio.on('disconnect')
        def handle_disconnect():
            logger.info(f"Client disconnected: {request.sid}")

        @self.socketio.on('join_fixtures')
        def handle_join_fixtures(data):
            from flask_socketio import join_room
            join_room('fixtures')
            logger.info(f"Client {request.sid} joined fixtures room")
            emit('joined_fixtures', {'status': 'joined'})

        @self.socketio.on('leave_fixtures')
        def handle_leave_fixtures(data):
            from flask_socketio import leave_room
            leave_room('fixtures')
            logger.info(f"Client {request.sid} left fixtures room")

        @self.socketio.on('get_fixtures')
        def handle_get_fixtures(data):
            try:
                if self.db_manager:
                    session = self.db_manager.get_session()
                    try:
                        from ..database.models import MatchModel
                        matches = session.query(MatchModel).filter_by(active_status=True).order_by(MatchModel.match_number).all()

                        fixtures_data = []
                        for match in matches[:5]:  # Only first 5 matches
                            match_dict = match.to_dict()
                            fixtures_data.append(match_dict)

                        emit('fixtures_update', {
                            'fixtures': fixtures_data,
                            'timestamp': time.time()
                        })

                        logger.info(f"Sent fixtures data to client {request.sid}: {len(fixtures_data)} matches")

                    finally:
                        session.close()
                else:
                    emit('error', {'message': 'Database not available'})

            except Exception as e:
                logger.error(f"Error getting fixtures for WebSocket: {e}")
                emit('error', {'message': str(e)})

        @self.socketio.on('get_matches')
        def handle_get_matches(data):
            try:
                if self.db_manager:
                    session = self.db_manager.get_session()
                    try:
                        from ..database.models import MatchModel
                        matches = session.query(MatchModel).filter_by(active_status=True).order_by(MatchModel.match_number).all()

                        matches_data = []
                        for match in matches[:5]:  # Only first 5 matches
                            match_dict = match.to_dict()
                            matches_data.append(match_dict)

                        emit('matches_update', {
                            'matches': matches_data,
                            'timestamp': time.time()
                        })

                        logger.info(f"Sent matches data to client {request.sid}: {len(matches_data)} matches")

                    finally:
                        session.close()
                else:
                    emit('error', {'message': 'Database not available'})

            except Exception as e:
                logger.error(f"Error getting matches for WebSocket: {e}")
                emit('error', {'message': str(e)})

    def _setup_routes(self):
        """Setup Flask routes"""
        # Pass dependencies to route modules
        main_bp.db_manager = self.db_manager
        main_bp.config_manager = self.config_manager
        main_bp.message_bus = self.message_bus

        auth_bp.auth_manager = self.auth_manager
        auth_bp.db_manager = self.db_manager

        api_bp.api = self.api
        api_bp.auth_manager = self.auth_manager
        api_bp.db_manager = self.db_manager
        api_bp.config_manager = self.config_manager
        api_bp.message_bus = self.message_bus
        api_bp.socketio = self.socketio
        
        # Pass dependencies to screen cast blueprint
        screen_cast_bp.message_bus = self.message_bus
        screen_cast_bp.db_manager = self.db_manager
        
        # Register blueprints
        self.app.register_blueprint(main_bp)
        self.app.register_blueprint(auth_bp, url_prefix='/auth')
        self.app.register_blueprint(api_bp, url_prefix='/api')
        self.app.register_blueprint(screen_cast_bp, url_prefix='/screen_cast')
    
    def _create_server(self):
        """Create HTTP/HTTPS server with SocketIO support"""
        try:
            from werkzeug.serving import make_server

            protocol = "HTTP"

            if self.settings.enable_ssl:
                protocol = "HTTPS"
                logger.info("SSL enabled - server will use HTTPS")
                # Get SSL certificate paths
                from ..config.settings import get_user_data_dir
                cert_path, key_path = get_ssl_certificate_paths(get_user_data_dir())
                if cert_path and key_path:
                    # Create SSL context for HTTPS
                    self.ssl_context = create_ssl_context(cert_path, key_path)
                    if not self.ssl_context:
                        logger.warning("SSL context creation failed, falling back to HTTP")
                        self.ssl_context = None
                        protocol = "HTTP"
                else:
                    logger.warning("SSL certificate files not available, falling back to HTTP")
                    self.ssl_context = None
                    protocol = "HTTP"

            # Create WSGI server that can be shutdown
            if self.socketio:
                # For SocketIO, try to use the SocketIO WSGI app
                try:
                    wsgi_app = self.socketio.WSGIApp(self.app)
                except AttributeError:
                    # Fallback for older SocketIO versions or different implementations
                    logger.warning("SocketIO WSGIApp not available, falling back to standard Flask app")
                    wsgi_app = self.app
                    self.socketio = None  # Disable SocketIO since we can't use it
            else:
                wsgi_app = self.app

            self.server = make_server(
                host=self.settings.host,
                port=self.settings.port,
                app=wsgi_app,
                threaded=True,
                ssl_context=self.ssl_context
            )

            logger.info(f"{protocol} server created on {self.settings.host}:{self.settings.port}")

            if self.settings.enable_ssl and self.ssl_context:
                logger.info("⚠️  Using self-signed certificate - browsers will show security warning")
                logger.info("   You can safely proceed by accepting the certificate")

        except Exception as e:
            logger.error(f"Failed to create {protocol} server: {e}")
            raise
    
    def run(self):
        """Main run loop"""
        try:
            logger.info("WebDashboard thread started")
            
            # Send ready status
            protocol = "https" if self.settings.enable_ssl else "http"
            ready_message = MessageBuilder.system_status(
                sender=self.name,
                status="ready",
                details={
                    "host": self.settings.host,
                    "port": self.settings.port,
                    "ssl_enabled": self.settings.enable_ssl,
                    "url": f"{protocol}://{self.settings.host}:{self.settings.port}"
                }
            )
            self.message_bus.publish(ready_message)
            
            # Start HTTP server in separate thread
            server_thread = threading.Thread(
                target=self._run_server,
                name="WebServer",
                daemon=True
            )
            server_thread.start()
            
            # Message processing loop
            while self.running and not self.shutdown_event.is_set():
                try:
                    # Process messages
                    message = self.message_bus.get_message(self.name, timeout=1.0)
                    if message:
                        self._process_message(message)

                    # Update heartbeat
                    self.heartbeat()

                    time.sleep(0.1)

                except Exception as e:
                    logger.error(f"WebDashboard run loop error: {e}")
                    time.sleep(1.0)
                    
            # Wait for server thread to finish (with timeout since it's daemon)
            if server_thread and server_thread.is_alive():
                server_thread.join(timeout=2.0)
                
        except Exception as e:
            logger.error(f"WebDashboard run failed: {e}")
        finally:
            logger.info("WebDashboard thread ended")
    
    def _run_server(self):
        """Run HTTP/HTTPS server with optional SocketIO"""
        try:
            protocol = "HTTPS" if self.settings.enable_ssl else "HTTP"
            socketio_status = "with SocketIO" if self.socketio else "without SocketIO"
            logger.info(f"Starting {protocol} server {socketio_status} on {self.settings.host}:{self.settings.port}")

            if self.server:
                # Use the shutdown-capable server
                # serve_forever() will block until shutdown() is called
                self.server.serve_forever()
                logger.info("HTTP server stopped")
            else:
                logger.error("Server not created, cannot start")
                return

        except Exception as e:
            if self.running:  # Only log if not shutting down
                protocol = "HTTPS" if self.settings.enable_ssl else "HTTP"
                logger.error(f"{protocol} server error: {e}")
            else:
                # Expected during shutdown
                logger.debug(f"Server stopped during shutdown: {e}")
    
    def _setup_ssl_error_suppression(self):
        """Setup logging filter to suppress expected SSL connection errors"""
        import logging
        
        class SSLErrorFilter(logging.Filter):
            """Filter to suppress expected SSL connection errors from Werkzeug"""
            
            def filter(self, record):
                # Check if this is a Werkzeug error log
                if record.name == 'werkzeug' and record.levelno >= logging.ERROR:
                    message = record.getMessage()
                    
                    # Suppress specific SSL connection errors that are expected for long-polling
                    suppress_patterns = [
                        'Error on request:',
                        'BrokenPipeError: [Errno 32] Broken pipe',
                        'ssl.SSLError: [SSL: UNEXPECTED_EOF_WHILE_READING]',
                        'unexpected eof while reading',
                        'During handling of the above exception, another exception occurred:'
                    ]
                    
                    # If message contains any suppression pattern, filter it out
                    if any(pattern in message for pattern in suppress_patterns):
                        # Log as debug instead
                        debug_msg = f"SSL connection error (expected for long-polling): {message[:100]}..."
                        logging.getLogger(__name__).debug(debug_msg)
                        return False  # Suppress the original error log
                
                return True  # Allow all other log messages
        
        # Apply filter to werkzeug logger
        werkzeug_logger = logging.getLogger('werkzeug')
        ssl_filter = SSLErrorFilter()
        werkzeug_logger.addFilter(ssl_filter)
        
        logger.debug("Applied SSL error logging suppression filter to Werkzeug")
    
    def shutdown(self):
        """Shutdown web dashboard"""
        try:
            logger.info("Shutting down WebDashboard...")

            # Shutdown the HTTP server
            if self.server:
                logger.info("Shutting down HTTP server...")
                self.server.shutdown()
                self.server.server_close()
                logger.info("HTTP server shutdown completed")

            # Note: SocketIO connections will be closed when the server shuts down
            # No explicit SocketIO shutdown needed as it's handled by the WSGI server

        except Exception as e:
            logger.error(f"WebDashboard shutdown error: {e}")
    
    def _process_message(self, message: Message):
        """Process received message"""
        try:
            # Handle messages directly since some messages don't trigger subscription handlers
            if message.type == MessageType.CONFIG_UPDATE:
                self._handle_config_update(message)
            elif message.type == MessageType.SYSTEM_STATUS:
                self._handle_system_status(message)
            elif message.type == MessageType.CUSTOM:
                self._handle_custom_message(message)
                
        except Exception as e:
            logger.error(f"Failed to process message: {e}")
    
    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 received for section: {config_section}")
            
            # Update configuration through config manager
            if config_section and config_data:
                self.config_manager.update_from_web(config_data)
            
        except Exception as e:
            logger.error(f"Failed to handle config update: {e}")
    
    def _handle_system_status(self, message: Message):
        """Handle system status message"""
        try:
            status = message.data.get("status")
            sender = message.sender

            logger.debug(f"System status from {sender}: {status}")

            # Store status for web interface
            # This could be cached or stored in database for display

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

    def _handle_custom_message(self, message: Message):
        """Handle custom messages (like timer state responses)"""
        try:
            response = message.data.get("response")
            timer_update = message.data.get("timer_update")
            fixture_status_update = message.data.get("fixture_status_update")
            download_progress = message.data.get("download_progress")

            if response == "timer_state":
                # Update stored timer state
                timer_state = message.data.get("timer_state", {})
                self.current_timer_state.update(timer_state)
                logger.debug(f"Timer state updated: {timer_state}")

            elif response == "timer_stopped":
                # Reset timer state
                self.current_timer_state = {
                    "running": False,
                    "remaining_seconds": 0,
                    "total_seconds": 0,
                    "fixture_id": None,
                    "match_id": None,
                    "start_time": None
                }
                logger.debug("Timer stopped")

            elif timer_update:
                # Handle periodic timer updates from match_timer component
                self.current_timer_state.update(timer_update)
                logger.debug(f"Timer update received: {timer_update}")

                # Add timer update to notification queue for long-polling clients
                self._add_client_notification("TIMER_UPDATE", timer_update, message.timestamp)

            elif fixture_status_update:
                # Handle fixture status updates from games_thread
                logger.debug(f"Fixture status update received: {fixture_status_update}")

                # Add fixture status update to notification queue for long-polling clients
                self._add_client_notification("FIXTURE_STATUS_UPDATE", fixture_status_update, message.timestamp)

            elif download_progress:
                # Handle download progress updates from API client
                if self.socketio:
                    # Broadcast download progress to all connected clients
                    self.socketio.emit('download_progress', download_progress)
                    logger.debug(f"Broadcasted download progress: {download_progress}")

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


    def _handle_client_notification(self, message: Message):
        """Handle messages that should be sent to long-polling clients"""
        try:
            # Convert message to notification format
            notification_data = {
                "type": message.type.value,
                "data": message.data,
                "timestamp": message.timestamp,
                "sender": message.sender
            }

            # Add to notification queue
            self._add_client_notification(message.type.value, message.data, message.timestamp, message.sender)

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

    def _add_client_notification(self, notification_type: str, data: Dict[str, Any],
                                timestamp: float, sender: str = None):
        """Add notification to the client queue"""
        try:
            with self.notification_lock:
                notification = {
                    "type": notification_type,
                    "data": data,
                    "timestamp": timestamp
                }
                if sender:
                    notification["sender"] = sender

                self.notification_queue.append(notification)

                # Keep queue size reasonable (limit to last 100 notifications)
                if len(self.notification_queue) > 100:
                    self.notification_queue = self.notification_queue[-50:]

                logger.debug(f"Added client notification: {notification_type}")

            # Wake up all waiting clients
            with self.waiting_clients_lock:
                for event in self.waiting_clients:
                    event.set()
                self.waiting_clients.clear()

        except Exception as e:
            logger.error(f"Failed to add client notification: {e}")

    def get_pending_notifications(self) -> List[Dict[str, Any]]:
        """Get the first pending notification for a client (one at a time)"""
        try:
            with self.notification_lock:
                if self.notification_queue:
                    # Return only the first notification and remove it from queue
                    notification = self.notification_queue.pop(0)
                    return [notification]
                return []
        except Exception as e:
            logger.error(f"Failed to get pending notifications: {e}")
            return []

    def register_waiting_client(self, event: threading.Event):
        """Register a waiting client Event to be notified when notifications arrive"""
        try:
            with self.waiting_clients_lock:
                self.waiting_clients.append(event)
        except Exception as e:
            logger.error(f"Failed to register waiting client: {e}")

    def unregister_waiting_client(self, event: threading.Event):
        """Unregister a waiting client Event"""
        try:
            with self.waiting_clients_lock:
                if event in self.waiting_clients:
                    self.waiting_clients.remove(event)
        except Exception as e:
            logger.error(f"Failed to unregister waiting client: {e}")
    
    def get_app_context(self):
        """Get Flask application context"""
        if self.app:
            return self.app.app_context()
        return None
    
    def send_video_command(self, command: str, **kwargs) -> bool:
        """Send video command through message bus"""
        try:
            if command == "play":
                message = MessageBuilder.video_play(
                    sender=self.name,
                    file_path=kwargs.get("file_path", ""),
                    template=kwargs.get("template", "news_template"),
                    overlay_data=kwargs.get("overlay_data", {})
                )
            elif command == "pause":
                message = Message(
                    type=MessageType.VIDEO_PAUSE,
                    sender=self.name,
                    data={}
                )
            elif command == "stop":
                message = Message(
                    type=MessageType.VIDEO_STOP,
                    sender=self.name,
                    data={}
                )
            elif command == "template_change":
                message = MessageBuilder.template_change(
                    sender=self.name,
                    template_name=kwargs.get("template_name", "news_template"),
                    template_data=kwargs.get("template_data", {})
                )
            else:
                logger.error(f"Unknown video command: {command}")
                return False
            
            # Send to qt_player
            message.recipient = "qt_player"
            self.message_bus.publish(message)
            
            logger.info(f"Video command sent: {command}")
            return True
            
        except Exception as e:
            logger.error(f"Failed to send video command: {e}")
            return False
    
    def get_system_status(self) -> Dict[str, Any]:
        """Get current system status"""
        try:
            # Request status from core
            status_request = Message(
                type=MessageType.CONFIG_REQUEST,
                sender=self.name,
                recipient="core",
                data={"section": "status"}
            )
            self.message_bus.publish(status_request)

            # For now, return basic status
            # In a full implementation, this would wait for response or cache status
            protocol = "https" if self.settings.enable_ssl else "http"
            return {
                "web_dashboard": "running",
                "host": self.settings.host,
                "port": self.settings.port,
                "ssl_enabled": self.settings.enable_ssl,
                "url": f"{protocol}://{self.settings.host}:{self.settings.port}",
                "timestamp": time.time()
            }

        except Exception as e:
            logger.error(f"Failed to get system status: {e}")
            return {"error": str(e)}

    def get_timer_state(self) -> Dict[str, Any]:
        """Get current timer state"""
        try:
            # Request fresh timer state from match_timer component
            if self.message_bus:
                request_message = Message(
                    type=MessageType.CUSTOM,
                    sender=self.name,
                    recipient="match_timer",
                    data={
                        "request": "get_timer_state",
                        "timestamp": time.time()
                    },
                    correlation_id=f"timer_state_{int(time.time() * 1000)}"
                )
                self.message_bus.publish(request_message)

            # Return current cached state
            return self.current_timer_state.copy()

        except Exception as e:
            logger.error(f"Failed to get timer state: {e}")
            return {
                "running": False,
                "remaining_seconds": 0,
                "total_seconds": 0,
                "fixture_id": None,
                "match_id": None,
                "start_time": None,
                "error": str(e)
            }

    def broadcast_fixtures_update(self):
        """Broadcast fixtures update to all connected WebSocket clients"""
        try:
            if not self.socketio:
                logger.debug("SocketIO not available, skipping broadcast")
                return

            # Get fixtures data
            session = self.db_manager.get_session()
            try:
                from ..database.models import MatchModel
                matches = session.query(MatchModel).filter_by(active_status=True).order_by(MatchModel.match_number).all()

                fixtures_data = []
                for match in matches[:5]:  # Only first 5 matches
                    match_dict = match.to_dict()
                    fixtures_data.append(match_dict)

                # Broadcast to fixtures room
                self.socketio.emit('fixtures_update', {
                    'fixtures': fixtures_data,
                    'timestamp': time.time()
                }, room='fixtures')

                logger.debug(f"Broadcasted fixtures update to {len(fixtures_data)} matches")

            finally:
                session.close()

        except Exception as e:
            logger.error(f"Failed to broadcast fixtures update: {e}")


def create_app(db_manager: DatabaseManager, config_manager: ConfigManager, 
               settings: WebConfig) -> Flask:
    """Factory function to create Flask app (for testing)"""
    dashboard = WebDashboard(None, db_manager, config_manager, settings)
    dashboard.initialize()
    return dashboard.app