use serde::{Deserialize, Serialize};
use serde_json::Value;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JsonRpcRequest {
    pub jsonrpc: String,
    pub method: String,
    #[serde(default)]
    pub params: Value,
    pub id: Value,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JsonRpcResponse {
    pub jsonrpc: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub result: Option<Value>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub error: Option<JsonRpcError>,
    pub id: Value,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JsonRpcError {
    pub code: i64,
    pub message: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub data: Option<Value>,
}

#[derive(Debug, PartialEq)]
pub enum MethodType {
    Read,
    Write,
    Account,
}

pub fn classify_method(method: &str) -> MethodType {
    match method {
        // Write/signing methods — intercept and route to frontend
        "eth_sendTransaction"
        | "eth_signTransaction"
        | "personal_sign"
        | "eth_sign"
        | "eth_signTypedData"
        | "eth_signTypedData_v3"
        | "eth_signTypedData_v4" => MethodType::Write,

        // Account methods — return connected wallet from frontend
        "eth_accounts" | "eth_requestAccounts" => MethodType::Account,

        // Everything else — passthrough to upstream RPC
        _ => MethodType::Read,
    }
}

impl JsonRpcResponse {
    pub fn error(id: Value, code: i64, message: impl Into<String>) -> Self {
        Self {
            jsonrpc: "2.0".into(),
            result: None,
            error: Some(JsonRpcError {
                code,
                message: message.into(),
                data: None,
            }),
            id,
        }
    }

    pub fn success(id: Value, result: Value) -> Self {
        Self {
            jsonrpc: "2.0".into(),
            result: Some(result),
            error: None,
            id,
        }
    }
}
