"""
Boring-OS SDK data models.

Pydantic models matching the Boring-OS API schemas for type-safe
request and response handling.
"""

from datetime import datetime
from enum import Enum
from typing import Any

from pydantic import BaseModel, Field


# =============================================================================
# Enums
# =============================================================================

class ToolType(str, Enum):
    """Type of tool implementation."""
    API_BACKED = "api_backed"
    PURE_FUNCTION = "pure_function"
    COMPOSITE = "composite"


class ToolStatus(str, Enum):
    """Current status of a tool."""
    ACTIVE = "active"
    DEPRECATED = "deprecated"
    DISABLED = "disabled"


class ResultStatus(str, Enum):
    """Status of a tool execution result."""
    PENDING = "pending"
    COMPLETED = "completed"
    PARTIAL = "partial"
    ERROR = "error"


# =============================================================================
# Tool Definition Models
# =============================================================================

class ToolInstructions(BaseModel):
    """Agent guidance for using a tool."""
    summary: str | None = Field(default=None, description="Brief summary for agents")
    when_to_use: str | None = Field(default=None, description="When to use this tool")
    when_not_to_use: str | None = Field(default=None, description="When NOT to use")
    examples: list[dict[str, Any]] | None = Field(default=None, description="Example usages")


class ToolSchema(BaseModel):
    """Input/output schema definitions for a tool."""
    input: dict[str, Any] = Field(description="JSON Schema for input parameters")
    output: dict[str, Any] = Field(description="JSON Schema for output")


class DeprecationInfo(BaseModel):
    """Deprecation details for a deprecated tool."""
    deprecated_at: datetime | None = None
    replacement_tool: str | None = Field(default=None, description="Suggested replacement")
    sunset_date: datetime | None = Field(default=None, description="When tool will be disabled")
    reason: str | None = Field(default=None, description="Reason for deprecation")


class Tool(BaseModel):
    """
    Full tool definition with all metadata.
    
    Returned when fetching a specific tool's details.
    The `name` is the internal identifier, `display_name` is the human-readable label.
    """
    name: str = Field(description="Unique identifier for the tool")
    display_name: str = Field(default="", description="Human-readable display name for UI")
    version: str = Field(description="Semantic version")
    type: ToolType = Field(description="Type of tool implementation")
    description: str | None = Field(default=None, description="Human-readable description")
    status: ToolStatus = Field(default=ToolStatus.ACTIVE, description="Current status")
    adapter_id: str | None = Field(default=None, description="Adapter ID for API-backed tools")
    schema_: ToolSchema | None = Field(default=None, alias="schema", description="Input/output schema")
    instructions: ToolInstructions | None = Field(default=None, description="Agent guidance")
    deprecation_info: DeprecationInfo | None = Field(default=None, description="Deprecation details")
    
    model_config = {"populate_by_name": True}


class ToolInfo(BaseModel):
    """
    Summary tool information for listings.
    
    Returned in tool list responses with essential info only.
    """
    name: str = Field(description="Tool name")
    display_name: str = Field(default="", description="Human-readable display name for UI")
    version: str = Field(description="Tool version")
    type: ToolType = Field(description="Tool type")
    description: str | None = Field(default=None, description="Brief description")
    status: ToolStatus = Field(default=ToolStatus.ACTIVE, description="Current status")


class ToolListResponse(BaseModel):
    """Response from listing tools."""
    tools: list[ToolInfo] = Field(description="List of tools")
    total: int = Field(description="Total number of tools matching filters")


# =============================================================================
# Request/Response Models
# =============================================================================

class ExecutionOptions(BaseModel):
    """Options for tool execution requests."""
    timeout_seconds: int = Field(default=30, ge=1, le=300, description="Request timeout")
    trace_id: str | None = Field(default=None, description="Trace ID for observability")
    callback_url: str | None = Field(default=None, description="Webhook URL for results")


class ToolCallRequest(BaseModel):
    """Request to execute a tool."""
    tool_name: str = Field(description="Name of tool to execute")
    params: dict[str, Any] = Field(default_factory=dict, description="Tool parameters")
    options: ExecutionOptions | None = Field(default=None, description="Execution options")


class ErrorInfo(BaseModel):
    """Error information from a failed request."""
    code: str = Field(description="Machine-readable error code")
    message: str = Field(description="Human-readable error message")
    details: dict[str, Any] | None = Field(default=None, description="Additional context")
    retryable: bool = Field(default=False, description="Whether request can be retried")


class ToolResultMetadata(BaseModel):
    """Metadata about a tool execution."""
    tool_name: str | None = Field(default=None, description="Executed tool name")
    tool_version: str | None = Field(default=None, description="Executed tool version")
    execution_ms: int | None = Field(default=None, description="Execution time in ms")
    completed_at: datetime | None = Field(default=None, description="Completion timestamp")
    trace_id: str | None = Field(default=None, description="Trace ID")


class DeprecationWarning(BaseModel):
    """Warning about deprecated tool usage."""
    message: str = Field(description="Warning message")
    replacement_tool: str | None = Field(default=None, description="Suggested replacement")
    sunset_date: datetime | None = Field(default=None, description="When tool will be disabled")


class ToolResult(BaseModel):
    """
    Result from a tool execution.
    
    This is the primary response model for synchronous tool calls.
    """
    request_id: str = Field(description="Unique request identifier")
    status: ResultStatus = Field(description="Execution status")
    result: dict[str, Any] | None = Field(default=None, description="Tool output")
    error: ErrorInfo | None = Field(default=None, description="Error info if failed")
    metadata: ToolResultMetadata | None = Field(default=None, description="Execution metadata")
    deprecation_warning: DeprecationWarning | None = Field(
        default=None, description="Warning if tool is deprecated"
    )
    
    @property
    def success(self) -> bool:
        """Check if execution was successful."""
        return self.status in (ResultStatus.COMPLETED, ResultStatus.PARTIAL)
    
    @property
    def data(self) -> dict[str, Any]:
        """
        Get the result data.
        
        Returns:
            Tool output data
        
        Raises:
            ValueError: If result is not available (error or pending)
        """
        if self.result is None:
            if self.error:
                raise ValueError(f"Tool execution failed: {self.error.message}")
            raise ValueError("Result not available")
        return self.result


class AsyncToolResponse(BaseModel):
    """Response from async tool submission."""
    request_id: str = Field(description="Request ID for polling")
    status: ResultStatus = Field(default=ResultStatus.PENDING, description="Current status")
    poll_url: str | None = Field(default=None, description="URL to poll for results")
    estimated_completion_ms: int | None = Field(default=None, description="Estimated time to completion")


# =============================================================================
# Session Models
# =============================================================================

class SessionInfo(BaseModel):
    """Session information for grouping tool calls."""
    session_id: str = Field(description="Unique session identifier")
    metadata: dict[str, Any] = Field(default_factory=dict, description="Session metadata")
