"""Service base class for the ABM Framework.

Services provide shared functionality that can be accessed by agents without
creating circular dependencies between agents and the world/simulation context.
"""

from typing import TYPE_CHECKING, Dict, Type, Optional

if TYPE_CHECKING:
    from layer2_simulation.world_builder import WorldBuilder


class Service:
    """Base class for services that provide functionality to agents.

    Services are registered with a ServiceRegistry and can be accessed by agents
    without needing to import or hold references to the full World/Simulation.

    Examples of services:
    - NetworkManager: manages relationships between agents
    - ResourceManager: manages shared resources
    - EventBus: facilitates communication between agents
    - DataCollector: collects metrics during simulation
    """

    def __init__(self, service_id: str):
        """Initialize a Service.

        Args:
            service_id: Unique identifier for this service
        """
        self.service_id = service_id
        self._world: Optional['WorldBuilder'] = None

    def register_world(self, world: 'WorldBuilder') -> None:
        """Register the world/simulation context with this service.

        This allows the service to access other services or world state if needed,
        while keeping agents decoupled from the world.

        Args:
            world: The WorldBuilder instance
        """
        self._world = world

    def get_world(self) -> Optional['WorldBuilder']:
        """Get the registered world context.

        Returns:
            The WorldBuilder instance, or None if not registered
        """
        return self._world

    def __repr__(self):
        return f"{self.__class__.__name__}({self.service_id})"


class ServiceRegistry:
    """Registry for managing services in a simulation.

    The ServiceRegistry allows services to be registered by type and retrieved
    by agents or other services as needed. This provides a clean way to manage
    dependencies without circular imports.
    """

    def __init__(self):
        """Initialize a ServiceRegistry."""
        self._services: Dict[str, Service] = {}
        self._services_by_type: Dict[Type[Service], Service] = {}

    def register(self, service: Service) -> None:
        """Register a service.

        Args:
            service: The service instance to register
        """
        self._services[service.service_id] = service
        self._services_by_type[type(service)] = service

    def get(self, service_id: str) -> Optional[Service]:
        """Get a service by its ID.

        Args:
            service_id: The service identifier

        Returns:
            The service instance, or None if not found
        """
        return self._services.get(service_id)

    def get_by_type(self, service_type: Type[Service]) -> Optional[Service]:
        """Get a service by its type.

        Args:
            service_type: The service class type

        Returns:
            The service instance, or None if not found
        """
        return self._services_by_type.get(service_type)

    def has(self, service_id: str) -> bool:
        """Check if a service is registered.

        Args:
            service_id: The service identifier

        Returns:
            True if the service is registered, False otherwise
        """
        return service_id in self._services

    def has_type(self, service_type: Type[Service]) -> bool:
        """Check if a service of a given type is registered.

        Args:
            service_type: The service class type

        Returns:
            True if a service of that type is registered, False otherwise
        """
        return service_type in self._services_by_type

    def __repr__(self):
        return f"ServiceRegistry(services={len(self._services)})"