"""
Base class for all agent-compatible tools.
Defines the common interface and shared functionality for different tools.
"""

from loguru import logger
from abc import ABC, abstractmethod
from typing import Any, Dict


# Safe type mapping for parameter validation (prevents eval() RCE)
TYPE_MAP = {
    "str": str,
    "int": int,
    "float": float,
    "bool": bool,
    "list": list,
    "dict": dict,
    "tuple": tuple,
    "set": set,
}


class BaseTool(ABC):
    """Abstract base class for all agent-compatible tools."""

    def __init__(self, name: str, description: str):
        """
        Initialize the tool.

        Args:
            name: The name of the tool
            description: A description of what the tool does
        """
        self.name = name
        self.description = description
        self.parameters: Dict[str, Dict[str, Any]] = {}

    @abstractmethod
    def execute(self, **kwargs) -> Any:
        """
        Execute the tool with the given parameters.

        Args:
            **kwargs: Tool-specific parameters

        Returns:
            Any: The result of the tool execution
        """
        pass

    def get_schema(self) -> Dict[str, Any]:
        """
        Get the JSON schema for the tool's parameters.

        Returns:
            Dict[str, Any]: The JSON schema
        """
        return {
            "name": self.name,
            "description": self.description,
            "parameters": self.parameters,
        }

    def validate_parameters(self, **kwargs) -> bool:
        """
        Validate the provided parameters against the tool's schema.

        Args:
            **kwargs: Parameters to validate

        Returns:
            bool: True if parameters are valid, False otherwise
        """
        for param_name, param_schema in self.parameters.items():
            if param_name not in kwargs:
                if param_schema.get("required", False):
                    logger.error(f"Missing required parameter: {param_name}")
                    return False
                continue

            param_value = kwargs[param_name]
            param_type = param_schema.get("type")

            # Use safe type mapping instead of eval() to prevent RCE
            if param_type:
                expected_type = TYPE_MAP.get(param_type)
                if expected_type and not isinstance(param_value, expected_type):
                    logger.error(
                        f"Invalid type for parameter {param_name}: "
                        f"expected {param_type}, got {type(param_value).__name__}"
                    )
                    return False

            if (
                "enum" in param_schema
                and param_value not in param_schema["enum"]
            ):
                logger.error(f"Invalid value for parameter {param_name}")
                return False

        return True

    def _log_execution(self, **kwargs) -> None:
        """
        Log tool execution details.

        Args:
            **kwargs: Parameters used in execution
        """
        # Don't log kwargs directly as it may contain sensitive data
        logger.info(f"Executing tool {self.name} with {len(kwargs)} parameters")

    def _log_result(self, result: Any) -> None:
        """
        Log tool execution result.

        Args:
            result: The result of the tool execution
        """
        logger.info(
            f"Tool {self.name} execution completed with result: {result}"
        )
