"""Enhanced main controller implementing IMainCtrl interface."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any
from weakref import WeakValueDictionary

from PySide2.QtCore import QObject, Signal

from pytola_sim.lscsim.utils.logger import get_logger

if TYPE_CHECKING:
    from pytola_sim.lscsim.interfaces.icomponent import IComponent

logger = get_logger(__name__)


class EnhancedMainController(
    QObject,
):  # Removed IMainCtrl inheritance due to metaclass conflict
    """Enhanced main controller implementing full IMainCtrl interface.

    This controller provides complete component management, command routing,
    and message handling capabilities equivalent to the C++ MainCtrl.
    """

    # Qt Signals
    status_message_changed = Signal(str)
    component_registered = Signal(str)
    command_executed = Signal(str, bool)
    message_sent = Signal(str)

    def __init__(self) -> None:
        super().__init__()
        self._components: dict[str, IComponent] = {}
        self._weak_components: WeakValueDictionary[str, IComponent] = WeakValueDictionary()
        self._commands: dict[str, IComponent] = {}
        self._messages: dict[str, list[Any]] = {}
        self._special_interfaces: dict[str, Any] = {}
        self._timers: dict[int, IComponent] = {}
        self._window_handle: Any = None

        # Initialize the system
        self.init()
        logger.info("Enhanced main controller initialized")

    def init(self) -> None:
        """Initialize the main controller system."""
        logger.info("Initializing enhanced main controller")
        self._register_all_components()
        self._setup_message_system()
        logger.info("Main controller initialization completed")

    def _register_all_components(self) -> None:
        """Register all system components.

        This method should be overridden by subclasses to register
        specific components for the application.
        """
        logger.debug("Registering system components")
        # Base registration - will be extended by specific implementations

    def _setup_message_system(self) -> None:
        """Set up the message handling system."""
        logger.debug("Setting up message system")
        # Initialize message handlers and subscriptions

    def get_component(self, component_id: str) -> IComponent | None:
        """Get component by ID."""
        component = self._components.get(component_id)
        if component is None:
            component = self._weak_components.get(component_id)

        if component:
            logger.debug(f"Retrieved component: {component_id}")
        else:
            logger.warning(f"Component not found: {component_id}")

        return component

    def execute_command(
        self,
        command_id: str,
        in_param: object = None,
        out_param: object = None,
    ) -> bool:
        """Execute a command by routing it to the appropriate component."""
        logger.debug(f"Executing command: {command_id}")

        try:
            if command_id in self._commands:
                component = self._commands[command_id]
                # Assuming component has execute_command method
                result = component.execute_command(command_id, in_param, out_param)
                logger.info(f"Command {command_id} executed successfully")
                self.command_executed.emit(command_id, True)  # noqa: FBT003
                return result
            error_msg = f"Unknown command: {command_id}"
            logger.error(error_msg)
            self.command_executed.emit(command_id, False)  # noqa: FBT003
        except (OSError, RuntimeError, ValueError):
            logger.exception(f"Command {command_id} failed with exception")
            self.command_executed.emit(command_id, False)  # noqa: FBT003
            return False
        else:
            return False

    def send_message(self, message: str, value: int = 0, param: object = None) -> None:
        """Send message to all registered handlers."""
        logger.debug(f"Sending message: {message}")

        try:
            if message in self._messages:
                for handler in self._messages[message]:
                    self._safe_handle_message(handler, message, value, param)

            self.message_sent.emit(message)
            logger.debug(f"Message {message} sent to handlers")

        except (OSError, RuntimeError, ValueError):
            logger.exception(f"Failed to send message {message}")

    def send_message_to_main(
        self,
        message: str,
        value: int = 0,
        param: object = None,
    ) -> None:
        """Send message specifically to main window."""
        logger.debug(f"Sending message to main window: {message}")
        # Implementation depends on main window integration
        self.send_message(message, value, param)

    def get_interface_ptr(self, interface_id: str) -> object | None:
        """Get specialized interface pointer."""
        interface = self._special_interfaces.get(interface_id)
        if interface:
            logger.debug(f"Retrieved interface: {interface_id}")
        else:
            logger.debug(f"Interface not found: {interface_id}")
        return interface

    def set_window_handle(self, handle_id: object) -> None:
        """Set main window handle."""
        self._window_handle = handle_id
        logger.debug(f"Window handle set: {handle_id}")

    def quit(self) -> None:
        """Quit the application gracefully."""
        logger.info("Shutting down main controller")

        # Release all components
        for component in self._components.values():
            self._safe_release_component(component)

        # Clear all collections
        self._components.clear()
        self._weak_components.clear()
        self._commands.clear()
        self._messages.clear()
        self._special_interfaces.clear()
        self._timers.clear()

        logger.info("Main controller shutdown completed")

    def _safe_handle_message(
        self,
        handler: object,
        message: str,
        value: int,
        param: object,
    ) -> None:
        """Safely handle a message with exception handling."""
        try:
            handler.handle_message(message, value, param)  # type: ignore[attr-defined]
        except (OSError, RuntimeError, ValueError):
            logger.exception(f"Error in message handler for {message}")

    def _safe_release_component(self, component: object) -> None:
        """Safely release a component with exception handling."""
        try:
            component.release()  # type: ignore[attr-defined]
        except (OSError, RuntimeError, ValueError):
            logger.exception("Error releasing component")

    def get_window_handle(self) -> int:
        """Get main window handle."""
        if self._window_handle is not None:
            return id(self._window_handle)
        return 0

    def add_hit_info(self, hit_info: str) -> None:
        """Add hint/information message."""
        logger.info(f"Hint info: {hit_info}")
        self.status_message_changed.emit(hit_info)

    # Component Management Methods
    def register_component(self, component: IComponent) -> bool:
        """Register a component with the system."""
        try:
            component_id = component.get_id()

            if component_id in self._components:
                logger.warning(f"Component {component_id} already registered")
                return False

            # Set main controller reference
            component.set_main_ctrl(self)

            # Store component
            self._components[component_id] = component
            self._weak_components[component_id] = component

            # Initialize component
            component.init()

            # Register component interfaces
            self._register_component_interfaces(component)

            logger.info(f"Component registered: {component_id}")
            self.component_registered.emit(component_id)
        except (OSError, RuntimeError, ValueError):
            logger.exception("Failed to register component")
            return False
        else:
            return True

    def unregister_component(self, component_id: str) -> bool:
        """Unregister a component from the system."""
        try:
            component = self._components.pop(component_id, None)
            self._weak_components.pop(component_id, None)

            if component:
                # Remove from command mappings
                commands_to_remove = [cmd for cmd, comp in self._commands.items() if comp == component]
                for cmd in commands_to_remove:
                    del self._commands[cmd]

                # Remove from message handlers
                for msg_handlers in self._messages.values():
                    if component in msg_handlers:
                        msg_handlers.remove(component)

                # Remove from special interfaces
                interfaces_to_remove = [iface for iface, comp in self._special_interfaces.items() if comp == component]
                for iface in interfaces_to_remove:
                    del self._special_interfaces[iface]

                # Release component
                component.release()

                logger.info(f"Component unregistered: {component_id}")
                return True
            logger.warning(
                f"Component not found for unregistration: {component_id}",
            )
        except (OSError, RuntimeError, ValueError):
            logger.exception(f"Failed to unregister component {component_id}")
            return False
        else:
            return False

    def _register_component_interfaces(self, component: IComponent) -> None:
        """Register all interfaces provided by a component."""
        try:
            interface_count = component.get_interface_count()

            for i in range(interface_count):
                interface_id = component.get_interface_id(i)
                interface_ptr = component.get_interface_ptr(interface_id)

                if interface_ptr is not None:
                    self._special_interfaces[interface_id] = interface_ptr
                    logger.debug(f"Registered interface: {interface_id}")

        except (OSError, RuntimeError, ValueError):
            logger.exception("Error registering component interfaces")

    def register_command(self, component: IComponent, command_ids: list[str]) -> None:
        """Register commands for a component."""
        for command_id in command_ids:
            self._commands[command_id] = component
            logger.debug(
                f"Registered command {command_id} for component {component.get_id()}",
            )

    def register_message_handler(
        self,
        component: IComponent,
        message_ids: list[str],
    ) -> None:
        """Register message handlers for a component."""
        for message_id in message_ids:
            if message_id not in self._messages:
                self._messages[message_id] = []
            self._messages[message_id].append(component)
            logger.debug(
                f"Registered message handler {message_id} for component {component.get_id()}",
            )

    def register_timer(self, timer_id: int, component: IComponent) -> None:
        """Register timer callback for a component."""
        self._timers[timer_id] = component
        logger.debug(f"Registered timer {timer_id} for component {component.get_id()}")

    # Utility Methods
    def get_all_components(self) -> list[IComponent]:
        """Get list of all registered components."""
        return list(self._components.values())

    def get_component_ids(self) -> list[str]:
        """Get list of all component IDs."""
        return list(self._components.keys())

    def has_component(self, component_id: str) -> bool:
        """Check if component is registered."""
        return component_id in self._components or component_id in self._weak_components


# Backward compatibility alias
MainCtrl = EnhancedMainController
