from abc import abstractmethod
from typing import Any, Dict, Optional, Set, Type, Callable

from ._DependencyMapAdapterBase import DependencyMapAdapterBase
from ._types import AnyType


class DependencyContext(DependencyMapAdapterBase):
    """Dependency Context for managing dependency injection"""

    @abstractmethod
    def get_instances_by_type(
        self,
        parent_type: Type[AnyType],
    ) -> Set[AnyType]:
        """Retrieves all instances of a given type.

        Args:
            parent_type (Type[AnyType]): The type of the instances to retrieve.

        Returns:
            Set[AnyType]: A set of dependency instances matching the parent type.
        """
        raise NotImplementedError()

    @abstractmethod
    def get_instance(
        self,
        instance_cls: Type[AnyType],
        params: Optional[Dict[str, Any]] = None
    ) -> AnyType:
        """Retrieves or creates a single instance of a given dependency class.

        Args:
            instance_cls (Type[AnyType]): The class of the dependency to retrieve or create.
            params (Optional[Dict[str, Any]], optional): Optional parameters for instance creation. Defaults to None.

        Returns:
            AnyType: The dependency instance.
        """
        raise NotImplementedError()

    @abstractmethod
    def call_function(
        self,
        function: Callable[..., AnyType],
        params: Optional[Dict[str, Any]] = None
    ) -> AnyType:
        """Call an function with injected parameters

        Args:
            function (Callable): The function for which to resolve parameters.
            params (Optional[Dict[str, Any]], optional): Additional parameters to consider during resolution. Defaults to None.

        Returns:
            AnyType: The result of the function call.
        """
        raise NotImplementedError()

    @abstractmethod
    def dispose(self):
        """Disposes of all managed dependency instances."""
        raise NotImplementedError()
