"""Service Container for Dependency Injection.

This module provides a singleton container that manages service instances
and their dependencies, ensuring consistent state across all interfaces
(REST API, BLE GATT, plugins, etc.).
"""
from typing import Optional

from ..workers.pm3_worker import PM3Worker, SubprocessPM3Worker
from ..managers.session_manager import SessionManager
from ..managers.wifi_manager import WiFiManager
from ..managers.update_manager import get_update_manager
from ..managers.pm3_device_manager import PM3DeviceManager

from .pm3_service import PM3Service
from .system_service import SystemService
from .wifi_service import WiFiService
from .update_service import UpdateService


class ServiceContainer:
    """Dependency injection container for services.

    This container:
    - Creates and manages singleton instances of services
    - Injects shared dependencies (workers, managers)
    - Ensures consistent state across all interfaces
    - Provides centralized access to services

    Usage:
        # In REST API
        from app.backend.services.container import container
        result = await container.pm3_service.execute_command(...)

        # In BLE GATT
        from app.backend.services.container import container
        result = await container.pm3_service.execute_command(...)

        # Both use the same service instance!
    """

    _instance: Optional['ServiceContainer'] = None

    def __init__(self):
        """Initialize service container with shared dependencies."""
        if ServiceContainer._instance is not None:
            raise RuntimeError(
                "ServiceContainer is a singleton. Use container.get_instance() "
                "or import the global 'container' instance."
            )

        # Create shared worker/manager instances
        # These are the low-level components that services will use
        # Use PM3Worker with SWIG bindings for better performance
        # Falls back to SubprocessPM3Worker if SWIG import fails
        try:
            self._pm3_worker = PM3Worker()  # Try SWIG bindings first
        except Exception:
            self._pm3_worker = SubprocessPM3Worker()  # Fallback to subprocess
        self._pm3_device_manager = PM3DeviceManager()  # NEW: Multi-device manager
        self._session_manager = SessionManager()
        self._wifi_manager = WiFiManager()
        self._update_manager = get_update_manager()

        # Create service instances with injected dependencies
        self._pm3_service = PM3Service(
            pm3_worker=self._pm3_worker,
            session_manager=self._session_manager,
            device_manager=self._pm3_device_manager  # NEW: Multi-device support
        )

        self._system_service = SystemService()

        self._wifi_service = WiFiService(
            wifi_manager=self._wifi_manager
        )

        self._update_service = UpdateService(
            update_manager=self._update_manager
        )

        # Note: WorkflowService will be added in Phase 5
        # self._workflow_service = WorkflowService(
        #     pm3_service=self._pm3_service
        # )

    @classmethod
    def get_instance(cls) -> 'ServiceContainer':
        """Get the singleton service container instance.

        Returns:
            ServiceContainer instance
        """
        if cls._instance is None:
            cls._instance = ServiceContainer()
        return cls._instance

    @classmethod
    def reset_instance(cls):
        """Reset the singleton instance.

        This is primarily used for testing purposes.
        """
        cls._instance = None

    # Service properties (read-only access)

    @property
    def pm3_service(self) -> PM3Service:
        """Get PM3 service instance.

        Returns:
            Shared PM3Service instance
        """
        return self._pm3_service

    @property
    def system_service(self) -> SystemService:
        """Get system service instance.

        Returns:
            Shared SystemService instance
        """
        return self._system_service

    @property
    def wifi_service(self) -> WiFiService:
        """Get WiFi service instance.

        Returns:
            Shared WiFiService instance
        """
        return self._wifi_service

    @property
    def update_service(self) -> UpdateService:
        """Get update service instance.

        Returns:
            Shared UpdateService instance
        """
        return self._update_service

    # Manager/Worker access (for cases where direct access is needed)

    @property
    def pm3_worker(self) -> PM3Worker:
        """Get PM3 worker instance.

        Returns:
            Shared PM3Worker instance
        """
        return self._pm3_worker

    @property
    def session_manager(self) -> SessionManager:
        """Get session manager instance.

        Returns:
            Shared SessionManager instance
        """
        return self._session_manager

    @property
    def wifi_manager(self) -> WiFiManager:
        """Get WiFi manager instance.

        Returns:
            Shared WiFiManager instance
        """
        return self._wifi_manager

    @property
    def pm3_device_manager(self) -> PM3DeviceManager:
        """Get PM3 device manager instance.

        Returns:
            Shared PM3DeviceManager instance for multi-device support
        """
        return self._pm3_device_manager


# Global singleton instance
# Import this throughout the codebase for consistent service access
container = ServiceContainer.get_instance()


# Convenience exports for common services
__all__ = [
    'ServiceContainer',
    'container',
]
