/**
 * MCP 客户端
 * 管理与单个 MCP 服务器的连接
 */

import type {
  Transport,
  MCPServerConfig,
  MCPTool,
  MCPServerStatus,
  MCPServerStatusType,
  MCPToolCallResult,
  InitializeParams,
  InitializeResult,
  ListToolsResult,
  CallToolParams,
  CallToolResult,
  ServerCapabilities,
  MCPContent,
} from './types.js';
import { createTransport } from './transports/index.js';

/** MCP 协议版本 */
const PROTOCOL_VERSION = '2024-11-05';

/** 客户端信息 */
const CLIENT_INFO = {
  name: 'ai-terminal-assistant',
  version: '1.0.0',
};

/**
 * MCP 客户端类
 */
export class MCPClient {
  private transport: Transport;
  private serverCapabilities?: ServerCapabilities;
  private serverInfo?: { name: string; version: string };
  private tools: MCPTool[] = [];
  private _status: MCPServerStatusType = 'disconnected';
  private _error?: string;
  private lastConnected?: Date;

  constructor(
    private name: string,
    private config: MCPServerConfig
  ) {
    this.transport = createTransport(name, config);
  }

  /**
   * 连接到 MCP 服务器
   */
  async connect(): Promise<void> {
    if (this._status === 'connected') {
      return;
    }

    this._status = 'connecting';
    this._error = undefined;

    try {
      // 启动传输层
      await this.transport.start();

      // 监听连接关闭
      this.transport.onClose((error) => {
        this._status = 'disconnected';
        if (error) {
          this._error = error.message;
        }
      });

      // 监听服务器通知
      this.transport.onNotification((method, params) => {
        this.handleNotification(method, params);
      });

      // 初始化握手
      await this.initialize();

      // 获取工具列表
      await this.refreshTools();

      this._status = 'connected';
      this.lastConnected = new Date();
    } catch (error) {
      this._status = 'error';
      this._error = error instanceof Error ? error.message : String(error);
      throw error;
    }
  }

  /**
   * 断开连接
   */
  async disconnect(): Promise<void> {
    if (this._status === 'disconnected') {
      return;
    }

    try {
      await this.transport.close();
    } finally {
      this._status = 'disconnected';
      this.tools = [];
    }
  }

  /**
   * MCP 初始化握手
   */
  private async initialize(): Promise<void> {
    const params: InitializeParams = {
      protocolVersion: PROTOCOL_VERSION,
      capabilities: {
        roots: { listChanged: true },
      },
      clientInfo: CLIENT_INFO,
    };

    const result = (await this.transport.request(
      'initialize',
      params
    )) as InitializeResult;

    this.serverCapabilities = result.capabilities;
    this.serverInfo = result.serverInfo;

    // 发送 initialized 通知
    await this.transport.notify('notifications/initialized');
  }

  /**
   * 刷新工具列表
   */
  async refreshTools(): Promise<void> {
    const result = (await this.transport.request(
      'tools/list',
      {}
    )) as ListToolsResult;

    this.tools = result.tools.map((tool) => ({
      server: this.name,
      name: `${this.name}-${tool.name}`,
      originalName: tool.name,
      description: tool.description || '',
      inputSchema: tool.inputSchema,
      outputSchema: tool.outputSchema,
    }));
  }

  /**
   * 调用工具
   */
  async callTool(
    toolName: string,
    args: Record<string, unknown>
  ): Promise<MCPToolCallResult> {
    // 获取原始工具名
    const tool = this.tools.find((t) => t.name === toolName);
    if (!tool) {
      return {
        success: false,
        content: [{ type: 'text', text: `Tool not found: ${toolName}` }],
        isError: true,
      };
    }

    try {
      const params: CallToolParams = {
        name: tool.originalName,
        arguments: args,
      };

      const result = (await this.transport.request(
        'tools/call',
        params
      )) as CallToolResult;

      return {
        success: !result.isError,
        content: result.content as MCPContent[],
        isError: result.isError,
      };
    } catch (error) {
      return {
        success: false,
        content: [
          {
            type: 'text',
            text: error instanceof Error ? error.message : String(error),
          },
        ],
        isError: true,
      };
    }
  }

  /**
   * 获取工具列表
   */
  getTools(): MCPTool[] {
    return [...this.tools];
  }

  /**
   * 获取状态
   */
  getStatus(): MCPServerStatus {
    return {
      name: this.name,
      type: this.config.type,
      status: this._status,
      toolCount: this.tools.length,
      error: this._error,
      lastConnected: this.lastConnected,
    };
  }

  /**
   * 获取服务器信息
   */
  getServerInfo(): { name: string; version: string } | undefined {
    return this.serverInfo;
  }

  /**
   * 获取服务器能力
   */
  getServerCapabilities(): ServerCapabilities | undefined {
    return this.serverCapabilities;
  }

  /**
   * 处理服务器通知
   */
  private handleNotification(method: string, params: unknown): void {
    switch (method) {
      case 'notifications/tools/list_changed':
        // 工具列表变化，刷新
        this.refreshTools().catch((error) => {
          console.error(
            `[MCP:${this.name}] Failed to refresh tools:`,
            error
          );
        });
        break;

      case 'notifications/resources/list_changed':
        // 资源列表变化（暂不处理）
        break;

      case 'notifications/prompts/list_changed':
        // 提示列表变化（暂不处理）
        break;

      default:
        console.debug(
          `[MCP:${this.name}] Unknown notification: ${method}`,
          params
        );
    }
  }
}
