from __future__ import annotations

"""Shared SDK error types."""


class ProviderError(Exception):
    """Base class for LLM provider failures."""

    @classmethod
    def missing_api_key(cls, env_var: str) -> "ProviderError":
        return cls(f"Missing API key - set {env_var}")

    @classmethod
    def http(cls, message: str) -> "ProviderError":
        return cls(f"HTTP request failed: {message}")

    @classmethod
    def api(cls, status: int, message: str) -> "ProviderError":
        return cls(f"API error {status}: {message}")

    @classmethod
    def parse(cls, message: str) -> "ProviderError":
        return cls(f"Response parsing failed: {message}")

    @classmethod
    def rate_limited(cls, retry_after_secs: int) -> "ProviderError":
        return cls(f"Rate limited - retry after {retry_after_secs}s")

    @classmethod
    def context_window_exceeded(cls) -> "ProviderError":
        return cls("Context window exceeded")

    @classmethod
    def invalid_response(cls, message: str) -> "ProviderError":
        return cls(f"Invalid provider response: {message}")

    @classmethod
    def unsupported(cls, feature: str) -> "ProviderError":
        return cls(f"Unsupported provider feature: {feature}")


class ToolError(Exception):
    """Errors produced by tool execution."""

    @classmethod
    def invalid_input(cls, message: str) -> "ToolError":
        return cls(f"Invalid tool input: {message}")

    @classmethod
    def execution(cls, message: str) -> "ToolError":
        return cls(f"Tool execution failed: {message}")

    @classmethod
    def timeout(cls) -> "ToolError":
        return cls("Tool execution timed out")

    @classmethod
    def permission_denied(cls, message: str) -> "ToolError":
        return cls(f"Permission denied: {message}")


class MemoryError(Exception):
    """Errors produced by memory backends."""

    @classmethod
    def backend(cls, message: str) -> "MemoryError":
        return cls(f"Memory backend failed: {message}")

    @classmethod
    def serialization(cls, message: str) -> "MemoryError":
        return cls(f"Memory serialization failed: {message}")


class McpError(Exception):
    """Errors produced by MCP clients or adapters."""

    @classmethod
    def invalid_command(cls) -> "McpError":
        return cls("Invalid MCP command")

    @classmethod
    def spawn_failed(cls, message: str) -> "McpError":
        return cls(f"Failed to spawn MCP server: {message}")

    @classmethod
    def protocol(cls, message: str) -> "McpError":
        return cls(f"MCP protocol error: {message}")

    @classmethod
    def response(cls, message: str) -> "McpError":
        return cls(f"MCP response error: {message}")

    @classmethod
    def timeout(cls) -> "McpError":
        return cls("MCP request timed out")


class AgentError(Exception):
    """Top-level SDK error."""

    @classmethod
    def provider(cls, error: Exception) -> "AgentError":
        return cls(f"LLM provider error: {error}")

    @classmethod
    def tool_error(cls, error: Exception) -> "AgentError":
        return cls(f"Tool error: {error}")

    @classmethod
    def tool_failure(cls, name: str, source: Exception) -> "AgentError":
        return cls(f"Tool execution failed '{name}': {source}")

    @classmethod
    def mcp(cls, error: Exception) -> "AgentError":
        return cls(f"MCP error: {error}")

    @classmethod
    def memory(cls, error: Exception) -> "AgentError":
        return cls(f"Memory error: {error}")

    @classmethod
    def max_steps_reached(cls, steps: int) -> "AgentError":
        return cls(f"Max steps reached: {steps}")

    @classmethod
    def missing_field(cls, field: str) -> "AgentError":
        return cls(f"Missing required field: {field}")

    @classmethod
    def no_llm_provider(cls) -> "AgentError":
        return cls("No LLM provider configured")

    @classmethod
    def tool_not_found(cls, name: str) -> "AgentError":
        return cls(f"Tool not found: {name}")

    @classmethod
    def agent_not_found(cls, name: str) -> "AgentError":
        return cls(f"Agent not found: {name}")

    @classmethod
    def invalid_configuration(cls, message: str) -> "AgentError":
        return cls(f"Invalid configuration: {message}")

    @classmethod
    def invalid_stream(cls) -> "AgentError":
        return cls("Invalid stream payload")

    @classmethod
    def context_window_exceeded(cls) -> "AgentError":
        return cls("Context window exceeded")
