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