from __future__ import annotations

from typing import Protocol, runtime_checkable

from abcreg import AnnotatedProtocolMeta  # type: ignore[import-untyped]

_DEFAULT_METHODS = ("link_name", "subpage_html", "summary_value_suffix_html")


def _install_default_methods(interface: type, impl: type) -> None:
    """Give implementations the protocol's optional methods before signature checks."""
    if getattr(impl, "_is_protocol", False):
        return
    skip = set(interface.__mro__)
    for name in _DEFAULT_METHODS:
        if any(name in base.__dict__ for base in impl.__mro__ if base not in skip):
            continue
        for base in interface.__mro__:
            default = base.__dict__.get(name)
            if callable(default):
                setattr(impl, name, default)
                break


class _SubpageMeta(AnnotatedProtocolMeta):
    def __init__(
        cls,
        name: str,
        bases: tuple[type, ...],
        namespace: dict[str, object],
        **kwargs: object,
    ) -> None:
        if not getattr(cls, "_is_protocol", False):
            for base in bases:
                if isinstance(base, _SubpageMeta) and getattr(base, "_is_protocol", False):
                    _install_default_methods(base, cls)
        super().__init__(name, bases, namespace, **kwargs)

    def register(cls, subclass: type) -> type:
        _install_default_methods(cls, subclass)
        super().register(subclass)
        return subclass


@runtime_checkable
class Subpage(Protocol, metaclass=_SubpageMeta):
    """
    Subpage: A per-project subpage provided by a plugin.

    Subclass this protocol, or register a virtual subclass with ``@Subpage.register``.
    """

    def subpage_name(self) -> str: ...

    def link_name(self, project: str) -> str | None:
        return None

    def subpage_html(self, project: str) -> str | None:
        return None

    def summary_value_suffix_html(self, project: str, project_enc: str) -> str | None:
        """Optional HTML appended after the subpage \"view\" link on the project summary table."""
        return None