use serde_json::json;
use thiserror::Error;

#[derive(Debug, Error)]
pub enum McpError {
    #[error("Invalid JSON-RPC: {0}")]
    InvalidJson(String),

    #[error("Method not found: {0}")]
    MethodNotFound(String),

    #[error("Invalid parameters for {method}: {reason}")]
    InvalidParams { method: String, reason: String },

    #[error("Backend API error: {status} - {message}")]
    BackendError { status: u16, message: String },

    #[error("Tool invocation failed: {0}")]
    ToolError(String),

    #[error("IO error: {0}")]
    IoError(#[from] std::io::Error),

    #[error("Serialization error: {0}")]
    SerdeError(#[from] serde_json::error::Error),

    #[error("HTTP error: {0}")]
    HttpError(#[from] reqwest::Error),
}

impl McpError {
    pub fn to_json_rpc_error(&self) -> serde_json::Value {
        let (code, message) = match self {
            McpError::InvalidJson(_) => (-32700, "Parse error".to_string()),
            McpError::MethodNotFound(m) => (-32601, format!("Method not found: {}", m)),
            McpError::InvalidParams { .. } => (-32602, "Invalid params".to_string()),
            McpError::BackendError { .. } => (-32000, "Server error".to_string()),
            McpError::ToolError(e) => (-32000, e.clone()),
            _ => (-32603, "Internal error".to_string()),
        };

        json!({
            "jsonrpc": "2.0",
            "error": {
                "code": code,
                "message": message,
                "data": { "details": self.to_string() }
            }
        })
    }
}

pub type Result<T> = std::result::Result<T, McpError>;
