"""Feature flag helpers."""

from functools import wraps
from typing import Any, Callable

from punq import Container  # type: ignore[import-untyped]

from .runtime.context import get_app_context
from .support.errors import FeatureDisabledError

ERR_FMT = "feature_enabled requires /feature/<context>/<use_case>"

SettingNameFactory = Callable[[str], Any]


def configure_feature_flags(*args, **kwargs) -> None:
    raise RuntimeError(
        "Global feature flag configuration was removed. Pass settings_interface=... to feature_enabled()."
    )


def clear_feature_flag_config() -> None:
    return None


def _feature_setting_name(feature_path: str, setting_name_factory: SettingNameFactory) -> Any:
    path = feature_path.strip()
    if not path:
        raise ValueError("feature_enabled requires a non-empty feature path")
    normalized = path if path.startswith("/") else f"/{path}"
    if not normalized.startswith("/feature/"):
        raise ValueError("feature_enabled requires a path starting with /feature/")
    parts = [part for part in normalized.strip("/").split("/") if part]
    parts.pop(0)
    if len(parts) != 2:
        raise ValueError(ERR_FMT)
    context, use_case = parts
    return setting_name_factory(f"/feature/{context}/{use_case}/enabled")


def feature_enabled(
    feature_path: str,
    default: bool = True,
    message: str | None = None,
    *,
    settings_interface: type[Any],
    setting_name_factory: SettingNameFactory | None = None,
    disabled_exception: type[Exception] | None = None,
    container: Container | None = None,
) -> Callable[[type[Any]], type[Any]]:
    """Guard a callable class with a feature flag."""

    if not isinstance(settings_interface, type):
        raise TypeError("settings_interface must be a type used for container resolution")
    if setting_name_factory is not None and not callable(setting_name_factory):
        raise TypeError("setting_name_factory must be callable")
    resolved_exception = disabled_exception or FeatureDisabledError
    if not issubclass(resolved_exception, Exception):
        raise TypeError("disabled_exception must be an Exception subclass")
    resolved_name = _feature_setting_name(feature_path, setting_name_factory or (lambda value: value))

    def decorator(cls: type[Any]) -> type[Any]:
        original_call = getattr(cls, "__call__", None)
        if original_call is None:
            raise TypeError("feature_enabled can only decorate classes with a __call__ method")

        @wraps(original_call)
        def wrapped(self: Any, *args: Any, **kwargs: Any) -> Any:
            active_container = container or get_app_context()
            try:
                settings = active_container.resolve(settings_interface)
            except Exception as exc:
                raise RuntimeError(
                    f"Could not resolve feature settings interface '{settings_interface.__name__}' from the container."
                ) from exc
            if not settings.is_feature_enabled(resolved_name, default=default):
                raise resolved_exception(message or f"Feature disabled: {resolved_name}")
            return original_call(self, *args, **kwargs)

        setattr(cls, "__call__", wrapped)
        return cls

    return decorator


__all__ = ["ERR_FMT", "clear_feature_flag_config", "configure_feature_flags", "feature_enabled"]
