"""Formal adapter for built-in tools following the adapter lifecycle pattern.

Provides the :class:`BuiltinAdapter` class that wraps the existing
``register_file_tools``, ``register_git_tools``, and
``register_subplan_tool`` functions behind a unified adapter interface
with ``discover``, ``register``, ``activate``, and ``deactivate``
lifecycle methods.

The adapter follows the same lifecycle naming used by
:class:`~cleveragents.skill.loader.AgentSkillLoader` (``discover``,
``register``, ``activate``, ``deactivate``) rather than the connection-
oriented naming of :class:`~cleveragents.mcp.adapter.MCPToolAdapter`
(``connect``, ``discover_tools``, ``register_tools``, ``disconnect``).
Built-in tools are always in the default namespace, so ``register``
does not accept a ``namespace`` parameter.

Usage::

    from cleveragents.tool.builtins.adapter import BuiltinAdapter
    from cleveragents.tool.registry import ToolRegistry

    adapter = BuiltinAdapter()
    specs = adapter.discover()        # list of all built-in ToolSpecs
    registry = ToolRegistry()
    names = adapter.register(registry) # registers and returns names
    adapter.activate()                 # no-op — built-ins are always available
    adapter.deactivate()               # no-op
"""

from __future__ import annotations

from cleveragents.tool.builtins.file_tools import ALL_FILE_TOOLS
from cleveragents.tool.builtins.git_tools import ALL_GIT_TOOLS
from cleveragents.tool.builtins.subplan_tool import ALL_SUBPLAN_TOOLS
from cleveragents.tool.registry import ToolRegistry
from cleveragents.tool.runtime import ToolSpec

__all__ = ["BuiltinAdapter"]


class BuiltinAdapter:
    """Formal adapter for built-in tools following the adapter lifecycle.

    Wraps the existing ``ALL_FILE_TOOLS``, ``ALL_GIT_TOOLS``, and
    ``ALL_SUBPLAN_TOOLS`` lists behind a unified interface.

    The lifecycle methods mirror those of
    :class:`~cleveragents.skill.loader.AgentSkillLoader`:

    - :meth:`discover` — enumerate all available built-in tool specs.
    - :meth:`register` — register all specs into a ``ToolRegistry``.
    - :meth:`activate` — no-op (built-in tools are always available).
    - :meth:`deactivate` — no-op.
    """

    def __init__(self) -> None:
        self._tools: list[ToolSpec] = []
        self._discovered: bool = False

    @property
    def is_discovered(self) -> bool:
        """Whether :meth:`discover` has been called."""
        return self._discovered

    def discover(self) -> list[ToolSpec]:
        """Discover all built-in tools.

        Returns a copy of the internal list so callers cannot mutate it.
        The discovery result is cached; subsequent calls return the same
        specs without re-scanning.

        Returns
        -------
        list[ToolSpec]
            All built-in file, git, and subplan tool specs.
        """
        if not self._discovered:
            self._tools = [*ALL_FILE_TOOLS, *ALL_GIT_TOOLS, *ALL_SUBPLAN_TOOLS]
            self._discovered = True
        return list(self._tools)

    def register(self, registry: ToolRegistry) -> list[str]:
        """Register all built-in tools in the registry.

        Calls :meth:`discover` if not already done, then registers each
        spec into *registry*.  Already-registered tools are silently
        skipped so that calling ``register()`` twice on the same registry
        is safe (idempotent).

        Parameters
        ----------
        registry:
            The ``ToolRegistry`` to register tools into.

        Returns
        -------
        list[str]
            Names of successfully registered tools.

        Raises
        ------
        ValueError
            If *registry* is ``None``.
        """
        if registry is None:
            raise ValueError("registry must not be None")
        tools = self.discover()
        registered: list[str] = []
        for spec in tools:
            if registry.get(spec.name) is not None:
                continue
            registry.register(spec)
            registered.append(spec.name)
        return registered

    def activate(self) -> None:
        """No-op for built-in tools (always available)."""

    def deactivate(self) -> None:
        """No-op for built-in tools."""
