"""
UDP broadcast component for LAN discovery
Broadcasts MBetterClient server information every 30 seconds
"""

import socket
import json
import time
import logging
import threading
from typing import Optional, Dict, Any

from .thread_manager import ThreadedComponent
from .message_bus import MessageBus, Message, MessageType

logger = logging.getLogger(__name__)


class UDPBroadcastComponent(ThreadedComponent):
    """Component for broadcasting server information via UDP"""
    
    def __init__(self, message_bus: MessageBus, broadcast_port: int = 45123):
        super().__init__("udp_broadcast", message_bus)
        self.broadcast_port = broadcast_port
        self.broadcast_interval = 30.0  # 30 seconds
        self.socket: Optional[socket.socket] = None
        
        # Server information to broadcast
        self.server_info: Dict[str, Any] = {
            "service": "MBetterClient",
            "host": "127.0.0.1",
            "port": 5001,
            "ssl": False,
            "url": "http://127.0.0.1:5001",
            "timestamp": time.time()
        }
        
        # Register message queue
        self.message_queue = self.message_bus.register_component(self.name)
        
        logger.info(f"UDP Broadcast component initialized on port {broadcast_port}")
    
    def initialize(self) -> bool:
        """Initialize UDP socket for broadcasting"""
        try:
            # Create UDP socket
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            
            # Subscribe to system status messages to get web server info
            self.message_bus.subscribe(self.name, MessageType.SYSTEM_STATUS, self._handle_system_status)
            
            logger.info("UDP broadcast socket initialized successfully")
            return True
            
        except Exception as e:
            logger.error(f"UDP broadcast initialization failed: {e}")
            return False
    
    def run(self):
        """Main broadcast loop"""
        try:
            logger.info("UDP broadcast thread started")
            
            # Request initial web server status
            self._request_web_server_status()
            
            last_broadcast_time = 0
            
            while self.running:
                try:
                    current_time = time.time()
                    
                    # Process messages
                    message = self.message_bus.get_message(self.name, timeout=1.0)
                    if message:
                        self._process_message(message)
                    
                    # Broadcast every 30 seconds
                    if current_time - last_broadcast_time >= self.broadcast_interval:
                        self._broadcast_server_info()
                        last_broadcast_time = current_time
                    
                    # Update heartbeat
                    self.heartbeat()
                    
                    time.sleep(0.5)
                    
                except Exception as e:
                    logger.error(f"UDP broadcast loop error: {e}")
                    time.sleep(2.0)
                    
        except Exception as e:
            logger.error(f"UDP broadcast run failed: {e}")
        finally:
            logger.info("UDP broadcast thread ended")
    
    def shutdown(self):
        """Shutdown UDP broadcast component"""
        try:
            logger.info("Shutting down UDP broadcast...")
            
            if self.socket:
                self.socket.close()
                self.socket = None
            
        except Exception as e:
            logger.error(f"UDP broadcast shutdown error: {e}")
    
    def _process_message(self, message: Message):
        """Process received message"""
        try:
            if message.type == MessageType.SYSTEM_STATUS:
                self._handle_system_status(message)
                
        except Exception as e:
            logger.error(f"Failed to process message: {e}")
    
    def _handle_system_status(self, message: Message):
        """Handle system status messages from web dashboard"""
        try:
            if message.sender == "web_dashboard":
                details = message.data.get("details", {})
                
                if "host" in details and "port" in details:
                    self.server_info.update({
                        "host": details.get("host", "127.0.0.1"),
                        "port": details.get("port", 5001),
                        "ssl": details.get("ssl_enabled", False),
                        "url": details.get("url", "http://127.0.0.1:5001"),
                        "timestamp": time.time()
                    })
                    
                    logger.debug(f"Updated server info from web dashboard: {self.server_info}")
                
        except Exception as e:
            logger.error(f"Failed to handle system status: {e}")
    
    def _request_web_server_status(self):
        """Request current web server status"""
        try:
            # Send a status request to get current web server info
            status_request = Message(
                type=MessageType.CONFIG_REQUEST,
                sender=self.name,
                recipient="web_dashboard",
                data={"section": "status"}
            )
            self.message_bus.publish(status_request)
            
        except Exception as e:
            logger.error(f"Failed to request web server status: {e}")
    
    def _broadcast_server_info(self):
        """Broadcast server information via UDP"""
        try:
            if not self.socket:
                logger.warning("UDP socket not available for broadcasting")
                return
            
            # Update timestamp
            self.server_info["timestamp"] = time.time()
            
            # Create broadcast message
            broadcast_data = json.dumps(self.server_info, separators=(',', ':')).encode('utf-8')
            
            # Broadcast to all interfaces
            broadcast_addresses = self._get_broadcast_addresses()
            
            for broadcast_addr in broadcast_addresses:
                try:
                    self.socket.sendto(broadcast_data, (broadcast_addr, self.broadcast_port))
                    logger.debug(f"Broadcasted to {broadcast_addr}:{self.broadcast_port}")
                except Exception as e:
                    logger.debug(f"Failed to broadcast to {broadcast_addr}: {e}")
            
            logger.info(f"UDP broadcast sent: {self.server_info['service']} at {self.server_info['url']}")
            
        except Exception as e:
            logger.error(f"UDP broadcast failed: {e}")
    
    def _get_broadcast_addresses(self) -> list:
        """Get list of broadcast addresses for all network interfaces"""
        broadcast_addresses = ['255.255.255.255']  # Global broadcast
        
        try:
            import netifaces
            
            # Get all network interfaces
            for interface in netifaces.interfaces():
                try:
                    # Get IPv4 addresses for this interface
                    addrs = netifaces.ifaddresses(interface)
                    if netifaces.AF_INET in addrs:
                        for addr_info in addrs[netifaces.AF_INET]:
                            if 'broadcast' in addr_info:
                                broadcast_addr = addr_info['broadcast']
                                if broadcast_addr not in broadcast_addresses:
                                    broadcast_addresses.append(broadcast_addr)
                except Exception:
                    continue
                    
        except ImportError:
            # netifaces not available, use basic approach
            logger.debug("netifaces not available, using global broadcast only")
        except Exception as e:
            logger.debug(f"Error getting network interfaces: {e}")
        
        return broadcast_addresses
    
    def get_current_server_info(self) -> Dict[str, Any]:
        """Get current server information"""
        return self.server_info.copy()