"""Decorators and helpers for punq-backed dependency injection."""

from typing import Any, Callable

from punq import Container

_default_container: Container | None = None


def set_default_container(container: Container) -> None:
    """Set the default container used by registration and feature decorators."""

    global _default_container
    _default_container = container


def clear_default_container() -> None:
    """Clear any configured default container."""

    global _default_container
    _default_container = None


def get_default_container() -> Container:
    """Return the configured default container."""

    if _default_container is None:
        raise RuntimeError(
            "No default punq.Container configured. "
            "Call set_default_container(container) or pass container=... explicitly."
        )
    return _default_container


def _resolve_container(container: Container | None = None) -> Container:
    if container is not None:
        return container
    return get_default_container()


def _infer_interface(cls: type[Any]) -> type[Any]:
    for base in cls.__bases__:
        if base is object:
            continue
        if isinstance(base, type) and getattr(base, "_is_protocol", False):
            return base
        return base

    raise ValueError(
        f"Cannot infer adapter interface for '{cls.__name__}'. "
        "Provide one via @register(interface=...)."
    )


def register(
    cls: type[Any] | None = None,
    *,
    interface: type[Any] | None = None,
    container: Container | None = None,
) -> type[Any] | Callable[[type[Any]], type[Any]]:
    """Register a class into a punq container."""

    def _register(target: type[Any]) -> type[Any]:
        target_interface = interface or _infer_interface(target)
        active_container = _resolve_container(container)
        active_container.register(target_interface, target)
        if target_interface is not target:
            active_container.register(target)
        return target

    if cls is None:
        return _register
    return _register(cls)


component = adapter = controller = policy = repository = service = usecase = seed = register


__all__ = [
    "adapter",
    "clear_default_container",
    "component",
    "controller",
    "get_default_container",
    "policy",
    "register",
    "repository",
    "seed",
    "service",
    "set_default_container",
    "usecase",
]

