"""
MCP Protocol Types - Data structures for Model Context Protocol

Defines types for MCP servers, tools, resources, and prompts following
the MCP specification: https://modelcontextprotocol.io/
"""

from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Optional


class MCPTransportType(Enum):
    """Transport types for MCP communication"""

    STDIO = "stdio"
    SSE = "sse"
    HTTP = "http"


class MCPCapability(Enum):
    """MCP server capabilities"""

    TOOLS = "tools"
    RESOURCES = "resources"
    PROMPTS = "prompts"
    LOGGING = "logging"
    SAMPLING = "sampling"


@dataclass
class MCPToolParameter:
    """Parameter definition for an MCP tool"""

    name: str
    description: str
    type: str  # JSON Schema type (string, number, boolean, object, array)
    required: bool = True
    enum: Optional[list[str]] = None
    default: Optional[Any] = None


@dataclass
class MCPTool:
    """Tool provided by an MCP server"""

    name: str
    description: str
    parameters: list[MCPToolParameter] = field(default_factory=list)

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary for JSON serialization"""
        return {
            "name": self.name,
            "description": self.description,
            "inputSchema": {
                "type": "object",
                "properties": {
                    p.name: {
                        "type": p.type,
                        "description": p.description,
                        **({"enum": p.enum} if p.enum else {}),
                        **({"default": p.default} if p.default is not None else {}),
                    }
                    for p in self.parameters
                },
                "required": [p.name for p in self.parameters if p.required],
            },
        }


@dataclass
class MCPResource:
    """Resource provided by an MCP server"""

    uri: str
    name: str
    description: str
    mime_type: Optional[str] = None


@dataclass
class MCPPrompt:
    """Prompt template provided by an MCP server"""

    name: str
    description: str
    arguments: list[MCPToolParameter] = field(default_factory=list)


@dataclass
class MCPServerConfig:
    """Configuration for an MCP server"""

    name: str
    command: str  # Command to run (e.g., "npx", "python", "uvx")
    args: list[str] = field(default_factory=list)
    env: dict[str, str] = field(default_factory=dict)
    transport: MCPTransportType = MCPTransportType.STDIO
    description: str = ""
    enabled: bool = True

    # For SSE/HTTP transport
    url: Optional[str] = None

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary for JSON serialization"""
        result = {
            "name": self.name,
            "command": self.command,
            "args": self.args,
            "env": self.env,
            "transport": self.transport.value,
            "description": self.description,
            "enabled": self.enabled,
        }
        if self.url:
            result["url"] = self.url
        return result

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "MCPServerConfig":
        """Create from dictionary"""
        transport = data.get("transport", "stdio")
        if isinstance(transport, str):
            transport = MCPTransportType(transport)
        return cls(
            name=data["name"],
            command=data.get("command", ""),
            args=data.get("args", []),
            env=data.get("env", {}),
            transport=transport,
            description=data.get("description", ""),
            enabled=data.get("enabled", True),
            url=data.get("url"),
        )


@dataclass
class MCPServerInfo:
    """Information about a connected MCP server"""

    name: str
    version: str
    capabilities: list[MCPCapability] = field(default_factory=list)
    tools: list[MCPTool] = field(default_factory=list)
    resources: list[MCPResource] = field(default_factory=list)
    prompts: list[MCPPrompt] = field(default_factory=list)


@dataclass
class MCPToolResult:
    """Result from executing an MCP tool"""

    content: Any
    is_error: bool = False
    error_message: Optional[str] = None


@dataclass
class MCPMessage:
    """JSON-RPC 2.0 message for MCP protocol"""

    jsonrpc: str = "2.0"
    method: Optional[str] = None
    params: Optional[dict[str, Any]] = None
    result: Optional[Any] = None
    error: Optional[dict[str, Any]] = None
    id: Optional[int | str] = None

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary for JSON serialization"""
        msg: dict[str, Any] = {"jsonrpc": self.jsonrpc}
        if self.method is not None:
            msg["method"] = self.method
        if self.params is not None:
            msg["params"] = self.params
        if self.result is not None:
            msg["result"] = self.result
        if self.error is not None:
            msg["error"] = self.error
        if self.id is not None:
            msg["id"] = self.id
        return msg

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "MCPMessage":
        """Create from dictionary"""
        return cls(
            jsonrpc=data.get("jsonrpc", "2.0"),
            method=data.get("method"),
            params=data.get("params"),
            result=data.get("result"),
            error=data.get("error"),
            id=data.get("id"),
        )


# Standard MCP methods
class MCPMethod:
    """Standard MCP protocol methods"""

    # Initialization
    INITIALIZE = "initialize"
    INITIALIZED = "notifications/initialized"

    # Tools
    TOOLS_LIST = "tools/list"
    TOOLS_CALL = "tools/call"

    # Resources
    RESOURCES_LIST = "resources/list"
    RESOURCES_READ = "resources/read"
    RESOURCES_SUBSCRIBE = "resources/subscribe"
    RESOURCES_UNSUBSCRIBE = "resources/unsubscribe"

    # Prompts
    PROMPTS_LIST = "prompts/list"
    PROMPTS_GET = "prompts/get"

    # Logging
    LOGGING_SET_LEVEL = "logging/setLevel"

    # Sampling
    SAMPLING_CREATE_MESSAGE = "sampling/createMessage"

    # Notifications
    CANCELLED = "notifications/cancelled"
    PROGRESS = "notifications/progress"
    RESOURCES_UPDATED = "notifications/resources/updated"
    RESOURCES_LIST_CHANGED = "notifications/resources/list_changed"
    TOOLS_LIST_CHANGED = "notifications/tools/list_changed"
    PROMPTS_LIST_CHANGED = "notifications/prompts/list_changed"
