using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;
using System.IO.Pipelines;
using System.Reflection;

/// <summary>
/// Model Context Protocol (MCP) 相关的帮助方法
/// 统一管理 MCP 相关的 NuGet 包版本和常用功能
/// </summary>
public static class McpHelper
{
    /// <summary>
    /// 使用反射从指定类型中提取所有 MCP 工具
    /// </summary>
    public static List<McpServerTool> GetToolsForType<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(
        System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)] T>()
    {
        var tools = new List<McpServerTool>();
        var toolType = typeof(T);

        // 获取所有标记了 McpServerToolAttribute 的公共静态方法
        var methods = toolType.GetMethods(BindingFlags.Public | BindingFlags.Static)
            .Where(m => m.GetCustomAttributes(typeof(McpServerToolAttribute), false).Any());

        foreach (var method in methods)
        {
            try
            {
                var tool = McpServerTool.Create(method, target: null, new McpServerToolCreateOptions());
                tools.Add(tool);
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"添加工具失败 {toolType.Name}.{method.Name}: {ex.Message}", ex);
            }
        }

        return tools;
    }

    /// <summary>
    /// 创建并初始化 InMemory Transport 的 Server 和 Client
    /// </summary>
    /// <param name="tools">要注册的工具集合</param>
    /// <param name="serverOptions">Server 配置选项（可选）</param>
    /// <param name="loggerFactory">日志工厂（可选）</param>
    /// <returns>返回已连接的 Client 和运行中的 Server</returns>
    public static async Task<(McpClient Client, McpServer Server)> CreateInMemoryClientAndServerAsync(
        List<McpServerTool> tools,
        McpServerOptions? serverOptions = null,
        McpClientOptions? clientOptions = null,
        ILoggerFactory? loggerFactory = null)
    {
        // 步骤 1：创建两个 Pipe（双向管道）
        Pipe clientToServerPipe = new();
        Pipe serverToClientPipe = new();

        // 步骤 2：创建 Server，使用 StreamServerTransport
        var serverTransport = new StreamServerTransport(
            clientToServerPipe.Reader.AsStream(),
            serverToClientPipe.Writer.AsStream());

        var toolCollection = new McpServerPrimitiveCollection<McpServerTool>();

        tools.ForEach(toolCollection.Add);

        var options = serverOptions ?? new McpServerOptions();
        options.ToolCollection = toolCollection;

        var server = McpServer.Create(serverTransport, options);

        // 步骤 3：启动 Server（后台运行）
        _ = server.RunAsync();

        // 步骤 4：创建 Client，使用 StreamClientTransport
        var client = await McpClient.CreateAsync(
            new StreamClientTransport(
                clientToServerPipe.Writer.AsStream(),
                serverToClientPipe.Reader.AsStream()),
            clientOptions: clientOptions,
            loggerFactory: loggerFactory);

        return (client, server);
    }

}


public static class InMemoryMcpClientServerBuilder
{
    private static readonly Pipe ClientToServerPipe = new();
    private static readonly Pipe ServerToClientPipe = new();

    public static IMcpServerBuilder CreateMcpServerBuilder(Action<McpServerOptions>? options = null)
    {
        ServiceCollection sc = new();
        sc.AddLogging();
        var builder = sc.AddMcpServer(options)
            .WithStreamServerTransport(ClientToServerPipe.Reader.AsStream(), ServerToClientPipe.Writer.AsStream());

        return builder;
    }

    public static Task StartMcpServer(IMcpServerBuilder mcpServerBuilder)
    {
        var serviceProvider = mcpServerBuilder.Services.BuildServiceProvider();

        var server = serviceProvider.GetRequiredService<McpServer>();

        return server.RunAsync();
    }


    public static async Task<McpClient> CreateMcpClientForServer(McpClientOptions? clientOptions = null)
    {
        var loggerFactory = LoggerFactory.Create(loggingBuilder =>
        {
            loggingBuilder.AddConsole();
        });

        return await McpClient.CreateAsync(
            new StreamClientTransport(
                serverInput: ClientToServerPipe.Writer.AsStream(),
                ServerToClientPipe.Reader.AsStream(),
                loggerFactory),
            clientOptions: clientOptions,
            loggerFactory: loggerFactory);
    }
}


