///|
/// Transport-level errors
/// These occur at the communication layer (network, IO, etc.)
pub(all) suberror TransportError {
  /// Connection has been closed (clean shutdown)
  ConnectionClosed
  /// Failed to read from transport
  ReadError(String)
  /// Failed to write to transport
  WriteError(String)
  /// Operation timed out
  Timeout
  /// Invalid transport state (e.g., trying to send after close)
  InvalidState(String)
  /// HTTP 401 Unauthorized — includes WWW-Authenticate header info
  Unauthorized(String)
  /// HTTP 403 Forbidden — insufficient scope or permissions
  Forbidden(String)
  /// HTTP error status carrying the response body, so callers (e.g. the
  /// era probe) can inspect it for a recognized modern JSON-RPC error
  /// (UnsupportedProtocolVersion / MissingRequiredClientCapability /
  /// HeaderMismatch) before deciding on a legacy fallback.
  HttpError(Int, String)
} derive(Debug, Eq)

///|
pub impl Show for TransportError with fn to_string(self) -> String {
  match self {
    ConnectionClosed => "Connection closed"
    ReadError(msg) => "Read error: " + msg
    WriteError(msg) => "Write error: " + msg
    Timeout => "Timeout"
    InvalidState(msg) => "Invalid state: " + msg
    Unauthorized(msg) => "Unauthorized: " + msg
    Forbidden(msg) => "Forbidden: " + msg
    HttpError(status, body) =>
      "HTTP " + status.to_string() + " error, body: " + body
  }
}

///|
/// MCP protocol-level errors
/// These follow the JSON-RPC 2.0 error code conventions.
///
/// Error code allocation (per 2026-07-28 spec):
/// - `-32700`, `-32600`..`-32603`: standard JSON-RPC 2.0
/// - `-32000`..`-32019`: legacy/implementation-defined (no new allocations)
/// - `-32020`..`-32099`: reserved for the MCP specification
pub(all) suberror MCPError {
  /// Failed to parse JSON-RPC request (-32700)
  ParseError(String)
  /// Invalid JSON-RPC request structure (-32600)
  InvalidRequest(String)
  /// Method not found (-32601)
  MethodNotFound(String)
  /// Invalid method parameters (-32602).
  /// Also used for resource-not-found (was -32002 in earlier revisions).
  InvalidParams(String)
  /// Internal MCP server error (-32603)
  InternalError(String)
  /// Transport layer error (wrapped)
  TransportError(TransportError)
  /// Tool execution error (implementation-defined, -32000)
  ToolError(String)
  /// Streamable HTTP header/body mismatch (-32020, MCP-spec-defined).
  /// `data` carries detail; server returns HTTP 400.
  HeaderMismatch(String)
  /// Request needs a client capability the client did not declare
  /// (-32021, MCP-spec-defined). `required` lists the missing capabilities.
  MissingRequiredClientCapability(String, required~ : Array[String])
  /// Client requested an unsupported protocol version
  /// (-32022, MCP-spec-defined). `supported` lists the versions the server
  /// can speak; `requested` echoes what the client asked for.
  UnsupportedProtocolVersion(
    String,
    supported~ : Array[String],
    requested~ : String
  )
} derive(Debug, Eq)

///|
/// Convert MCPError to JSON-RPC error code
pub fn MCPError::to_error_code(self : MCPError) -> Int {
  match self {
    ParseError(_) => -32700
    InvalidRequest(_) => -32600
    MethodNotFound(_) => -32601
    InvalidParams(_) => -32602
    InternalError(_) => -32603
    TransportError(_) => -32603
    ToolError(_) => -32000
    HeaderMismatch(_) => -32020
    MissingRequiredClientCapability(_, ..) => -32021
    UnsupportedProtocolVersion(_, ..) => -32022
  }
}

///|
/// Get error message from MCPError
pub fn MCPError::message(self : MCPError) -> String {
  match self {
    ParseError(msg) => msg
    InvalidRequest(msg) => msg
    MethodNotFound(msg) => msg
    InvalidParams(msg) => msg
    InternalError(msg) => msg
    TransportError(te) => "Transport error: " + te.to_string()
    ToolError(msg) => msg
    HeaderMismatch(msg) => msg
    MissingRequiredClientCapability(msg, ..) => msg
    UnsupportedProtocolVersion(msg, ..) => msg
  }
}

///|
/// Serialize the structured `data` member of a JSON-RPC error response.
/// Returns `None` for errors that carry no `data` per the spec. The
/// `-3202x` MCP-spec-defined errors populate `data` with fields clients
/// use for recovery (e.g. supported versions to retry with).
pub fn MCPError::to_error_data(self : MCPError) -> Json? {
  match self {
    UnsupportedProtocolVersion(_, supported~, requested~) => {
      let versions = supported.map(fn(v) { Json::string(v) })
      Some(
        Json::object({
          "supported": Json::array(versions),
          "requested": requested,
        }),
      )
    }
    MissingRequiredClientCapability(_, required~) => {
      let caps = required.map(fn(c) { Json::string(c) })
      Some(Json::object({ "requiredCapabilities": Json::array(caps) }))
    }
    _ => None
  }
}