"""Tool models for the Danube SDK."""

from typing import Any, Dict, List, Optional

from pydantic import BaseModel, Field


class Parameter(BaseModel):
    """A tool parameter.

    Parameters define the inputs that a tool accepts when executed.
    """

    name: str
    description: str = ""
    type: str = "string"
    location: str = "body"  # body, query, path, header
    required: bool = False
    default: Optional[Any] = None

    model_config = {"extra": "ignore"}


class Tool(BaseModel):
    """A tool that can be executed.

    Tools represent API endpoints or MCP tools that can be called
    through the Danube platform with specified parameters.
    """

    id: str
    name: str
    description: str = ""
    service_id: str = ""

    # Parameters as dict for flexibility (matches backend format)
    parameters: Dict[str, Any] = Field(default_factory=dict)

    # Pricing
    is_paid: bool = False
    price_per_call_cents: Optional[int] = 0

    # Optional metadata
    tags: List[str] = Field(default_factory=list)
    method: str = "POST"
    tips: Optional[str] = None
    metadata: Dict[str, Any] = Field(default_factory=dict)

    model_config = {"extra": "ignore"}

    def get_parameters(self) -> List[Parameter]:
        """Get parameters as typed Parameter objects.

        Returns:
            List of Parameter objects parsed from the parameters dict.
        """
        result = []
        for name, value in self.parameters.items():
            if isinstance(value, dict):
                param_data = {k: v for k, v in value.items() if k != "name"}
                result.append(Parameter(name=name, **param_data))
            else:
                result.append(Parameter(name=name))
        return result

    def get_required_parameters(self) -> List[Parameter]:
        """Get only the required parameters.

        Returns:
            List of Parameter objects that are required.
        """
        return [p for p in self.get_parameters() if p.required]

    @classmethod
    def from_api_response(cls, data: Dict[str, Any]) -> "Tool":
        """Create a Tool from API response data.

        Args:
            data: Raw API response dictionary.

        Returns:
            Tool instance.
        """
        return cls(
            id=data.get("id", ""),
            name=data.get("name", ""),
            description=data.get("description", ""),
            service_id=data.get("service_id", ""),
            parameters=data.get("parameters", {}),
            is_paid=data.get("is_paid", False),
            price_per_call_cents=data.get("price_per_call_cents", 0),
            tags=data.get("tags", []),
            method=data.get("method", "POST"),
            tips=data.get("tips"),
            metadata=data.get("metadata", {}),
        )


class ToolResult(BaseModel):
    """Result from tool execution.

    Contains the execution result or error information along with
    metadata about the execution.
    """

    success: bool
    result: Optional[Any] = None
    error: Optional[str] = None

    # Metadata
    tool_id: Optional[str] = None
    tool_name: Optional[str] = None
    duration_ms: Optional[float] = None
    request_id: Optional[str] = None

    model_config = {"extra": "ignore"}

    @property
    def content(self) -> str:
        """Get result as text content.

        Returns:
            The result as a string, or error message if failed.
        """
        if self.error:
            return self.error
        if isinstance(self.result, str):
            return self.result
        return str(self.result) if self.result is not None else ""

    @classmethod
    def from_api_response(cls, data: Dict[str, Any]) -> "ToolResult":
        """Create a ToolResult from API response data.

        Args:
            data: Raw API response dictionary.

        Returns:
            ToolResult instance.
        """
        # Handle MCP-style response format
        result_data = data.get("result", {})
        meta = data.get("_meta", {})

        # Check if it's an error response
        is_error = result_data.get("isError", False)
        content = result_data.get("content", [])

        # Extract text content
        result_text = None
        if content and isinstance(content, list):
            for item in content:
                if isinstance(item, dict) and item.get("type") == "text":
                    result_text = item.get("text", "")
                    break

        if is_error:
            return cls(
                success=False,
                error=result_text or "Unknown error",
                tool_id=meta.get("tool_id"),
                tool_name=meta.get("tool_name"),
                duration_ms=meta.get("duration_ms"),
                request_id=meta.get("request_id"),
            )

        return cls(
            success=True,
            result=result_text or data.get("result"),
            tool_id=meta.get("tool_id"),
            tool_name=meta.get("tool_name"),
            duration_ms=meta.get("duration_ms"),
            request_id=meta.get("request_id"),
        )

    @classmethod
    def from_error(cls, message: str, tool_id: Optional[str] = None) -> "ToolResult":
        """Create a ToolResult representing an error.

        Args:
            message: Error message.
            tool_id: Optional tool ID that failed.

        Returns:
            ToolResult with success=False.
        """
        return cls(success=False, error=message, tool_id=tool_id)
