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

from typing import Any

class ToolRegistry:
    """
    Registry for agent tools.

    Allows dynamic registration and execution of tools.
    """

    def __init__(self):
        self._tools: dict[str, Any] = {}

    def register(self, tool: Any) -> "ToolRegistry":
        """Register one tool and return self for chaining."""
        if tool is None:
            return self
        self._tools[tool.name] = tool
        return self

    def register_many(self, *tools: Any) -> "ToolRegistry":
        """Register multiple tools (None entries are ignored)."""
        for tool in tools:
            self.register(tool)
        return self

    def unregister(self, name: str) -> "ToolRegistry":
        """Unregister a tool by name and return self for chaining."""
        self._tools.pop(name, None)
        return self

    def get(self, name: str) -> Any | 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 all tool definitions when available."""
        definitions: list[dict[str, Any]] = []
        for tool in self._tools.values():
            to_schema = getattr(tool, "to_schema", None)
            if callable(to_schema):
                definitions.append(to_schema())
        return definitions

    def get_agno_tool_instances(self) -> list[Any]:
        """Return registered tool instances for agno Agent(tools=[...])."""
        return list(self._tools.values())

    async def execute(self, name: str, params: dict[str, Any]) -> str:
        """Execute a tool by name with given parameters."""
        _HINT = "\n\n[Analyze the error above and try a different approach.]"

        tool = self._tools.get(name)
        if not tool:
            return f"Error: Tool '{name}' not found. Available: {', '.join(self.tool_names)}"

        execute = getattr(tool, "execute", None)
        if not callable(execute):
            return f"Error: Tool '{name}' is not executable." + _HINT
        try:
            cast_params = getattr(tool, "cast_params", None)
            if callable(cast_params):
                params = cast_params(params)

            validate_params = getattr(tool, "validate_params", None)
            if callable(validate_params):
                errors = validate_params(params)
                if errors:
                    return f"Error: Invalid parameters for tool '{name}': " + "; ".join(errors) + _HINT

            result = await execute(**params)
            if isinstance(result, str) and result.startswith("Error"):
                return result + _HINT
            return result
        except Exception as e:
            return f"Error executing {name}: {str(e)}" + _HINT

    @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

    def __iter__(self):
        """Iterate through registered tool instances."""
        return iter(self._tools.values())
