"""
Base Tool Interface - Defines the contract for all tools
"""
from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional, Union
from pydantic import BaseModel, Field
from enum import Enum
import logging

logger = logging.getLogger(__name__)


class ParameterType(str, Enum):
    """Supported parameter types for tools"""
    STRING = "string"
    INTEGER = "integer"
    FLOAT = "float"
    BOOLEAN = "boolean"
    DATE = "date"
    DATETIME = "datetime"
    ARRAY = "array"
    OBJECT = "object"


class ToolParameter(BaseModel):
    """Definition of a tool parameter"""
    name: str = Field(..., description="Parameter name")
    type: ParameterType = Field(..., description="Parameter type")
    description: str = Field(..., description="What this parameter does")
    required: bool = Field(default=True, description="Is this parameter required?")
    default: Optional[Any] = Field(default=None, description="Default value if not provided")
    enum: Optional[List[str]] = Field(default=None, description="Allowed values for this parameter")

    def to_json_schema(self) -> Dict[str, Any]:
        """Convert to JSON Schema format for AI model"""
        schema = {
            "type": self.type.value,
            "description": self.description,
        }
        if self.enum:
            schema["enum"] = self.enum
        if self.default is not None:
            schema["default"] = self.default
        return schema


class ToolResult(BaseModel):
    """Result returned from tool execution"""
    success: bool = Field(..., description="Whether the tool executed successfully")
    data: Optional[Any] = Field(default=None, description="The data returned by the tool")
    error: Optional[str] = Field(default=None, description="Error message if failed")
    message: Optional[str] = Field(default=None, description="Human-readable result message")

    @classmethod
    def success_result(cls, data: Any, message: str = None) -> "ToolResult":
        """Create a successful result"""
        return cls(success=True, data=data, message=message)

    @classmethod
    def error_result(cls, error: str) -> "ToolResult":
        """Create an error result"""
        return cls(success=False, error=error)


class Tool(ABC):
    """
    Base class for all tools that can be executed by the AI agent.

    Each tool represents a specific action the AI can take, such as:
    - Getting sales data
    - Creating an order
    - Looking up inventory
    - Processing a refund
    """

    @property
    @abstractmethod
    def name(self) -> str:
        """Unique identifier for this tool"""
        pass

    @property
    @abstractmethod
    def description(self) -> str:
        """Human-readable description of what this tool does"""
        pass

    @property
    @abstractmethod
    def parameters(self) -> List[ToolParameter]:
        """List of parameters this tool accepts"""
        pass

    @property
    def category(self) -> str:
        """Category for grouping tools (e.g., 'sales', 'orders', 'inventory')"""
        return "general"

    @property
    def requires_confirmation(self) -> bool:
        """Whether this tool requires user confirmation before executing (for write operations)"""
        return False

    @property
    def agent_types(self) -> List[str]:
        """Which agent types can use this tool (e.g., ['ecommerce', 'pos', 'general'])"""
        return ["general"]

    @abstractmethod
    async def execute(
        self,
        connector: Any,
        params: Dict[str, Any],
        context: Dict[str, Any]
    ) -> ToolResult:
        """
        Execute the tool action.

        Args:
            connector: The connector to the client's data source (Shopify, POS, etc.)
            params: Parameters passed by the AI
            context: Additional context (client_id, user_id, conversation_id, etc.)

        Returns:
            ToolResult with the outcome
        """
        pass

    def validate_params(self, params: Dict[str, Any]) -> Optional[str]:
        """
        Validate that all required parameters are provided.

        Returns:
            Error message if validation fails, None if valid
        """
        for param in self.parameters:
            if param.required and param.name not in params:
                if param.default is None:
                    return f"Missing required parameter: {param.name}"

            if param.name in params and param.enum:
                if params[param.name] not in param.enum:
                    return f"Invalid value for {param.name}. Must be one of: {param.enum}"

        return None

    def to_function_schema(self) -> Dict[str, Any]:
        """
        Convert this tool to OpenAI/Anthropic function calling format.

        Returns:
            Dict in the format expected by AI models for tool/function calling
        """
        properties = {}
        required = []

        for param in self.parameters:
            properties[param.name] = param.to_json_schema()
            if param.required:
                required.append(param.name)

        return {
            "name": self.name,
            "description": self.description,
            "parameters": {
                "type": "object",
                "properties": properties,
                "required": required
            }
        }

    def __repr__(self) -> str:
        return f"<Tool: {self.name}>"


class ReadOnlyTool(Tool):
    """Base class for tools that only read data (no confirmation needed)"""

    @property
    def requires_confirmation(self) -> bool:
        return False


class WriteTool(Tool):
    """Base class for tools that modify data (may need confirmation)"""

    @property
    def requires_confirmation(self) -> bool:
        return True
