"""Custom exceptions for the inversipy library."""

from typing import Any


class InversipyError(Exception):
    """Base exception for all inversipy errors."""

    pass


class DependencyNotFoundError(InversipyError):
    """Raised when a dependency cannot be found in the container."""

    def __init__(
        self,
        dependency_type: type[Any],
        container_name: str = "container",
        name: str | None = None,
    ) -> None:
        self.dependency_type = dependency_type
        self.container_name = container_name
        self.name = name

        if name:
            msg = (
                f"Dependency '{dependency_type.__name__}' with name '{name}' "
                f"not found in {container_name}"
            )
        else:
            msg = f"Dependency '{dependency_type.__name__}' not found in {container_name}"
        super().__init__(msg)


class CircularDependencyError(InversipyError):
    """Raised when a circular dependency is detected."""

    def __init__(self, dependency_chain: list[type[Any]]) -> None:
        self.dependency_chain = dependency_chain
        chain_str = " -> ".join(dep.__name__ for dep in dependency_chain)
        super().__init__(f"Circular dependency detected: {chain_str}")


class ValidationError(InversipyError):
    """Raised when container validation fails."""

    def __init__(self, errors: list[str]) -> None:
        self.errors = errors
        error_messages = "\n  - " + "\n  - ".join(errors)
        super().__init__(
            f"Container validation failed with {len(errors)} error(s):{error_messages}"
        )


class InvalidScopeError(InversipyError):
    """Raised when an invalid scope is used."""

    pass


class RegistrationError(InversipyError):
    """Raised when there's an error during dependency registration."""

    pass


class ResolutionError(InversipyError):
    """Raised when there's an error during dependency resolution."""

    pass


class AmbiguousDependencyError(InversipyError):
    """Raised when multiple implementations exist for a single get() call.

    This error indicates that the container has multiple implementations
    registered for the requested interface, and it cannot determine which
    one to return. Use get_all() to retrieve all implementations, or use
    named bindings to disambiguate.
    """

    def __init__(
        self,
        dependency_type: type[Any],
        count: int,
        container_name: str = "container",
    ) -> None:
        self.dependency_type = dependency_type
        self.count = count
        self.container_name = container_name
        super().__init__(
            f"Ambiguous dependency: {count} implementations of "
            f"'{dependency_type.__name__}' registered in {container_name}. "
            f"Use get_all() for collection injection or register with name= for disambiguation."
        )
