use serde_json::{Value, json};

pub const CURRENT_PROTOCOL_VERSION: &str = "2025-11-25";
pub const DEFAULT_PROTOCOL_VERSION: &str = "2025-03-26";
pub const SUPPORTED_PROTOCOL_VERSIONS: &[&str] = &[
    DEFAULT_PROTOCOL_VERSION,
    "2025-06-18",
    CURRENT_PROTOCOL_VERSION,
];

pub fn request_id(message: &Value) -> Value {
    message.get("id").cloned().unwrap_or(Value::Null)
}

pub fn method_name(message: &Value) -> Option<&str> {
    message.get("method").and_then(Value::as_str)
}

pub fn params(message: &Value) -> Value {
    message
        .get("params")
        .cloned()
        .unwrap_or_else(|| Value::Object(Default::default()))
}

pub fn is_notification(message: &Value) -> bool {
    method_name(message).is_some() && message.get("id").is_none()
}

pub fn is_request(message: &Value) -> bool {
    method_name(message).is_some() && message.get("id").is_some()
}

pub fn is_response(message: &Value) -> bool {
    method_name(message).is_none()
        && (message.get("result").is_some() || message.get("error").is_some())
}

pub fn jsonrpc_result(id: Value, result: Value) -> Value {
    json!({
        "jsonrpc": "2.0",
        "id": id,
        "result": result
    })
}

pub fn jsonrpc_error(id: Value, code: i64, message: impl Into<String>) -> Value {
    json!({
        "jsonrpc": "2.0",
        "id": id,
        "error": {
            "code": code,
            "message": message.into()
        }
    })
}

pub fn negotiated_protocol_version(requested: &str) -> Option<&'static str> {
    SUPPORTED_PROTOCOL_VERSIONS
        .iter()
        .copied()
        .find(|version| *version == requested)
}
