"""Tool registry for dynamic tool management."""

from typing import Any

from nanobot.agent.tools.base import Tool


class ToolRegistry:
    """
    Registry for agent tools.
    
    Allows dynamic registration and execution of tools.
    """
    
    def __init__(self):
        self._tools: dict[str, Tool] = {}
    
    def register(self, tool: Tool) -> None:
        """Register a tool."""
        self._tools[tool.name] = tool
    
    def unregister(self, name: str) -> None:
        """Unregister a tool by name."""
        self._tools.pop(name, None)
    
    def get(self, name: str) -> Tool | None:
        """Get a tool by name."""
        return self._tools.get(name)
    
    def has(self, name: str) -> bool:
        """Check if a tool is registered."""
        return name in self._tools
    
    def get_definitions(self) -> list[dict[str, Any]]:
        """Get tool definitions for all registered tools.

        Supports both function tools (with to_schema) and native tools (with to_params).
        """
        definitions = []
        for tool in self._tools.values():
            if hasattr(tool, 'to_params'):  # Native Anthropic tool
                definitions.append(tool.to_params())
            elif hasattr(tool, 'to_schema'):  # Function tool
                definitions.append(tool.to_schema())
            else:
                raise ValueError(f"Tool {tool.name} has no schema method (to_params or to_schema)")
        return definitions
    
    async def execute(self, name: str, params: dict[str, Any]) -> Any:
        """
        Execute a tool by name with given parameters.

        Supports both native Anthropic tools (via __call__) and function tools (via execute).

        Args:
            name: Tool name.
            params: Tool parameters.

        Returns:
            Tool execution result (ToolResult, CLIResult, or string).

        Raises:
            KeyError: If tool not found.
        """
        tool = self._tools.get(name)
        if not tool:
            return f"Error: Tool '{name}' not found"

        try:
            # Duck typing - support both native and function tools
            if hasattr(tool, 'to_params'):
                # Native Anthropic tool - call directly via __call__, no validation needed
                return await tool(**params)
            else:
                # Legacy function tool - validate then execute
                errors = tool.validate_params(params)
                if errors:
                    return f"Error: Invalid parameters for tool '{name}': " + "; ".join(errors)
                return await tool.execute(**params)
        except Exception as e:
            return f"Error executing {name}: {str(e)}"
    
    def get_tools(self) -> list[Any]:
        """Get list of tool objects (not definitions).

        Returns tool objects which can be inspected for metadata like beta_flag.
        """
        return list(self._tools.values())

    @property
    def tool_names(self) -> list[str]:
        """Get list of registered tool names."""
        return list(self._tools.keys())

    def __len__(self) -> int:
        return len(self._tools)

    def __contains__(self, name: str) -> bool:
        return name in self._tools
