//! Tool, prompt, and resource routers for function-based handlers
//!
//! The `McpToolRouter` bridges function-based tool handlers (from `#[mcp_tool_router]`)
//! with the existing `ToolRegistry` system, preserving circuit breaker integration.
//!
//! The `McpPromptRouter` provides the same ergonomic pattern for prompts.
//!
//! The `McpResourceRouter` provides the same ergonomic pattern for resources and templates.

use std::borrow::Cow;
use std::collections::HashMap;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;

use async_trait::async_trait;
use serde_json::Value;

use crate::content::resource::ResourceContent;
use crate::macros::{PromptResult, ResourceResult, ToolResult};
use crate::server::visibility::{ExecutionContext, VisibilityContext};

use super::prompts::{GetPromptResult, Prompt, PromptError, PromptInfo, PromptManager};
use super::resources::{
    Resource, ResourceError, ResourceInfo, ResourceManager, ResourceTemplate, ResourceTemplateInfo,
};
use super::tools::{Tool, ToolError, ToolInfo, ToolOutput, ToolRegistry};

/// Type alias for tool handler futures
pub type ToolHandlerFuture<'a> = Pin<Box<dyn Future<Output = ToolResult> + Send + 'a>>;

/// Type alias for tool handler functions
pub type ToolHandlerFn<S> =
    for<'a> fn(&'a S, ExecutionContext<'a>) -> ToolHandlerFuture<'a>;

/// Type alias for visibility predicate functions
pub type VisibilityFn = fn(&VisibilityContext) -> bool;

/// A route in the tool router
pub struct McpToolRoute<S> {
    /// Tool metadata (name, description, schema)
    pub info: ToolInfo,
    /// Handler function
    pub handler: ToolHandlerFn<S>,
    /// Optional visibility predicate
    pub visibility: Option<VisibilityFn>,
}

/// Router for function-based tools
///
/// Collects tools defined via `#[mcp_tool]` and provides a bridge to `ToolRegistry`.
///
/// # Example
///
/// ```rust,ignore
/// #[mcp_tool_router]
/// impl MyServer {
///     #[mcp_tool(name = "calculate")]
///     async fn calculate(&self, ctx: Ctx, params: Parameters<CalcParams>) -> ToolResult {
///         // ...
///     }
/// }
///
/// // Generated by macro:
/// impl MyServer {
///     pub fn tool_router() -> McpToolRouter<Self> {
///         McpToolRouter::new()
///             .with_tool(Self::calculate_tool_info(), Self::calculate_handler, None)
///     }
/// }
///
/// // Registration:
/// let server = Arc::new(MyServer::new());
/// MyServer::tool_router().register_all(&registry, server);
/// ```
pub struct McpToolRouter<S> {
    routes: HashMap<Cow<'static, str>, McpToolRoute<S>>,
}

impl<S> McpToolRouter<S> {
    /// Create a new empty router
    pub fn new() -> Self {
        Self {
            routes: HashMap::new(),
        }
    }

    /// Add a tool to the router
    pub fn with_tool(
        mut self,
        info: ToolInfo,
        handler: ToolHandlerFn<S>,
        visibility: Option<VisibilityFn>,
    ) -> Self {
        self.routes.insert(
            Cow::Owned(info.name.clone()),
            McpToolRoute {
                info,
                handler,
                visibility,
            },
        );
        self
    }

    /// Get number of routes
    pub fn len(&self) -> usize {
        self.routes.len()
    }

    /// Check if router is empty
    pub fn is_empty(&self) -> bool {
        self.routes.is_empty()
    }

    /// List all tool infos
    pub fn list(&self) -> Vec<ToolInfo> {
        self.routes.values().map(|r| r.info.clone()).collect()
    }
}

impl<S: Send + Sync + 'static> McpToolRouter<S> {
    /// Convert router routes into `Arc<dyn Tool>` objects
    ///
    /// Creates wrapper types that implement the `Tool` trait by delegating
    /// to the function handlers.
    pub fn into_tools(self, service: Arc<S>) -> Vec<Arc<dyn Tool>> {
        self.routes
            .into_values()
            .map(|route| {
                Arc::new(RouterTool {
                    service: service.clone(),
                    info: route.info,
                    handler: route.handler,
                    visibility: route.visibility,
                }) as Arc<dyn Tool>
            })
            .collect()
    }

    /// Register all routes with a ToolRegistry
    ///
    /// This is the primary integration point. Tools registered this way
    /// automatically get circuit breaker protection from the registry.
    pub fn register_all(self, registry: &ToolRegistry, service: Arc<S>) {
        for tool in self.into_tools(service) {
            registry.register_boxed(tool);
        }
    }
}

impl<S> Default for McpToolRouter<S> {
    fn default() -> Self {
        Self::new()
    }
}

impl<S> std::fmt::Debug for McpToolRouter<S> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("McpToolRouter")
            .field("route_count", &self.routes.len())
            .field("tools", &self.routes.keys().collect::<Vec<_>>())
            .finish()
    }
}

/// Wrapper type that adapts router-based handlers to the `Tool` trait
struct RouterTool<S> {
    service: Arc<S>,
    info: ToolInfo,
    handler: ToolHandlerFn<S>,
    visibility: Option<VisibilityFn>,
}

#[async_trait]
impl<S: Send + Sync + 'static> Tool for RouterTool<S> {
    fn name(&self) -> &str {
        &self.info.name
    }

    fn title(&self) -> Option<&str> {
        self.info.title.as_deref()
    }

    fn description(&self) -> Option<&str> {
        self.info.description.as_deref()
    }

    fn input_schema(&self) -> Value {
        self.info.input_schema.clone()
    }

    fn output_schema(&self) -> Option<Value> {
        self.info.output_schema.clone()
    }

    fn execution(&self) -> Option<crate::protocol::types::ToolExecution> {
        self.info.execution.clone()
    }

    fn is_visible(&self, ctx: &VisibilityContext) -> bool {
        self.visibility.map(|f| f(ctx)).unwrap_or(true)
    }

    async fn execute(&self, ctx: ExecutionContext<'_>) -> Result<ToolOutput, ToolError> {
        // Call the handler function
        (self.handler)(&self.service, ctx).await
    }
}

/// Builder for creating tool routes manually (for advanced use cases)
pub struct ToolRouteBuilder<S> {
    info: ToolInfo,
    handler: Option<ToolHandlerFn<S>>,
    visibility: Option<VisibilityFn>,
}

impl<S> ToolRouteBuilder<S> {
    /// Create a new builder with tool info
    pub fn new(info: ToolInfo) -> Self {
        Self {
            info,
            handler: None,
            visibility: None,
        }
    }

    /// Set the handler function
    pub fn handler(mut self, handler: ToolHandlerFn<S>) -> Self {
        self.handler = Some(handler);
        self
    }

    /// Set the visibility predicate
    pub fn visibility(mut self, visibility: VisibilityFn) -> Self {
        self.visibility = Some(visibility);
        self
    }

    /// Build the route (panics if handler not set)
    pub fn build(self) -> McpToolRoute<S> {
        McpToolRoute {
            info: self.info,
            handler: self.handler.expect("Handler must be set"),
            visibility: self.visibility,
        }
    }
}

/// Helper to create ToolInfo from components
pub fn tool_info(
    name: impl Into<String>,
    description: Option<String>,
    input_schema: Value,
) -> ToolInfo {
    ToolInfo {
        name: name.into(),
        title: None,
        description,
        input_schema,
        output_schema: None,
        execution: None,
        annotations: None,
    }
}

/// Helper to create ToolInfo with output schema for structured output
pub fn tool_info_with_output(
    name: impl Into<String>,
    title: Option<String>,
    description: Option<String>,
    input_schema: Value,
    output_schema: Value,
) -> ToolInfo {
    ToolInfo {
        name: name.into(),
        title,
        description,
        input_schema,
        output_schema: Some(output_schema),
        execution: None,
        annotations: None,
    }
}

// ============================================================================
// Prompt Router
// ============================================================================

/// Type alias for prompt handler futures
pub type PromptHandlerFuture<'a> = Pin<Box<dyn Future<Output = PromptResult> + Send + 'a>>;

/// Type alias for prompt handler functions
pub type PromptHandlerFn<S> = for<'a> fn(&'a S, ExecutionContext<'a>) -> PromptHandlerFuture<'a>;

/// A route in the prompt router
pub struct McpPromptRoute<S> {
    /// Prompt metadata (name, description, arguments)
    pub info: PromptInfo,
    /// Handler function
    pub handler: PromptHandlerFn<S>,
    /// Optional visibility predicate
    pub visibility: Option<VisibilityFn>,
}

/// Router for function-based prompts
///
/// Collects prompts defined via `#[mcp_prompt]` and provides a bridge to `PromptManager`.
///
/// # Example
///
/// ```rust,ignore
/// #[mcp_prompt_router]
/// impl MyServer {
///     #[mcp_prompt(name = "greeting")]
///     async fn greeting(&self, ctx: Ctx, args: Value) -> PromptResult {
///         // ...
///     }
/// }
///
/// // Generated by macro:
/// impl MyServer {
///     pub fn prompt_router() -> McpPromptRouter<Self> {
///         McpPromptRouter::new()
///             .with_prompt(Self::greeting_prompt_info(), Self::greeting_handler, None)
///     }
/// }
///
/// // Registration:
/// let server = Arc::new(MyServer::new());
/// MyServer::prompt_router().register_all(&manager, server);
/// ```
pub struct McpPromptRouter<S> {
    routes: HashMap<Cow<'static, str>, McpPromptRoute<S>>,
}

impl<S> McpPromptRouter<S> {
    /// Create a new empty router
    pub fn new() -> Self {
        Self {
            routes: HashMap::new(),
        }
    }

    /// Add a prompt to the router
    pub fn with_prompt(
        mut self,
        info: PromptInfo,
        handler: PromptHandlerFn<S>,
        visibility: Option<VisibilityFn>,
    ) -> Self {
        self.routes.insert(
            Cow::Owned(info.name.clone()),
            McpPromptRoute {
                info,
                handler,
                visibility,
            },
        );
        self
    }

    /// Get number of routes
    pub fn len(&self) -> usize {
        self.routes.len()
    }

    /// Check if router is empty
    pub fn is_empty(&self) -> bool {
        self.routes.is_empty()
    }

    /// List all prompt infos
    pub fn list(&self) -> Vec<PromptInfo> {
        self.routes.values().map(|r| r.info.clone()).collect()
    }
}

impl<S: Send + Sync + 'static> McpPromptRouter<S> {
    /// Convert router routes into `Arc<dyn Prompt>` objects
    ///
    /// Creates wrapper types that implement the `Prompt` trait by delegating
    /// to the function handlers.
    pub fn into_prompts(self, service: Arc<S>) -> Vec<Arc<dyn Prompt>> {
        self.routes
            .into_values()
            .map(|route| {
                Arc::new(RouterPrompt {
                    service: service.clone(),
                    info: route.info,
                    handler: route.handler,
                    visibility: route.visibility,
                }) as Arc<dyn Prompt>
            })
            .collect()
    }

    /// Register all routes with a PromptManager
    pub fn register_all(self, manager: &PromptManager, service: Arc<S>) {
        for prompt in self.into_prompts(service) {
            manager.register_boxed(prompt);
        }
    }
}

impl<S> Default for McpPromptRouter<S> {
    fn default() -> Self {
        Self::new()
    }
}

impl<S> std::fmt::Debug for McpPromptRouter<S> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("McpPromptRouter")
            .field("route_count", &self.routes.len())
            .field("prompts", &self.routes.keys().collect::<Vec<_>>())
            .finish()
    }
}

/// Wrapper type that adapts router-based handlers to the `Prompt` trait
struct RouterPrompt<S> {
    service: Arc<S>,
    info: PromptInfo,
    handler: PromptHandlerFn<S>,
    visibility: Option<VisibilityFn>,
}

#[async_trait]
impl<S: Send + Sync + 'static> Prompt for RouterPrompt<S> {
    fn name(&self) -> &str {
        &self.info.name
    }

    fn description(&self) -> Option<&str> {
        self.info.description.as_deref()
    }

    fn arguments(&self) -> Option<Vec<super::prompts::PromptArgument>> {
        self.info.arguments.clone()
    }

    fn is_visible(&self, ctx: &VisibilityContext) -> bool {
        self.visibility.map(|f| f(ctx)).unwrap_or(true)
    }

    async fn get(&self, ctx: ExecutionContext<'_>) -> Result<GetPromptResult, PromptError> {
        // Call the handler function
        (self.handler)(&self.service, ctx).await
    }
}

/// Helper to create PromptInfo from components
pub fn prompt_info(name: impl Into<String>, description: Option<String>) -> PromptInfo {
    PromptInfo {
        name: name.into(),
        description,
        arguments: None,
    }
}

/// Helper to create PromptInfo with arguments
pub fn prompt_info_with_args(
    name: impl Into<String>,
    description: Option<String>,
    arguments: Vec<super::prompts::PromptArgument>,
) -> PromptInfo {
    PromptInfo {
        name: name.into(),
        description,
        arguments: Some(arguments),
    }
}

// ============================================================================
// Resource Router
// ============================================================================

/// Type alias for resource handler futures
pub type ResourceHandlerFuture<'a> = Pin<Box<dyn Future<Output = ResourceResult> + Send + 'a>>;

/// Type alias for resource handler functions
pub type ResourceHandlerFn<S> = for<'a> fn(&'a S, ExecutionContext<'a>) -> ResourceHandlerFuture<'a>;

/// A route in the resource router
pub struct McpResourceRoute<S> {
    /// Resource metadata (uri, name, description, mime_type)
    pub info: ResourceInfo,
    /// Handler function
    pub handler: ResourceHandlerFn<S>,
    /// Optional visibility predicate
    pub visibility: Option<VisibilityFn>,
}

/// Router for function-based resources
///
/// Collects resources defined via `#[mcp_resource]` and provides a bridge to `ResourceManager`.
///
/// # Example
///
/// ```rust,ignore
/// #[mcp_resource_router]
/// impl MyServer {
///     #[mcp_resource(uri = "config:///app", name = "app_config")]
///     async fn app_config(&self, ctx: Ctx) -> ResourceResult {
///         Ok(vec![ResourceContent::text("config:///app", "{}")])
///     }
/// }
///
/// // Generated by macro:
/// impl MyServer {
///     pub fn resource_router() -> McpResourceRouter<Self> {
///         McpResourceRouter::new()
///             .with_resource(Self::app_config_resource_info(), Self::app_config_handler, None)
///     }
/// }
///
/// // Registration:
/// let server = Arc::new(MyServer::new());
/// MyServer::resource_router().register_all(&manager, server);
/// ```
pub struct McpResourceRouter<S> {
    routes: HashMap<Cow<'static, str>, McpResourceRoute<S>>,
}

impl<S> McpResourceRouter<S> {
    /// Create a new empty router
    pub fn new() -> Self {
        Self {
            routes: HashMap::new(),
        }
    }

    /// Add a resource to the router
    pub fn with_resource(
        mut self,
        info: ResourceInfo,
        handler: ResourceHandlerFn<S>,
        visibility: Option<VisibilityFn>,
    ) -> Self {
        self.routes.insert(
            Cow::Owned(info.uri.clone()),
            McpResourceRoute {
                info,
                handler,
                visibility,
            },
        );
        self
    }

    /// Get number of routes
    pub fn len(&self) -> usize {
        self.routes.len()
    }

    /// Check if router is empty
    pub fn is_empty(&self) -> bool {
        self.routes.is_empty()
    }

    /// List all resource infos
    pub fn list(&self) -> Vec<ResourceInfo> {
        self.routes.values().map(|r| r.info.clone()).collect()
    }
}

impl<S: Send + Sync + 'static> McpResourceRouter<S> {
    /// Convert router routes into `Arc<dyn Resource>` objects
    pub fn into_resources(self, service: Arc<S>) -> Vec<Arc<dyn Resource>> {
        self.routes
            .into_values()
            .map(|route| {
                Arc::new(RouterResource {
                    service: service.clone(),
                    info: route.info,
                    handler: route.handler,
                    visibility: route.visibility,
                }) as Arc<dyn Resource>
            })
            .collect()
    }

    /// Register all routes with a ResourceManager
    pub fn register_all(self, manager: &ResourceManager, service: Arc<S>) {
        for resource in self.into_resources(service) {
            manager.register_boxed(resource);
        }
    }
}

impl<S> Default for McpResourceRouter<S> {
    fn default() -> Self {
        Self::new()
    }
}

impl<S> std::fmt::Debug for McpResourceRouter<S> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("McpResourceRouter")
            .field("route_count", &self.routes.len())
            .field("resources", &self.routes.keys().collect::<Vec<_>>())
            .finish()
    }
}

/// Wrapper type that adapts router-based handlers to the `Resource` trait
struct RouterResource<S> {
    service: Arc<S>,
    info: ResourceInfo,
    handler: ResourceHandlerFn<S>,
    visibility: Option<VisibilityFn>,
}

#[async_trait]
impl<S: Send + Sync + 'static> Resource for RouterResource<S> {
    fn uri(&self) -> &str {
        &self.info.uri
    }

    fn name(&self) -> &str {
        &self.info.name
    }

    fn description(&self) -> Option<&str> {
        self.info.description.as_deref()
    }

    fn mime_type(&self) -> Option<&str> {
        self.info.mime_type.as_deref()
    }

    fn is_visible(&self, ctx: &VisibilityContext) -> bool {
        self.visibility.map(|f| f(ctx)).unwrap_or(true)
    }

    async fn read(&self, ctx: ExecutionContext<'_>) -> Result<Vec<ResourceContent>, ResourceError> {
        (self.handler)(&self.service, ctx).await
    }
}

/// Helper to create ResourceInfo from components
pub fn resource_info(
    uri: impl Into<String>,
    name: impl Into<String>,
    description: Option<String>,
    mime_type: Option<String>,
) -> ResourceInfo {
    ResourceInfo {
        uri: uri.into(),
        name: name.into(),
        description,
        mime_type,
    }
}

// ============================================================================
// Resource Template Router
// ============================================================================

/// Type alias for resource template handler futures
pub type ResourceTemplateHandlerFuture<'a> =
    Pin<Box<dyn Future<Output = ResourceResult> + Send + 'a>>;

/// Type alias for resource template handler functions
pub type ResourceTemplateHandlerFn<S> = for<'a> fn(&'a S, ExecutionContext<'a>) -> ResourceTemplateHandlerFuture<'a>;

/// A route in the resource template router
pub struct McpResourceTemplateRoute<S> {
    /// Template metadata (uri_template, name, description, mime_type)
    pub info: ResourceTemplateInfo,
    /// Handler function
    pub handler: ResourceTemplateHandlerFn<S>,
    /// Optional visibility predicate
    pub visibility: Option<VisibilityFn>,
}

/// Router for function-based resource templates
///
/// Collects resource templates defined via `#[mcp_resource_template]` and provides
/// a bridge to `ResourceManager`.
///
/// # Example
///
/// ```rust,ignore
/// #[mcp_resource_router]
/// impl MyServer {
///     #[mcp_resource_template(uri_template = "file:///{path}", name = "files")]
///     async fn read_file(&self, ctx: Ctx) -> ResourceResult {
///         let path = ctx.get_uri_param("path")?;
///         // ...
///     }
/// }
///
/// // Generated by macro:
/// impl MyServer {
///     pub fn resource_template_router() -> McpResourceTemplateRouter<Self> {
///         McpResourceTemplateRouter::new()
///             .with_template(Self::read_file_template_info(), Self::read_file_handler, None)
///     }
/// }
/// ```
pub struct McpResourceTemplateRouter<S> {
    routes: HashMap<Cow<'static, str>, McpResourceTemplateRoute<S>>,
}

impl<S> McpResourceTemplateRouter<S> {
    /// Create a new empty router
    pub fn new() -> Self {
        Self {
            routes: HashMap::new(),
        }
    }

    /// Add a resource template to the router
    pub fn with_template(
        mut self,
        info: ResourceTemplateInfo,
        handler: ResourceTemplateHandlerFn<S>,
        visibility: Option<VisibilityFn>,
    ) -> Self {
        self.routes.insert(
            Cow::Owned(info.uri_template.clone()),
            McpResourceTemplateRoute {
                info,
                handler,
                visibility,
            },
        );
        self
    }

    /// Get number of routes
    pub fn len(&self) -> usize {
        self.routes.len()
    }

    /// Check if router is empty
    pub fn is_empty(&self) -> bool {
        self.routes.is_empty()
    }

    /// List all template infos
    pub fn list(&self) -> Vec<ResourceTemplateInfo> {
        self.routes.values().map(|r| r.info.clone()).collect()
    }
}

impl<S: Send + Sync + 'static> McpResourceTemplateRouter<S> {
    /// Convert router routes into `Arc<dyn ResourceTemplate>` objects
    pub fn into_templates(self, service: Arc<S>) -> Vec<Arc<dyn ResourceTemplate>> {
        self.routes
            .into_values()
            .map(|route| {
                Arc::new(RouterResourceTemplate {
                    service: service.clone(),
                    info: route.info,
                    handler: route.handler,
                    visibility: route.visibility,
                }) as Arc<dyn ResourceTemplate>
            })
            .collect()
    }

    /// Register all routes with a ResourceManager
    pub fn register_all(self, manager: &ResourceManager, service: Arc<S>) {
        for template in self.into_templates(service) {
            manager.register_template_boxed(template);
        }
    }
}

impl<S> Default for McpResourceTemplateRouter<S> {
    fn default() -> Self {
        Self::new()
    }
}

impl<S> std::fmt::Debug for McpResourceTemplateRouter<S> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("McpResourceTemplateRouter")
            .field("route_count", &self.routes.len())
            .field("templates", &self.routes.keys().collect::<Vec<_>>())
            .finish()
    }
}

/// Wrapper type that adapts router-based handlers to the `ResourceTemplate` trait
struct RouterResourceTemplate<S> {
    service: Arc<S>,
    info: ResourceTemplateInfo,
    handler: ResourceTemplateHandlerFn<S>,
    visibility: Option<VisibilityFn>,
}

#[async_trait]
impl<S: Send + Sync + 'static> ResourceTemplate for RouterResourceTemplate<S> {
    fn uri_template(&self) -> &str {
        &self.info.uri_template
    }

    fn name(&self) -> &str {
        &self.info.name
    }

    fn title(&self) -> Option<&str> {
        self.info.title.as_deref()
    }

    fn description(&self) -> Option<&str> {
        self.info.description.as_deref()
    }

    fn mime_type(&self) -> Option<&str> {
        self.info.mime_type.as_deref()
    }

    fn is_visible(&self, ctx: &VisibilityContext) -> bool {
        self.visibility.map(|f| f(ctx)).unwrap_or(true)
    }

    async fn read(&self, ctx: ExecutionContext<'_>) -> Result<Vec<ResourceContent>, ResourceError> {
        (self.handler)(&self.service, ctx).await
    }
}

// ============================================================================
// Combined Router
// ============================================================================

/// Combined router holding all MCP handler routers
///
/// Generated by `#[mcp_router]` to provide a single entry point for all handlers.
///
/// # Example
///
/// ```rust,ignore
/// #[mcp_router]
/// impl MyServer {
///     #[mcp_tool(name = "echo")]
///     async fn echo(&self, ctx: Ctx, params: Parameters<EchoParams>) -> ToolResult { ... }
///
///     #[mcp_prompt(name = "greeting")]
///     async fn greeting(&self, ctx: Ctx, args: Value) -> PromptResult { ... }
/// }
///
/// // Registration:
/// let server = Arc::new(MyServer::new());
/// let router = MyServer::router();
/// router.register_all(&server_instance, server);
/// ```
pub struct McpRouter<S> {
    /// Tool router
    pub tools: McpToolRouter<S>,
    /// Prompt router
    pub prompts: McpPromptRouter<S>,
    /// Resource router
    pub resources: McpResourceRouter<S>,
    /// Resource template router
    pub templates: McpResourceTemplateRouter<S>,
}

impl<S: Send + Sync + 'static> McpRouter<S> {
    /// Create a new combined router with all sub-routers
    pub fn new(
        tools: McpToolRouter<S>,
        prompts: McpPromptRouter<S>,
        resources: McpResourceRouter<S>,
        templates: McpResourceTemplateRouter<S>,
    ) -> Self {
        Self {
            tools,
            prompts,
            resources,
            templates,
        }
    }

    /// Register all handlers with their respective managers
    pub fn register_all(
        self,
        tool_registry: &ToolRegistry,
        prompt_manager: &PromptManager,
        resource_manager: &ResourceManager,
        service: Arc<S>,
    ) {
        self.tools.register_all(tool_registry, service.clone());
        self.prompts.register_all(prompt_manager, service.clone());
        self.resources.register_all(resource_manager, service.clone());
        self.templates.register_all(resource_manager, service);
    }
}

impl<S> std::fmt::Debug for McpRouter<S> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("McpRouter")
            .field("tools", &self.tools.len())
            .field("prompts", &self.prompts.len())
            .field("resources", &self.resources.len())
            .field("templates", &self.templates.len())
            .finish()
    }
}

/// Helper to create ResourceTemplateInfo from components
pub fn resource_template_info(
    uri_template: impl Into<String>,
    name: impl Into<String>,
    title: Option<String>,
    description: Option<String>,
    mime_type: Option<String>,
) -> ResourceTemplateInfo {
    ResourceTemplateInfo {
        uri_template: uri_template.into(),
        name: name.into(),
        title,
        description,
        mime_type,
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::content::prompt::PromptMessage;

    struct TestServer;

    fn test_handler<'a>(
        _server: &'a TestServer,
        _ctx: ExecutionContext<'a>,
    ) -> ToolHandlerFuture<'a> {
        Box::pin(async move { Ok(ToolOutput::text("test")) })
    }

    fn test_prompt_handler<'a>(
        _server: &'a TestServer,
        _ctx: ExecutionContext<'a>,
    ) -> PromptHandlerFuture<'a> {
        Box::pin(async move {
            Ok(GetPromptResult {
                description: Some("test".into()),
                messages: vec![PromptMessage::user("test")],
            })
        })
    }

    #[test]
    fn test_router_creation() {
        let router: McpToolRouter<TestServer> = McpToolRouter::new();
        assert!(router.is_empty());
    }

    #[test]
    fn test_router_with_tool() {
        let info = tool_info("test_tool", Some("A test".into()), serde_json::json!({}));
        let router: McpToolRouter<TestServer> = McpToolRouter::new().with_tool(info, test_handler, None);

        assert_eq!(router.len(), 1);
        assert!(!router.is_empty());
    }

    #[test]
    fn test_router_list() {
        let info1 = tool_info("tool1", None, serde_json::json!({}));
        let info2 = tool_info("tool2", Some("desc".into()), serde_json::json!({}));

        let router: McpToolRouter<TestServer> = McpToolRouter::new()
            .with_tool(info1, test_handler, None)
            .with_tool(info2, test_handler, None);

        let list = router.list();
        assert_eq!(list.len(), 2);
    }

    #[test]
    fn test_router_debug() {
        let router: McpToolRouter<TestServer> = McpToolRouter::new();
        let debug = format!("{:?}", router);
        assert!(debug.contains("McpToolRouter"));
    }

    // Prompt router tests
    #[test]
    fn test_prompt_router_creation() {
        let router: McpPromptRouter<TestServer> = McpPromptRouter::new();
        assert!(router.is_empty());
    }

    #[test]
    fn test_prompt_router_with_prompt() {
        let info = prompt_info("test_prompt", Some("A test".into()));
        let router: McpPromptRouter<TestServer> =
            McpPromptRouter::new().with_prompt(info, test_prompt_handler, None);

        assert_eq!(router.len(), 1);
        assert!(!router.is_empty());
    }

    #[test]
    fn test_prompt_router_list() {
        let info1 = prompt_info("prompt1", None);
        let info2 = prompt_info("prompt2", Some("desc".into()));

        let router: McpPromptRouter<TestServer> = McpPromptRouter::new()
            .with_prompt(info1, test_prompt_handler, None)
            .with_prompt(info2, test_prompt_handler, None);

        let list = router.list();
        assert_eq!(list.len(), 2);
    }

    #[test]
    fn test_prompt_router_debug() {
        let router: McpPromptRouter<TestServer> = McpPromptRouter::new();
        let debug = format!("{:?}", router);
        assert!(debug.contains("McpPromptRouter"));
    }

    // Resource router tests
    fn test_resource_handler<'a>(
        _server: &'a TestServer,
        _ctx: ExecutionContext<'a>,
    ) -> ResourceHandlerFuture<'a> {
        Box::pin(async move { Ok(vec![ResourceContent::text("test:///uri", "content")]) })
    }

    #[test]
    fn test_resource_router_creation() {
        let router: McpResourceRouter<TestServer> = McpResourceRouter::new();
        assert!(router.is_empty());
    }

    #[test]
    fn test_resource_router_with_resource() {
        let info = resource_info("test:///resource", "test_resource", Some("A test".into()), None);
        let router: McpResourceRouter<TestServer> =
            McpResourceRouter::new().with_resource(info, test_resource_handler, None);

        assert_eq!(router.len(), 1);
        assert!(!router.is_empty());
    }

    #[test]
    fn test_resource_router_list() {
        let info1 = resource_info("test:///r1", "resource1", None, None);
        let info2 = resource_info("test:///r2", "resource2", Some("desc".into()), None);

        let router: McpResourceRouter<TestServer> = McpResourceRouter::new()
            .with_resource(info1, test_resource_handler, None)
            .with_resource(info2, test_resource_handler, None);

        let list = router.list();
        assert_eq!(list.len(), 2);
    }

    #[test]
    fn test_resource_router_debug() {
        let router: McpResourceRouter<TestServer> = McpResourceRouter::new();
        let debug = format!("{:?}", router);
        assert!(debug.contains("McpResourceRouter"));
    }

    // Resource template router tests
    fn test_template_handler<'a>(
        _server: &'a TestServer,
        _ctx: ExecutionContext<'a>,
    ) -> ResourceTemplateHandlerFuture<'a> {
        Box::pin(async move { Ok(vec![ResourceContent::text("file:///test", "content")]) })
    }

    #[test]
    fn test_template_router_creation() {
        let router: McpResourceTemplateRouter<TestServer> = McpResourceTemplateRouter::new();
        assert!(router.is_empty());
    }

    #[test]
    fn test_template_router_with_template() {
        let info = resource_template_info(
            "file:///{path}",
            "files",
            None,
            Some("Read files".into()),
            None,
        );
        let router: McpResourceTemplateRouter<TestServer> =
            McpResourceTemplateRouter::new().with_template(info, test_template_handler, None);

        assert_eq!(router.len(), 1);
        assert!(!router.is_empty());
    }

    #[test]
    fn test_template_router_list() {
        let info1 = resource_template_info("file:///{path}", "files", None, None, None);
        let info2 = resource_template_info("db:///{table}/{id}", "database", None, None, None);

        let router: McpResourceTemplateRouter<TestServer> = McpResourceTemplateRouter::new()
            .with_template(info1, test_template_handler, None)
            .with_template(info2, test_template_handler, None);

        let list = router.list();
        assert_eq!(list.len(), 2);
    }

    #[test]
    fn test_template_router_debug() {
        let router: McpResourceTemplateRouter<TestServer> = McpResourceTemplateRouter::new();
        let debug = format!("{:?}", router);
        assert!(debug.contains("McpResourceTemplateRouter"));
    }
}
