//! MCP method names
//!
//! Defines all available MCP methods as type-safe constants

use serde::{Deserialize, Serialize};
use std::fmt;

/// MCP method names
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum McpMethod {
    // Core methods
    Initialize,
    Ping,

    // Resource methods
    #[serde(rename = "resources/list")]
    ResourcesList,
    #[serde(rename = "resources/templates/list")]
    ResourcesTemplatesList,
    #[serde(rename = "resources/read")]
    ResourcesRead,
    #[serde(rename = "resources/subscribe")]
    ResourcesSubscribe,
    #[serde(rename = "resources/unsubscribe")]
    ResourcesUnsubscribe,

    // Prompt methods
    #[serde(rename = "prompts/list")]
    PromptsList,
    #[serde(rename = "prompts/get")]
    PromptsGet,

    // Tool methods
    #[serde(rename = "tools/list")]
    ToolsList,
    #[serde(rename = "tools/call")]
    ToolsCall,

    // Task methods (async execution)
    #[serde(rename = "tasks/get")]
    TasksGet,
    #[serde(rename = "tasks/result")]
    TasksResult,
    #[serde(rename = "tasks/list")]
    TasksList,
    #[serde(rename = "tasks/cancel")]
    TasksCancel,

    // Logging methods
    #[serde(rename = "logging/setLevel")]
    LoggingSetLevel,

    // Completion methods
    #[serde(rename = "completion/complete")]
    CompletionComplete,

    // Elicitation methods (server-initiated user input)
    #[serde(rename = "elicitation/create")]
    ElicitationCreate,

    // Sampling methods (server-initiated LLM sampling)
    #[serde(rename = "sampling/createMessage")]
    SamplingCreateMessage,

    // Roots methods (client workspace roots)
    #[serde(rename = "roots/list")]
    RootsList,

    // Notification methods
    #[serde(rename = "notifications/initialized")]
    NotificationsInitialized,
    #[serde(rename = "notifications/resources/list_changed")]
    NotificationsResourcesListChanged,
    #[serde(rename = "notifications/resources/updated")]
    NotificationsResourcesUpdated,
    #[serde(rename = "notifications/prompts/list_changed")]
    NotificationsPromptsListChanged,
    #[serde(rename = "notifications/tools/list_changed")]
    NotificationsToolsListChanged,
    #[serde(rename = "notifications/progress")]
    NotificationsProgress,
    #[serde(rename = "notifications/message")]
    NotificationsMessage,
    #[serde(rename = "notifications/cancelled")]
    NotificationsCancelled,
    #[serde(rename = "notifications/roots/list_changed")]
    NotificationsRootsListChanged,
    #[serde(rename = "notifications/tasks/status")]
    NotificationsTasksStatus,
    #[serde(rename = "notifications/elicitation/complete")]
    NotificationsElicitationComplete,

    // Custom/unknown method (for extensibility)
    #[serde(untagged)]
    Custom(String),
}

impl fmt::Display for McpMethod {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            McpMethod::Initialize => write!(f, "initialize"),
            McpMethod::Ping => write!(f, "ping"),
            McpMethod::ResourcesList => write!(f, "resources/list"),
            McpMethod::ResourcesTemplatesList => write!(f, "resources/templates/list"),
            McpMethod::ResourcesRead => write!(f, "resources/read"),
            McpMethod::ResourcesSubscribe => write!(f, "resources/subscribe"),
            McpMethod::ResourcesUnsubscribe => write!(f, "resources/unsubscribe"),
            McpMethod::PromptsList => write!(f, "prompts/list"),
            McpMethod::PromptsGet => write!(f, "prompts/get"),
            McpMethod::ToolsList => write!(f, "tools/list"),
            McpMethod::ToolsCall => write!(f, "tools/call"),
            McpMethod::TasksGet => write!(f, "tasks/get"),
            McpMethod::TasksResult => write!(f, "tasks/result"),
            McpMethod::TasksList => write!(f, "tasks/list"),
            McpMethod::TasksCancel => write!(f, "tasks/cancel"),
            McpMethod::LoggingSetLevel => write!(f, "logging/setLevel"),
            McpMethod::CompletionComplete => write!(f, "completion/complete"),
            McpMethod::ElicitationCreate => write!(f, "elicitation/create"),
            McpMethod::SamplingCreateMessage => write!(f, "sampling/createMessage"),
            McpMethod::RootsList => write!(f, "roots/list"),
            McpMethod::NotificationsInitialized => write!(f, "notifications/initialized"),
            McpMethod::NotificationsResourcesListChanged => {
                write!(f, "notifications/resources/list_changed")
            }
            McpMethod::NotificationsResourcesUpdated => {
                write!(f, "notifications/resources/updated")
            }
            McpMethod::NotificationsPromptsListChanged => {
                write!(f, "notifications/prompts/list_changed")
            }
            McpMethod::NotificationsToolsListChanged => {
                write!(f, "notifications/tools/list_changed")
            }
            McpMethod::NotificationsProgress => write!(f, "notifications/progress"),
            McpMethod::NotificationsMessage => write!(f, "notifications/message"),
            McpMethod::NotificationsCancelled => write!(f, "notifications/cancelled"),
            McpMethod::NotificationsRootsListChanged => {
                write!(f, "notifications/roots/list_changed")
            }
            McpMethod::NotificationsTasksStatus => write!(f, "notifications/tasks/status"),
            McpMethod::NotificationsElicitationComplete => {
                write!(f, "notifications/elicitation/complete")
            }
            McpMethod::Custom(s) => write!(f, "{}", s),
        }
    }
}

impl From<String> for McpMethod {
    fn from(s: String) -> Self {
        match s.as_str() {
            "initialize" => McpMethod::Initialize,
            "ping" => McpMethod::Ping,
            "resources/list" => McpMethod::ResourcesList,
            "resources/templates/list" => McpMethod::ResourcesTemplatesList,
            "resources/read" => McpMethod::ResourcesRead,
            "resources/subscribe" => McpMethod::ResourcesSubscribe,
            "resources/unsubscribe" => McpMethod::ResourcesUnsubscribe,
            "prompts/list" => McpMethod::PromptsList,
            "prompts/get" => McpMethod::PromptsGet,
            "tools/list" => McpMethod::ToolsList,
            "tools/call" => McpMethod::ToolsCall,
            "tasks/get" => McpMethod::TasksGet,
            "tasks/result" => McpMethod::TasksResult,
            "tasks/list" => McpMethod::TasksList,
            "tasks/cancel" => McpMethod::TasksCancel,
            "logging/setLevel" => McpMethod::LoggingSetLevel,
            "completion/complete" => McpMethod::CompletionComplete,
            "elicitation/create" => McpMethod::ElicitationCreate,
            "sampling/createMessage" => McpMethod::SamplingCreateMessage,
            "roots/list" => McpMethod::RootsList,
            "notifications/initialized" => McpMethod::NotificationsInitialized,
            "notifications/resources/list_changed" => McpMethod::NotificationsResourcesListChanged,
            "notifications/resources/updated" => McpMethod::NotificationsResourcesUpdated,
            "notifications/prompts/list_changed" => McpMethod::NotificationsPromptsListChanged,
            "notifications/tools/list_changed" => McpMethod::NotificationsToolsListChanged,
            "notifications/progress" => McpMethod::NotificationsProgress,
            "notifications/message" => McpMethod::NotificationsMessage,
            "notifications/cancelled" => McpMethod::NotificationsCancelled,
            "notifications/roots/list_changed" => McpMethod::NotificationsRootsListChanged,
            "notifications/tasks/status" => McpMethod::NotificationsTasksStatus,
            "notifications/elicitation/complete" => McpMethod::NotificationsElicitationComplete,
            _ => McpMethod::Custom(s),
        }
    }
}

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

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

    #[test]
    fn test_method_display() {
        assert_eq!(McpMethod::Initialize.to_string(), "initialize");
        assert_eq!(McpMethod::ResourcesList.to_string(), "resources/list");
        assert_eq!(McpMethod::ToolsCall.to_string(), "tools/call");
    }

    #[test]
    fn test_method_from_string() {
        assert_eq!(McpMethod::from("initialize"), McpMethod::Initialize);
        assert_eq!(McpMethod::from("tools/call"), McpMethod::ToolsCall);
        assert_eq!(
            McpMethod::from("notifications/progress"),
            McpMethod::NotificationsProgress
        );
    }

    #[test]
    fn test_custom_method() {
        let method = McpMethod::from("custom/method");
        assert!(matches!(method, McpMethod::Custom(_)));
        assert_eq!(method.to_string(), "custom/method");
    }
}
