"""Auto-discovery of feature packages for router, tool, and client registration.

Scans ``peon_mcp/`` for sub-packages that follow the standard convention
(``routes.py``, ``tools.py``, ``client.py``) and returns the discovered
objects so that ``web.py``, ``server.py``, and ``api_client.py`` no longer
need explicit per-feature imports.
"""

from __future__ import annotations

import importlib
import inspect
import pkgutil
from typing import Any

import peon_mcp

_EXCLUDE: frozenset[str] = frozenset({"common", "static", "hooks", "migrations", "grukk", "goblin"})


def _feature_package_names() -> list[str]:
    """Return sorted names of all feature sub-packages (excludes *common* and *static*)."""
    names: list[str] = []
    for info in pkgutil.iter_modules(peon_mcp.__path__):
        if info.ispkg and info.name not in _EXCLUDE:
            names.append(info.name)
    return sorted(names)


def discover_routers() -> list[Any]:
    """Import ``routes.router`` (and optionally ``routes.public_router``) from each feature package.

    Returns a list of :class:`fastapi.APIRouter` instances.
    Packages without a ``routes`` module are silently skipped.
    """
    routers = []
    for name in _feature_package_names():
        try:
            mod = importlib.import_module(f"peon_mcp.{name}.routes")
        except ImportError:
            continue
        router = getattr(mod, "router", None)
        if router is not None:
            routers.append(router)
        public_router = getattr(mod, "public_router", None)
        if public_router is not None:
            routers.append(public_router)
    return routers


def discover_tool_registrations() -> list[Any]:
    """Import ``tools.register_tools`` from each feature package.

    Returns a sorted list of callables with signature ``(mcp, api_fn)``.
    Packages without a ``tools`` module are silently skipped.
    """
    registrations = []
    for name in _feature_package_names():
        try:
            mod = importlib.import_module(f"peon_mcp.{name}.tools")
        except ImportError:
            continue
        fn = getattr(mod, "register_tools", None)
        if fn is not None:
            registrations.append(fn)
    return registrations


def discover_client_classes() -> list[type]:
    """Import ``*Client`` subclasses of :class:`BaseAPIClient` from each feature package.

    Returns a sorted list of types suitable for composing via multiple inheritance.
    Packages without a ``client`` module are silently skipped.
    """
    from peon_mcp.common.base_client import BaseAPIClient

    classes = []
    for name in _feature_package_names():
        try:
            mod = importlib.import_module(f"peon_mcp.{name}.client")
        except ImportError:
            continue
        for attr_name, attr_val in inspect.getmembers(mod, inspect.isclass):
            if (
                attr_name.endswith("Client")
                and issubclass(attr_val, BaseAPIClient)
                and attr_val is not BaseAPIClient
            ):
                classes.append(attr_val)
    return classes
