from __future__ import annotations

import importlib.metadata
import logging
from collections.abc import Iterable

from pygitweb.api.action import Action
from pygitweb.api.subpage import Subpage
from pygitweb.config import ACTIONS as BUILTIN_ACTIONS

logger = logging.getLogger(__name__)

SUBPAGE_GROUP = "pygitweb.subpages"
ACTION_GROUP = "pygitweb.actions"


def _entry_points(group: str) -> Iterable[importlib.metadata.EntryPoint]:
	return importlib.metadata.entry_points().select(group=group)


def load_subpages() -> list[Subpage]:
	out: list[Subpage] = []
	seen_names: set[str] = set()
	for ep in _entry_points(SUBPAGE_GROUP):
		try:
			loaded = ep.load()
		except Exception:
			logger.exception("pygitweb: failed to load subpage entry point %r", ep.name)
			continue
		if not isinstance(loaded, type) or not issubclass(loaded, Subpage):
			logger.error(
				"pygitweb: entry point %r must be a Subpage subclass, got %r",
				ep.name,
				loaded,
			)
			continue
		try:
			instance = loaded()
		except Exception:
			logger.exception("pygitweb: failed to instantiate subpage %r", ep.name)
			continue
		key = instance.subpage_name()
		if key in seen_names:
			logger.warning("pygitweb: duplicate subpage %r from %r; skipping", key, ep.name)
			continue
		seen_names.add(key)
		out.append(instance)
	return out


def load_plugin_actions() -> dict[str, Action]:
	out: dict[str, Action] = {}
	for ep in _entry_points(ACTION_GROUP):
		try:
			loaded = ep.load()
		except Exception:
			logger.exception("pygitweb: failed to load action entry point %r", ep.name)
			continue
		if not isinstance(loaded, type) or not issubclass(loaded, Action):
			logger.error(
				"pygitweb: entry point %r must be an Action subclass, got %r",
				ep.name,
				loaded,
			)
			continue
		try:
			instance = loaded()
		except Exception:
			logger.exception("pygitweb: failed to instantiate action %r", ep.name)
			continue
		name = instance.action_name()
		if name in BUILTIN_ACTIONS:
			logger.warning(
				"pygitweb: plugin action %r conflicts with built-in; skipping entry %r",
				name,
				ep.name,
			)
			continue
		if name in out:
			logger.warning("pygitweb: duplicate plugin action %r; skipping entry %r", name, ep.name)
			continue
		out[name] = instance
	return out