from typing import Type, Any, Optional, Set, Union, Callable

from . import DependencyBuilder
from ._DependencyManagerBase import DependencyManagerBase
from ._DependencyMap import DependencyMap, BuilderType
from ._types import AnyType
from ._utils import DEFAULT_LOGGER


class DependencyMapAdapterBase(DependencyManagerBase):
    """
    An adapter for a DependencyMap that implements the DependencyManagerBase interface.

    This class delegates most of its functionality to an underlying DependencyMap instance.
    It serves as a base class for more complex dependency managers that might add
    functionality on top of a simple dependency map.
    """

    def __init__(self, dependency_map: DependencyMap):
        """Initializes the DependencyMapAdapterBase.

        Args:
            dependency_map (DependencyMap): The DependencyMap instance to adapt.
        """
        self.dependency_map = dependency_map
        self.logger = DEFAULT_LOGGER
    def add_dependency_class(self, dep_cls: Type[AnyType]):
        """Registers a class as a dependency.

        Args:
            dep_cls (Type[AnyType]): The dependency class to register.
        """
        self.dependency_map.add_dependency_class(dep_cls)

    def add_dependency_extra_parameter(
        self,
        parameter_name: str,
        parameter_value: Any,
        for_type: Optional[Type] = None
    ):
        """Adds an extra parameter for dependency instantiation.

        Args:
            parameter_name (str): The name of the parameter.
            parameter_value (Any): The value of the parameter.
            for_type (Type, optional): The specific type this parameter is for. If None, it's a global parameter.
        """
        self.dependency_map.add_dependency_extra_parameter(
            parameter_name=parameter_name,
            parameter_value=parameter_value,
            for_type=for_type,
        )

    def add_dependency_extra_parameters(
        self,
        parameters: Any,
        for_type: Optional[Type] = None,
    ):
        """Adds multiple extra parameters for dependency instantiation.

        Args:
            parameters (Any): A dictionary or object with parameter names and values.
            for_type (Type, optional): The specific type these parameters are for. If None, they are global.
        """
        self.dependency_map.add_dependency_extra_parameters(
            parameters=parameters,
            for_type=for_type,
        )

    def get_dependencies_by_parent(self, parent_type: Type[AnyType]) -> Set[Type[AnyType]]:
        """Gets all registered dependency classes that are subclasses of a given parent type.

        Args:
            parent_type (Type[AnyType]): The parent type to search for.

        Returns:
            A set of dependency types that inherit from the parent type.
        """
        return self.dependency_map.get_dependencies_by_parent(parent_type)

    def add_dependency_instance(self, dependency_instance: Any):
        """Adds a pre-existing instance to the dependency map.

        The instance's type is also registered as a dependency class.

        Args:
            dependency_instance (Any): The instance to add.
        """
        self.dependency_map.add_dependency_instance(dependency_instance)
        self.add_dependency_class(type(dependency_instance))

    def has_instance(self, instance_cls: Type) -> bool:
        """Checks if an instance of a specific class is present in the dependency map.

        Args:
            instance_cls (Type): The class type to check for.

        Returns:
            True if an instance exists, False otherwise.
        """
        return self.dependency_map.has_instance(
            instance_cls=instance_cls,
        )

    def get_instance(self, instance_cls: Type[AnyType]) -> AnyType:
        """Retrieves a pre-existing instance of a specific class from the dependency map.

        Args:
            instance_cls (Type[AnyType]): The class type of the instance to retrieve.

        Returns:
            The stored instance.
        """
        return self.dependency_map.get_instance(
            instance_cls=instance_cls,
        )

    def has_extra_parameter(self, parameter_name: str, for_type: Optional[Type] = None) -> bool:
        """Checks if an extra parameter is defined.

        Args:
            parameter_name (str): The name of the parameter.
            for_type (Type, optional): The specific type the parameter might be for.

        Returns:
            True if the parameter is defined, False otherwise.
        """
        return self.dependency_map.has_extra_parameter(
            parameter_name=parameter_name,
            for_type=for_type,
        )

    def get_extra_parameter(self, parameter_name: str, for_type: Optional[Type] = None) -> Any:
        """Gets the value of an extra parameter.

        Args:
            parameter_name (str): The name of the parameter.
            for_type (Type, optional): The specific type the parameter is for.

        Returns:
            The value of the parameter.
        """
        return self.dependency_map.get_extra_parameter(
            parameter_name=parameter_name,
            for_type=for_type,
        )

    def has_dependency_class(self, dependency_cls: Type) -> bool:
        """Checks if a dependency class is registered.

        Args:
            dependency_cls (Type): The class to check.

        Returns:
            True if the class is registered, False otherwise.
        """
        return self.dependency_map.has_dependency_class(
            dependency_cls=dependency_cls,
        )

    def get_dependency_class(self, dependency_cls: Type[AnyType]) -> Type[AnyType]:
        """Gets a registered dependency class.

        Args:
            dependency_cls (Type[AnyType]): The class to retrieve.

        Returns:
            The registered dependency class.
        """
        return self.dependency_map.get_dependency_class(
            dependency_cls=dependency_cls,
        )

    def add_builder(self, builder: BuilderType, for_type: Optional[Type[AnyType]] = None):
        """Adds a custom builder for a specific type.

        Args:
            builder (BuilderType): The builder class or callable.
            for_type (Type[AnyType], optional): The type this builder is responsible for creating.
        """
        return self.dependency_map.add_builder(
            builder=builder,
            for_type=for_type,
        )
