//! Core JSON-RPC 2.0 and MCP protocol types
//!
//! Extracted from crimson/dictator implementations and enhanced with patterns
//! from the Go mcphost implementation.

use std::fmt;
use std::hash::{Hash, Hasher};

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

// =============================================================================
// REQUEST ID - Hashable JSON-RPC request identifier
// =============================================================================

/// A JSON-RPC request identifier.
///
/// Per the JSON-RPC 2.0 spec, this can be a number, string, or null.
/// This type wraps `serde_json::Value` but restricts to number/string
/// and implements `Hash + Eq` for use as HashMap keys.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RequestId {
    /// Numeric ID
    Number(i64),
    /// String ID
    String(std::string::String),
}

impl RequestId {
    /// Create a numeric request ID
    pub fn number(n: i64) -> Self {
        Self::Number(n)
    }

    /// Create a string request ID
    pub fn string(s: impl Into<std::string::String>) -> Self {
        Self::String(s.into())
    }

    /// Convert to a `serde_json::Value`
    pub fn to_value(&self) -> Value {
        match self {
            Self::Number(n) => Value::Number((*n).into()),
            Self::String(s) => Value::String(s.clone()),
        }
    }

    /// Try to convert from a `serde_json::Value`
    pub fn from_value(v: &Value) -> Option<Self> {
        match v {
            Value::Number(n) => n.as_i64().map(Self::Number),
            Value::String(s) => Some(Self::String(s.clone())),
            _ => None,
        }
    }
}

impl PartialEq for RequestId {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (Self::Number(a), Self::Number(b)) => a == b,
            (Self::String(a), Self::String(b)) => a == b,
            _ => false,
        }
    }
}

impl Eq for RequestId {}

impl Hash for RequestId {
    fn hash<H: Hasher>(&self, state: &mut H) {
        std::mem::discriminant(self).hash(state);
        match self {
            Self::Number(n) => n.hash(state),
            Self::String(s) => s.hash(state),
        }
    }
}

impl fmt::Display for RequestId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Number(n) => write!(f, "{n}"),
            Self::String(s) => write!(f, "{s}"),
        }
    }
}

impl From<i64> for RequestId {
    fn from(n: i64) -> Self {
        Self::Number(n)
    }
}

impl From<std::string::String> for RequestId {
    fn from(s: std::string::String) -> Self {
        Self::String(s)
    }
}

impl From<&str> for RequestId {
    fn from(s: &str) -> Self {
        Self::String(s.to_string())
    }
}

// =============================================================================
// JSON-RPC MESSAGE - Wire-format deserializable enum
// =============================================================================

/// A JSON-RPC 2.0 message as received on the wire.
///
/// Distinguishes between requests (has `method` + `id`), notifications
/// (has `method`, no `id`), and responses (has `result` or `error` + `id`).
#[derive(Debug, Clone, Serialize)]
#[serde(untagged)]
pub enum JsonRpcMessage {
    /// A request with an ID expecting a response
    Request(JsonRpcRequest),
    /// A notification (request with no ID)
    Notification(JsonRpcRequest),
    /// A response to a previous request
    Response(JsonRpcResponse),
}

impl<'de> Deserialize<'de> for JsonRpcMessage {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let raw: Value = Value::deserialize(deserializer)?;

        let obj = raw
            .as_object()
            .ok_or_else(|| serde::de::Error::custom("JSON-RPC message must be an object"))?;

        if obj.contains_key("method") {
            // Request or notification — distinguished by presence of `id`
            let request: JsonRpcRequest = serde_json::from_value(raw)
                .map_err(|e| serde::de::Error::custom(format!("invalid request: {e}")))?;
            if request.id.is_some() {
                Ok(JsonRpcMessage::Request(request))
            } else {
                Ok(JsonRpcMessage::Notification(request))
            }
        } else if obj.contains_key("result") || obj.contains_key("error") {
            let response: JsonRpcResponse = serde_json::from_value(raw)
                .map_err(|e| serde::de::Error::custom(format!("invalid response: {e}")))?;
            Ok(JsonRpcMessage::Response(response))
        } else {
            Err(serde::de::Error::custom(
                "JSON-RPC message must have 'method' (request/notification) or 'result'/'error' (response)",
            ))
        }
    }
}

impl JsonRpcMessage {
    /// Returns the request ID if this is a request or response (not a notification)
    pub fn id(&self) -> Option<&Value> {
        match self {
            Self::Request(r) => r.id.as_ref(),
            Self::Response(r) => Some(&r.id),
            Self::Notification(_) => None,
        }
    }

    /// Returns the method name if this is a request or notification
    pub fn method(&self) -> Option<&str> {
        match self {
            Self::Request(r) | Self::Notification(r) => Some(&r.method),
            Self::Response(_) => None,
        }
    }
}

/// JSON-RPC 2.0 request
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct JsonRpcRequest {
    /// JSON-RPC version (always "2.0")
    pub jsonrpc: String,
    /// Request ID (null for notifications)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<Value>,
    /// Method name
    pub method: String,
    /// Method parameters
    #[serde(skip_serializing_if = "Option::is_none")]
    pub params: Option<Value>,
}

impl JsonRpcRequest {
    /// Create a new request with ID
    pub fn new(id: Value, method: impl Into<String>, params: Option<Value>) -> Self {
        Self {
            jsonrpc: "2.0".to_string(),
            id: Some(id),
            method: method.into(),
            params,
        }
    }

    /// Create a notification (no ID)
    pub fn notification(method: impl Into<String>, params: Option<Value>) -> Self {
        Self {
            jsonrpc: "2.0".to_string(),
            id: None,
            method: method.into(),
            params,
        }
    }

    /// Check if this is a notification
    pub fn is_notification(&self) -> bool {
        self.id.is_none()
    }
}

/// JSON-RPC 2.0 response
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JsonRpcResponse {
    /// JSON-RPC version (always "2.0")
    pub jsonrpc: String,
    /// Request ID
    pub id: Value,
    /// Successful result
    #[serde(skip_serializing_if = "Option::is_none")]
    pub result: Option<Value>,
    /// Error object
    #[serde(skip_serializing_if = "Option::is_none")]
    pub error: Option<JsonRpcError>,
}

impl JsonRpcResponse {
    /// Create a successful response
    pub fn success(id: Value, result: Value) -> Self {
        Self {
            jsonrpc: "2.0".to_string(),
            id,
            result: Some(result),
            error: None,
        }
    }

    /// Create an error response
    pub fn error(id: Value, error: JsonRpcError) -> Self {
        Self {
            jsonrpc: "2.0".to_string(),
            id,
            result: None,
            error: Some(error),
        }
    }
}

/// JSON-RPC 2.0 error object
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct JsonRpcError {
    /// Error code
    pub code: i32,
    /// Error message
    pub message: String,
    /// Additional error data
    #[serde(skip_serializing_if = "Option::is_none")]
    pub data: Option<Value>,
}

/// Standard JSON-RPC 2.0 error codes
pub struct ErrorCode;

impl ErrorCode {
    /// Parse error (-32700)
    pub const PARSE_ERROR: i32 = -32700;
    /// Invalid request (-32600)
    pub const INVALID_REQUEST: i32 = -32600;
    /// Method not found (-32601)
    pub const METHOD_NOT_FOUND: i32 = -32601;
    /// Invalid params (-32602)
    pub const INVALID_PARAMS: i32 = -32602;
    /// Internal error (-32603)
    pub const INTERNAL_ERROR: i32 = -32603;
}

impl JsonRpcError {
    /// Create a new error
    pub fn new(code: i32, message: impl Into<String>) -> Self {
        Self {
            code,
            message: message.into(),
            data: None,
        }
    }

    /// Create a new error with additional data
    pub fn new_with_data(code: i32, message: impl Into<String>, data: Value) -> Self {
        Self {
            code,
            message: message.into(),
            data: Some(data),
        }
    }

    /// Add additional data to the error
    pub fn with_data(mut self, data: Value) -> Self {
        self.data = Some(data);
        self
    }

    /// Parse error (-32700)
    pub fn parse_error(message: impl Into<String>) -> Self {
        Self::new(ErrorCode::PARSE_ERROR, message)
    }

    /// Invalid request (-32600)
    pub fn invalid_request(message: impl Into<String>) -> Self {
        Self::new(ErrorCode::INVALID_REQUEST, message)
    }

    /// Method not found (-32601)
    pub fn method_not_found(message: impl Into<String>) -> Self {
        Self::new(ErrorCode::METHOD_NOT_FOUND, message)
    }

    /// Invalid params (-32602)
    pub fn invalid_params(message: impl Into<String>) -> Self {
        Self::new(ErrorCode::INVALID_PARAMS, message)
    }

    /// Internal error (-32603)
    pub fn internal_error(message: impl Into<String>) -> Self {
        Self::new(ErrorCode::INTERNAL_ERROR, message)
    }
}

/// Server/Client implementation information
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Implementation {
    /// Implementation name
    pub name: String,
    /// Implementation version
    pub version: String,
    /// Human-readable title for display
    #[serde(skip_serializing_if = "Option::is_none")]
    pub title: Option<String>,
    /// Description of the implementation
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    /// Icon URLs or data
    #[serde(skip_serializing_if = "Option::is_none")]
    pub icons: Option<Value>,
    /// Website URL
    #[serde(skip_serializing_if = "Option::is_none")]
    pub website_url: Option<String>,
}

impl Implementation {
    /// Create new implementation info (name + version only)
    pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            version: version.into(),
            title: None,
            description: None,
            icons: None,
            website_url: None,
        }
    }

    /// Set human-readable title
    pub fn with_title(mut self, title: impl Into<String>) -> Self {
        self.title = Some(title.into());
        self
    }

    /// Set description
    pub fn with_description(mut self, description: impl Into<String>) -> Self {
        self.description = Some(description.into());
        self
    }

    /// Set icons
    pub fn with_icons(mut self, icons: Value) -> Self {
        self.icons = Some(icons);
        self
    }

    /// Set website URL
    pub fn with_website_url(mut self, url: impl Into<String>) -> Self {
        self.website_url = Some(url.into());
        self
    }
}

/// Client information with version validation
#[derive(Debug, Clone, Default)]
pub struct ClientInfo {
    /// Client name
    pub name: String,
    /// Client version
    pub version: String,
}

impl ClientInfo {
    /// Create new client info
    pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            version: version.into(),
        }
    }

    /// Check if client version meets minimum requirements
    ///
    /// Uses the configurable MIN_CLIENT_VERSIONS from version module
    pub fn is_supported(&self, min_versions: &[(&str, &str)]) -> bool {
        for (name, min_version) in min_versions {
            if self.name == *name {
                return version_gte(&self.version, min_version);
            }
        }
        // Unknown clients are allowed by default
        true
    }
}

/// Compare semantic versions (simple: major.minor.patch)
///
/// Returns true if version >= min
pub fn version_gte(version: &str, min: &str) -> bool {
    let parse = |v: &str| -> (u32, u32, u32) {
        let parts: Vec<u32> = v.split('.').filter_map(|p| p.parse().ok()).collect();
        (
            parts.first().copied().unwrap_or(0),
            parts.get(1).copied().unwrap_or(0),
            parts.get(2).copied().unwrap_or(0),
        )
    };

    let (v_maj, v_min, v_patch) = parse(version);
    let (m_maj, m_min, m_patch) = parse(min);

    (v_maj, v_min, v_patch) >= (m_maj, m_min, m_patch)
}

// =============================================================================
// ROOTS - Client Context Management
// =============================================================================

/// Represents a root URI provided by the client
///
/// Roots are top-level directories or resources that the client wants
/// the server to be aware of for context.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct Root {
    /// URI of the root (e.g., file:// or other protocol)
    pub uri: String,
    /// Optional human-readable name for the root
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
}

/// Result of listing roots
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListRootsResult {
    /// List of roots provided by the client
    pub roots: Vec<Root>,
}

/// Notification that the client's root list has changed
///
/// Servers should re-request the roots list when receiving this
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RootsListChangedNotification {}

// =============================================================================
// SAMPLING - LLM Message Creation
// =============================================================================

/// Role in a conversation
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Role {
    /// User message
    User,
    /// Assistant message
    Assistant,
}

/// A message in a sampling conversation
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SamplingMessage {
    /// Role of the message sender
    pub role: Role,
    /// Message content (reuses Content from content module)
    pub content: Value, // Will be Content type from content module
}

/// Specifies how much context should be included in sampling requests
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ContextInclusion {
    /// No context
    None,
    /// Context from this server only
    ThisServer,
    /// Context from all connected servers
    AllServers,
}

/// Model hint for LLM selection
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ModelHint {
    /// Preferred model name (e.g., "claude-3-sonnet", "gpt-4")
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
}

/// Model selection preferences
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ModelPreferences {
    /// Model name hints
    #[serde(skip_serializing_if = "Option::is_none")]
    pub hints: Option<Vec<ModelHint>>,
    /// Cost priority (0.0-1.0, higher means prefer cheaper models)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cost_priority: Option<f64>,
    /// Speed priority (0.0-1.0, higher means prefer faster models)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub speed_priority: Option<f64>,
    /// Intelligence priority (0.0-1.0, higher means prefer smarter models)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub intelligence_priority: Option<f64>,
}

/// Request to create an LLM message/completion
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateMessageRequest {
    /// Conversation history
    pub messages: Vec<SamplingMessage>,
    /// Model selection preferences
    #[serde(skip_serializing_if = "Option::is_none")]
    pub model_preferences: Option<ModelPreferences>,
    /// System prompt to use
    #[serde(skip_serializing_if = "Option::is_none")]
    pub system_prompt: Option<String>,
    /// How much context to include
    #[serde(skip_serializing_if = "Option::is_none")]
    pub include_context: Option<ContextInclusion>,
    /// Temperature (0.0-1.0+)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub temperature: Option<f64>,
    /// Maximum tokens to generate
    pub max_tokens: u32,
    /// Stop sequences
    #[serde(skip_serializing_if = "Option::is_none")]
    pub stop_sequences: Option<Vec<String>>,
    /// Additional metadata
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<Value>,
}

/// Result of creating an LLM message
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateMessageResult {
    /// Generated message
    pub message: SamplingMessage,
    /// Model used for generation
    pub model: String,
    /// Why generation stopped
    #[serde(skip_serializing_if = "Option::is_none")]
    pub stop_reason: Option<String>, // "endTurn", "stopSequence", "maxTokens"
}

impl CreateMessageResult {
    /// Stop reason: natural end of turn
    pub const STOP_REASON_END_TURN: &'static str = "endTurn";
    /// Stop reason: hit a stop sequence
    pub const STOP_REASON_STOP_SEQUENCE: &'static str = "stopSequence";
    /// Stop reason: reached max tokens
    pub const STOP_REASON_MAX_TOKENS: &'static str = "maxTokens";
}

// =============================================================================
// ELICITATION - Structured User Input
// =============================================================================

/// Action taken by user in response to elicitation
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ElicitationAction {
    /// User approved and provided data
    Accept,
    /// User explicitly declined
    Decline,
    /// User dismissed without decision
    Cancel,
}

/// Request to elicit structured input from user
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateElicitationRequest {
    /// Message to show user
    pub message: String,
    /// Schema for requested data (imported from elicitation module)
    pub requested_schema: Value, // Will be ElicitationSchema
}

/// Result of elicitation request
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateElicitationResult {
    /// User's action
    pub action: ElicitationAction,
    /// User-provided content (only present if action is Accept)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub content: Option<Value>,
}

// ============================================================================
// Tasks
// ============================================================================

/// Task status in lifecycle
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[serde(rename_all = "snake_case")]
pub enum TaskStatus {
    /// The request is currently being processed
    Working,
    /// The task is waiting for input (e.g., elicitation or sampling)
    InputRequired,
    /// The request completed successfully and results are available
    Completed,
    /// The associated request did not complete successfully
    Failed,
    /// The request was cancelled before completion
    Cancelled,
}

/// Metadata for augmenting a request with task execution
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TaskMetadata {
    /// Requested duration in milliseconds to retain task from creation
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ttl: Option<u64>,
}

/// Data associated with a task
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Task {
    /// The task identifier
    pub task_id: String,
    /// Current task state
    pub status: TaskStatus,
    /// Optional human-readable message describing the current task state
    #[serde(skip_serializing_if = "Option::is_none")]
    pub status_message: Option<String>,
    /// ISO 8601 timestamp when the task was created
    pub created_at: String,
    /// ISO 8601 timestamp when the task was last updated
    pub last_updated_at: String,
    /// Actual retention duration from creation in milliseconds, null for unlimited
    pub ttl: Option<u64>,
    /// Suggested polling interval in milliseconds
    #[serde(skip_serializing_if = "Option::is_none")]
    pub poll_interval: Option<u64>,
}

/// A response to a task-augmented request
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateTaskResult {
    /// The created task
    pub task: Task,
}

/// Request params for tasks/get
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetTaskParams {
    /// The task identifier to query
    pub task_id: String,
}

/// Request params for tasks/cancel
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CancelTaskParams {
    /// The task identifier to cancel
    pub task_id: String,
}

/// Tool execution metadata
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ToolExecution {
    /// Indicates whether this tool supports task-augmented execution
    #[serde(skip_serializing_if = "Option::is_none")]
    pub task_support: Option<TaskSupport>,
}

/// Task support level for a tool
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum TaskSupport {
    /// Tool does not support task-augmented execution (default when absent)
    Forbidden,
    /// Tool may support task-augmented execution
    Optional,
    /// Tool requires task-augmented execution
    Required,
}

/// Tool annotations (hints for LLMs about tool behavior)
///
/// NOTE: All properties are **hints**. They are not guaranteed to provide
/// a faithful description of tool behavior. Clients should never make
/// tool use decisions based on annotations from untrusted servers.
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ToolAnnotations {
    /// Human-readable title for the tool
    #[serde(skip_serializing_if = "Option::is_none")]
    pub title: Option<String>,

    /// If true, the tool does not modify its environment.
    /// Default: false
    #[serde(skip_serializing_if = "Option::is_none")]
    pub read_only_hint: Option<bool>,

    /// If true, the tool may perform destructive updates to its environment.
    /// If false, the tool performs only additive updates.
    /// (Only meaningful when readOnlyHint is false)
    /// Default: true
    #[serde(skip_serializing_if = "Option::is_none")]
    pub destructive_hint: Option<bool>,

    /// If true, calling the tool repeatedly with the same arguments
    /// will have no additional effect on its environment.
    /// (Only meaningful when readOnlyHint is false)
    /// Default: false
    #[serde(skip_serializing_if = "Option::is_none")]
    pub idempotent_hint: Option<bool>,

    /// If true, this tool may interact with an "open world" of external
    /// entities. If false, the tool's domain of interaction is closed.
    /// Default: true
    #[serde(skip_serializing_if = "Option::is_none")]
    pub open_world_hint: Option<bool>,
}

// ============================================================================
// Completion Types (completion/complete)
// ============================================================================

/// Reference to what is being completed
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum CompletionRef {
    /// Completing a prompt argument
    #[serde(rename = "ref/prompt")]
    Prompt {
        /// Name of the prompt
        name: String,
    },
    /// Completing a resource URI
    #[serde(rename = "ref/resource")]
    Resource {
        /// URI of the resource
        uri: String,
    },
}

/// Argument being completed
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CompletionArgument {
    /// Name of the argument being completed
    pub name: String,
    /// Current value of the argument (partial input)
    pub value: String,
}

/// Request for completion suggestions
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CompleteRequest {
    /// Reference to what is being completed
    #[serde(rename = "ref")]
    pub reference: CompletionRef,
    /// The argument being completed
    pub argument: CompletionArgument,
}

/// A single completion suggestion
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CompletionValue {
    /// The completion value
    pub value: String,
    /// Optional display label (if different from value)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub label: Option<String>,
    /// Optional description
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
}

impl CompletionValue {
    /// Create a simple completion value
    pub fn new(value: impl Into<String>) -> Self {
        Self {
            value: value.into(),
            label: None,
            description: None,
        }
    }

    /// Create a completion value with label
    pub fn with_label(value: impl Into<String>, label: impl Into<String>) -> Self {
        Self {
            value: value.into(),
            label: Some(label.into()),
            description: None,
        }
    }

    /// Create a completion value with description
    pub fn with_description(value: impl Into<String>, description: impl Into<String>) -> Self {
        Self {
            value: value.into(),
            label: None,
            description: Some(description.into()),
        }
    }

    /// Create a fully specified completion value
    pub fn full(
        value: impl Into<String>,
        label: impl Into<String>,
        description: impl Into<String>,
    ) -> Self {
        Self {
            value: value.into(),
            label: Some(label.into()),
            description: Some(description.into()),
        }
    }
}

/// Completion result containing suggestions
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CompleteResult {
    /// Completion suggestions
    pub completion: CompletionInfo,
}

/// Information about completion suggestions
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CompletionInfo {
    /// List of completion values
    pub values: Vec<CompletionValue>,
    /// Total number of completions available (may be more than returned)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub total: Option<usize>,
    /// Whether there are more completions available
    #[serde(skip_serializing_if = "Option::is_none")]
    pub has_more: Option<bool>,
}

impl CompletionInfo {
    /// Create empty completion info
    pub fn empty() -> Self {
        Self {
            values: vec![],
            total: None,
            has_more: None,
        }
    }

    /// Create completion info with values
    pub fn with_values(values: Vec<CompletionValue>) -> Self {
        Self {
            values,
            total: None,
            has_more: None,
        }
    }

    /// Create completion info with pagination metadata
    pub fn with_pagination(values: Vec<CompletionValue>, total: usize, has_more: bool) -> Self {
        Self {
            values,
            total: Some(total),
            has_more: Some(has_more),
        }
    }
}

// ============================================================================
// Logging Types
// ============================================================================

/// Request to set the minimum logging level
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SetLevelRequest {
    /// Minimum log level to receive (debug, info, notice, warning, error, critical, alert, emergency)
    pub level: String,
}

// =============================================================================
// TOOL CALL TYPES - Request/Response for tools/call
// =============================================================================

/// Parameters for a `tools/call` request
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CallToolRequestParams {
    /// Name of the tool to call
    pub name: String,
    /// Tool arguments
    #[serde(skip_serializing_if = "Option::is_none")]
    pub arguments: Option<serde_json::Map<String, Value>>,
    /// Request metadata
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Value>,
}

/// Result of a `tools/call` request
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CallToolResult {
    /// Content items returned by the tool
    pub content: Vec<ContentItem>,
    /// Whether this result represents an error
    #[serde(skip_serializing_if = "Option::is_none")]
    pub is_error: Option<bool>,
    /// Structured content for machine consumption
    #[serde(skip_serializing_if = "Option::is_none")]
    pub structured_content: Option<Value>,
    /// Response metadata
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Value>,
}

impl CallToolResult {
    /// Create a successful text result
    pub fn text(s: impl Into<String>) -> Self {
        Self {
            content: vec![ContentItem::text(s)],
            is_error: None,
            structured_content: None,
            meta: None,
        }
    }

    /// Create an error text result
    pub fn error(s: impl Into<String>) -> Self {
        Self {
            content: vec![ContentItem::text(s)],
            is_error: Some(true),
            structured_content: None,
            meta: None,
        }
    }
}

/// Result of a `tools/list` request
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ListToolsResult {
    /// Available tools
    pub tools: Vec<Value>,
    /// Cursor for pagination
    #[serde(skip_serializing_if = "Option::is_none")]
    pub next_cursor: Option<String>,
    /// Response metadata
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<Value>,
}

// =============================================================================
// CONTENT ITEM - Serializable tagged enum for wire content
// =============================================================================

/// A content item in tool results and messages.
///
/// Tagged by `type` field for JSON serialization. This is the wire-format
/// counterpart to the `Content` trait used in the registry.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum ContentItem {
    /// Text content
    #[serde(rename = "text")]
    Text {
        /// The text value
        text: String,
    },
    /// Image content (base64-encoded)
    #[serde(rename = "image")]
    Image {
        /// Base64-encoded image data
        data: String,
        /// MIME type
        #[serde(rename = "mimeType")]
        mime_type: String,
    },
    /// Audio content (base64-encoded)
    #[serde(rename = "audio")]
    Audio {
        /// Base64-encoded audio data
        data: String,
        /// MIME type
        #[serde(rename = "mimeType")]
        mime_type: String,
    },
    /// Resource link
    #[serde(rename = "resource")]
    Resource {
        /// Resource URI
        uri: String,
        /// Optional title
        #[serde(skip_serializing_if = "Option::is_none")]
        title: Option<String>,
    },
}

impl ContentItem {
    /// Create a text content item
    pub fn text(s: impl Into<String>) -> Self {
        Self::Text { text: s.into() }
    }

    /// Create an image content item
    pub fn image(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
        Self::Image {
            data: data.into(),
            mime_type: mime_type.into(),
        }
    }

    /// Create an audio content item
    pub fn audio(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
        Self::Audio {
            data: data.into(),
            mime_type: mime_type.into(),
        }
    }

    /// Create a resource link content item
    pub fn resource(uri: impl Into<String>) -> Self {
        Self::Resource {
            uri: uri.into(),
            title: None,
        }
    }
}

// =============================================================================
// PAGINATION
// =============================================================================

/// Parameters for paginated requests
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PaginatedRequestParams {
    /// Cursor for the next page
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cursor: Option<String>,
}

// =============================================================================
// CANCELLED NOTIFICATION
// =============================================================================

/// Parameters for a `notifications/cancelled` notification
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CancelledNotificationParams {
    /// The ID of the request that was cancelled
    pub request_id: RequestId,
    /// Optional reason for cancellation
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reason: Option<String>,
}

/// Parameters for a `notifications/progress` notification
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ProgressNotificationParams {
    /// Progress token from the original request
    pub progress_token: Value,
    /// Progress value (0.0 - 1.0)
    pub progress: f64,
    /// Total expected value
    #[serde(skip_serializing_if = "Option::is_none")]
    pub total: Option<f64>,
    /// Optional message
    #[serde(skip_serializing_if = "Option::is_none")]
    pub message: Option<String>,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_version_gte_equal() {
        assert!(version_gte("1.0.0", "1.0.0"));
        assert!(version_gte("2.0.56", "2.0.56"));
    }

    #[test]
    fn test_version_gte_major_greater() {
        assert!(version_gte("2.0.0", "1.0.0"));
        assert!(version_gte("3.0.0", "2.9.99"));
    }

    #[test]
    fn test_version_gte_minor_greater() {
        assert!(version_gte("1.2.0", "1.1.0"));
        assert!(version_gte("1.10.0", "1.9.0"));
    }

    #[test]
    fn test_version_gte_patch_greater() {
        assert!(version_gte("1.0.2", "1.0.1"));
        assert!(version_gte("2.0.56", "2.0.55"));
    }

    #[test]
    fn test_version_gte_less_than() {
        assert!(!version_gte("1.0.0", "2.0.0"));
        assert!(!version_gte("2.0.55", "2.0.56"));
        assert!(!version_gte("1.9.0", "2.0.0"));
    }

    #[test]
    fn test_jsonrpc_request_creation() {
        let req = JsonRpcRequest::new(
            Value::from(1),
            "test_method",
            Some(serde_json::json!({"key": "value"})),
        );
        assert_eq!(req.jsonrpc, "2.0");
        assert_eq!(req.method, "test_method");
        assert!(req.id.is_some());
    }

    #[test]
    fn test_jsonrpc_notification() {
        let notif = JsonRpcRequest::notification("test_notif", None);
        assert!(notif.is_notification());
        assert!(notif.id.is_none());
    }

    #[test]
    fn test_jsonrpc_response_success() {
        let resp = JsonRpcResponse::success(Value::from(1), serde_json::json!({"status": "ok"}));
        assert!(resp.result.is_some());
        assert!(resp.error.is_none());
    }

    #[test]
    fn test_jsonrpc_response_error() {
        let error = JsonRpcError::method_not_found("test method not found");
        let resp = JsonRpcResponse::error(Value::from(1), error);
        assert!(resp.result.is_none());
        assert!(resp.error.is_some());
        assert_eq!(resp.error.unwrap().code, ErrorCode::METHOD_NOT_FOUND);
    }

    #[test]
    fn test_request_id_hash_eq() {
        use std::collections::HashMap;
        let mut map = HashMap::new();
        map.insert(RequestId::number(1), "first");
        map.insert(RequestId::string("abc"), "second");
        assert_eq!(map.get(&RequestId::number(1)), Some(&"first"));
        assert_eq!(map.get(&RequestId::string("abc")), Some(&"second"));
        assert_eq!(map.get(&RequestId::number(2)), None);
    }

    #[test]
    fn test_request_id_display() {
        assert_eq!(RequestId::number(42).to_string(), "42");
        assert_eq!(RequestId::string("req-1").to_string(), "req-1");
    }

    #[test]
    fn test_request_id_serde_roundtrip() {
        let id_num = RequestId::number(42);
        let json = serde_json::to_value(&id_num).unwrap();
        assert_eq!(json, serde_json::json!(42));
        let back: RequestId = serde_json::from_value(json).unwrap();
        assert_eq!(back, id_num);

        let id_str = RequestId::string("req-1");
        let json = serde_json::to_value(&id_str).unwrap();
        assert_eq!(json, serde_json::json!("req-1"));
        let back: RequestId = serde_json::from_value(json).unwrap();
        assert_eq!(back, id_str);
    }

    #[test]
    fn test_request_id_from_value() {
        assert_eq!(
            RequestId::from_value(&serde_json::json!(42)),
            Some(RequestId::number(42))
        );
        assert_eq!(
            RequestId::from_value(&serde_json::json!("abc")),
            Some(RequestId::string("abc"))
        );
        assert_eq!(RequestId::from_value(&serde_json::json!(null)), None);
        assert_eq!(RequestId::from_value(&serde_json::json!([1, 2])), None);
    }

    #[test]
    fn test_jsonrpc_message_deserialize_request() {
        let json = serde_json::json!({
            "jsonrpc": "2.0",
            "id": 1,
            "method": "tools/call",
            "params": {"name": "echo"}
        });
        let msg: JsonRpcMessage = serde_json::from_value(json).unwrap();
        assert!(matches!(msg, JsonRpcMessage::Request(_)));
        assert_eq!(msg.method(), Some("tools/call"));
    }

    #[test]
    fn test_jsonrpc_message_deserialize_notification() {
        let json = serde_json::json!({
            "jsonrpc": "2.0",
            "method": "notifications/initialized"
        });
        let msg: JsonRpcMessage = serde_json::from_value(json).unwrap();
        assert!(matches!(msg, JsonRpcMessage::Notification(_)));
        assert!(msg.id().is_none());
    }

    #[test]
    fn test_jsonrpc_message_deserialize_response() {
        let json = serde_json::json!({
            "jsonrpc": "2.0",
            "id": 1,
            "result": {"status": "ok"}
        });
        let msg: JsonRpcMessage = serde_json::from_value(json).unwrap();
        assert!(matches!(msg, JsonRpcMessage::Response(_)));
    }

    #[test]
    fn test_content_item_text() {
        let item = ContentItem::text("hello");
        let json = serde_json::to_value(&item).unwrap();
        assert_eq!(json["type"], "text");
        assert_eq!(json["text"], "hello");
    }

    #[test]
    fn test_content_item_roundtrip() {
        let item = ContentItem::image("base64data", "image/png");
        let json = serde_json::to_value(&item).unwrap();
        let back: ContentItem = serde_json::from_value(json).unwrap();
        assert_eq!(back, item);
    }

    #[test]
    fn test_call_tool_result_text() {
        let result = CallToolResult::text("done");
        assert_eq!(result.content.len(), 1);
        assert!(result.is_error.is_none());
    }

    #[test]
    fn test_call_tool_result_error() {
        let result = CallToolResult::error("failed");
        assert_eq!(result.is_error, Some(true));
    }

    #[test]
    fn test_implementation_builder() {
        let impl_info = Implementation::new("test", "1.0")
            .with_title("Test Server")
            .with_website_url("https://example.com");
        assert_eq!(impl_info.name, "test");
        assert_eq!(impl_info.title, Some("Test Server".to_string()));
        assert_eq!(
            impl_info.website_url,
            Some("https://example.com".to_string())
        );
        // Ensure backwards compat: only name+version serialized when no extras
        let minimal = Implementation::new("test", "1.0");
        let json = serde_json::to_value(&minimal).unwrap();
        assert!(!json.as_object().unwrap().contains_key("title"));
    }

    #[test]
    fn test_error_code_constants() {
        assert_eq!(ErrorCode::PARSE_ERROR, -32700);
        assert_eq!(ErrorCode::INVALID_REQUEST, -32600);
        assert_eq!(ErrorCode::METHOD_NOT_FOUND, -32601);
        assert_eq!(ErrorCode::INVALID_PARAMS, -32602);
        assert_eq!(ErrorCode::INTERNAL_ERROR, -32603);
    }
}
