/**
 * MCPExecutor MCP 执行器
 * 使用 @ai-sdk/mcp 连接到 MCP 服务器
 */

const { Plugin } = require('../core/plugin-base');
const { spawn } = require('child_process');
const fs = require('fs');
const path = require('path');
const { z } = require('zod');
const { createMCPClient } = require('@ai-sdk/mcp');
const { StdioClientTransport } = require('@modelcontextprotocol/sdk/client/stdio.js');
const { zodSchemaToMarkdown } = require('@chnak/zod-to-markdown');
const { logger } = require('../utils/logger');

const log = logger.child('MCPExecutor');

/**
 * MCP 客户端包装器
 */
class MCPClientWrapper {
  constructor(options = {}) {
    this.serverName = options.serverName || 'unknown';
    this.command = options.command;
    this.args = options.args || [];
    this.env = options.env || {};
    this.timeout = options.timeout || 30000;
    this.priority = 11;
    this.client = null;
    this.connected = false;
    this.tools = [];
  }

  /**
   * 连接 MCP 服务器
   */
  async connect() {
    if (this.connected) return;

    try {
      // 动态导入 @ai-sdk/mcp
      let createMCPClient;

      try {
        const mcpModule = require('@ai-sdk/mcp');
        createMCPClient = mcpModule.createMCPClient || mcpModule.experimental_createMCPClient;
      } catch (err) {
        throw new Error('@ai-sdk/mcp not installed. Please run: npm install @ai-sdk/mcp');
      }

      if (!createMCPClient) {
        throw new Error('createMCPClient not available');
      }

      // 解析命令路径
      const { which, shellResolve } = this._resolveCommand(this.command);

      // 使用正确的子路径导入
      try {
        const { Experimental_StdioMCPTransport } = require('@ai-sdk/mcp/mcp-stdio');
        const transport = new Experimental_StdioMCPTransport({
          command: which || this.command,
          args: shellResolve ? [shellResolve, ...this.args] : this.args,
          env: { ...process.env, ...this.env },
        });
        this.client = await createMCPClient({ transport });
      } catch (transportErr) {
        log.error(` Transport error:`, transportErr.message);
        throw transportErr;
      }

      // 获取工具列表
      // 新版 API: tools() 是函数
      if (typeof this.client.tools === 'function') {
        const toolsObject = await this.client.tools();
        this.tools = Object.entries(toolsObject)
          .filter(([, tool]) => tool != null)
          .map(([name, tool]) => ({ ...tool, name }));
      } else if (this.client.tools && typeof this.client.tools.list === 'function') {
        // 旧版 API: tools.list()
        const listResult = await this.client.tools.list();
        this.tools = listResult.tools || [];
      }

      this.connected = true;
      log.info(` Connected to ${this.serverName} with ${this.tools.length} tools`);
    } catch (err) {
      log.error(` Failed to connect to ${this.serverName}:`, err.message);
      // 不抛出错误，让框架继续运行
    }
  }

  /**
   * 解析命令路径
   */
  _resolveCommand(cmd) {
    const isWindows = process.platform === 'win32';
    const ext = isWindows ? '.cmd' : '';
    const withExt = cmd + ext;

    // 检查命令是否直接存在
    try {
      const result = spawn.sync(withExt, ['--version'], {
        stdio: 'ignore',
        timeout: 2000,
      });
      if (result.error?.code !== 'ENOENT') {
        return { which: withExt, shellResolve: null };
      }
    } catch (e) {
      // ignore
    }

    // 尝试解析 npm 全局 bin 目录
    const globalCommands = isWindows
      ? [
          path.join(process.env.APPDATA || '', 'npm', withExt),
          path.join(process.env.PROGRAMDATA || 'C:\\ProgramData', 'npm', withExt),
        ]
      : ['/usr/local/bin/' + cmd, '/usr/bin/' + cmd];

    for (const cmdPath of globalCommands) {
      try {
        if (fs.existsSync(cmdPath)) {
          return { which: cmdPath, shellResolve: null };
        }
      } catch (e) {
        // ignore
      }
    }

    return { which: cmd, shellResolve: null };
  }

  /**
   * 调用工具
   */
  async callTool(toolName, args) {
    if (!this.connected) {
      await this.connect();
    }

    if (!this.client) {
      throw new Error('MCP client not initialized');
    }

    try {
      // 新版 API: tools() 返回对象
      let toolsObject;
      if (typeof this.client.tools === 'function') {
        toolsObject = await this.client.tools();
      } else if (this.client.tools && typeof this.client.tools.list === 'function') {
        // 旧版 API
        const listResult = await this.client.tools.list();
        toolsObject = listResult.tools || {};
      } else {
        throw new Error('Cannot get tools from MCP client');
      }

      const tool = toolsObject[toolName];
      if (!tool) {
        throw new Error(`Tool not found: ${toolName}`);
      }

      const result = await tool.execute(args);
      return result;
    } catch (err) {
      log.error(` Tool call failed: ${toolName}:`, err.message);
      throw err;
    }
  }

  /**
   * 断开连接
   */
  async disconnect() {
    if (this.client) {
      try {
        await this.client.destroy();
      } catch (e) {
        // ignore
      }
      this.client = null;
      this.connected = false;
      this.tools = [];
    }
  }
}

/**
 * MCPExecutorPlugin
 */
class MCPExecutorPlugin extends Plugin {
  constructor(config = {}) {
    super();
    this.name = 'mcp';
    this.version = '1.0.0';
    this.description = 'MCP (Model Context Protocol) 执行器';
    this.priority = 11;
    this.system = true;

    this._framework = null;
    // serverName -> { client, tools: [{ name, description, inputSchema }], toolObjects: { toolName: actualTool } }
    this._clients = new Map();
    // 保存服务器配置，用于重新启用
    this._serverConfigs = new Map();
    this._config = config;
    // 注册的工具对象（extension-executor 会扫描这个）
    // 格式: { 'server_toolname': { name, description, inputSchema, execute } }
    this.tools = {};
  }

  install(framework) {
    this._framework = framework;
    return this;
  }

  async start(framework) {
    // 先连接所有 MCP 服务器
    if (this._config.servers) {
      for (const serverConfig of this._config.servers) {
        if (serverConfig.enabled === false) {
          log.info(` Skipping disabled server: ${serverConfig.name}`);
          // 保存完整配置，以便后续动态启用
          this._serverConfigs.set(serverConfig.name, { ...serverConfig });
          continue;
        }
        await this.addServer(serverConfig);
      }
    }

    // 注册 mcp_tool_schema 工具 - 直接返回可用的调用示例
    framework.registerTool({
      name: 'mcp_tool_schema',
      description: '查询工具的调用示例，直接复制 example 或 fullExample 字段使用',
      inputSchema: z.object({
        server: z.string().describe('MCP 服务器名称'),
        tool: z.string().describe('工具名称'),
      }),
      execute: async (args) => {
        const { server, tool } = args;
        const clientInfo = this._clients.get(server);
        if (!clientInfo) {
          return { success: false, error: `MCP server '${server}' not found` };
        }

        const toolInfo = clientInfo.tools.find((t) => t.name === tool);
        if (!toolInfo) {
          return { success: false, error: `Tool '${tool}' not found` };
        }

        const schema = this._extractSchema(toolInfo.inputSchema);
        const props = schema.properties || {};
        const required = schema.required || [];

        // 生成示例值的辅助函数
        const generateExample = (prop, depth = 0) => {
          if (!prop) return null;
          const type = prop.type || (prop.properties ? 'object' : 'string');

          if (type === 'string') {
            return prop.description?.split('.')[0] || `${prop.title || '值'}`;
          } else if (type === 'number' || type === 'integer') {
            return prop.default || 0;
          } else if (type === 'boolean') {
            return false;
          } else if (type === 'array') {
            // 数组类型：提供单个示例元素
            if (prop.items) {
              const itemExample = generateExample(prop.items, depth + 1);
              return depth === 0 ? [itemExample] : itemExample;
            }
            return ['示例'];
          } else if (type === 'object' || prop.properties) {
            // 对象类型：递归生成嵌套结构
            const obj = {};
            const objProps = prop.properties || {};
            for (const [key, val] of Object.entries(objProps)) {
              obj[key] = generateExample(val, depth + 1);
            }
            return obj;
          }
          return null;
        };

        // 生成可直接使用的调用示例
        const exampleArgs = {};
        for (const key of required) {
          const prop = props[key];
          if (prop) {
            exampleArgs[key] = generateExample(prop);
          }
        }

        return {
          success: true,
          result: {
            name: toolInfo.name,
            description: toolInfo.description,
            required,
            // 各参数的详细说明
            parameters: Object.fromEntries(
              required.map((key) => [
                key,
                {
                  type: props[key]?.type || 'string',
                  description: props[key]?.description || '',
                  example: generateExample(props[key]),
                },
              ])
            ),
            // 直接返回可以复制使用的调用示例
            example: JSON.stringify(exampleArgs, null, 2),
            fullExample: `mcp_call({ server: "${server}", tool: "${tool}", args_json: ${JSON.stringify(JSON.stringify(exampleArgs))} })`,
          },
        };
      },
    });

    // 注册 mcp_call 工具
    framework.registerTool({
      name: 'mcp_call',
      description:
        '调用 MCP 服务器工具。args_json 是包含实际参数的 JSON 字符串，如 \'{"url": "https://news.baidu.com"}\'',
      inputSchema: z.object({
        server: z.string().describe('MCP 服务器名称'),
        tool: z.string().describe('工具名称'),
        args_json: z
          .string()
          .describe('参数 JSON 字符串，如 {"url": "https://..."}，fetch 工具必填 url'),
      }),
      execute: async (args) => {
        const { server, tool, args_json } = args;
        log.info(` mcp_call: server=${server}, tool=${tool}, args_json=${args_json}`);

        const clientInfo = this._clients.get(server);
        if (!clientInfo) {
          return { success: false, error: `MCP server '${server}' not found` };
        }

        // 解析 args_json
        let finalArgs = {};
        if (args_json) {
          try {
            finalArgs = JSON.parse(args_json);
          } catch (e) {
            return { success: false, error: `args_json 格式错误，不是有效的 JSON: ${args_json}` };
          }
        }

        // 检查参数是否为空
        if (!finalArgs || Object.keys(finalArgs).length === 0) {
          const toolInfo = clientInfo.tools.find((t) => t.name === tool);
          if (toolInfo) {
            const schema = this._extractSchema(toolInfo.inputSchema);
            const required = schema.required || [];
            return {
              success: false,
              error: `参数为空！必须提供: ${required.join(', ')}`,
              hint: `正确格式: {"${required[0]}": "具体值"}`,
            };
          }
        }

        try {
          // 使用缓存的工具对象
          const mcpTool = clientInfo.toolObjects?.[tool];
          if (!mcpTool) {
            return { success: false, error: `Tool '${tool}' not found on server '${server}'` };
          }

          // 触发 MCP 工具开始事件
          const mcpToolName = `${server}:${tool}`;
          framework.emit('tool:call', {
            name: mcpToolName,
            args: finalArgs,
            source: 'mcp',
          });
          framework.emit('tool-call', {
            name: mcpToolName,
            args: finalArgs,
            source: 'mcp',
          });

          const execResult = await mcpTool.execute(finalArgs);

          // 触发 MCP 工具完成事件
          framework.emit('tool:result', {
            name: mcpToolName,
            args: finalArgs,
            result: execResult,
            source: 'mcp',
          });

          return { success: true, result: execResult };
        } catch (err) {
          log.error(` Tool '${tool}' failed:`, err.message);

          // 触发 MCP 工具错误事件
          const mcpToolName = `${server}:${tool}`;
          framework.emit('tool:error', {
            name: mcpToolName,
            args: finalArgs,
            error: err.message,
            source: 'mcp',
          });

          return { success: false, error: err.message };
        }
      },
    });

    // 注册 mcp_list_servers 工具
    framework.registerTool({
      name: 'mcp_list_servers',
      description: '列出已连接的 MCP 服务器及其工具',
      inputSchema: z.object({}),
      execute: async () => {
        const servers = [];
        // 已连接的服务器
        for (const [name, info] of this._clients) {
          servers.push({
            name,
            enabled: true,
            connected: true,
            tools: info.tools.map((t) => ({ name: t.name, description: t.description })),
          });
        }
        // 未连接的服务器（配置中存在但未启用）
        for (const [name, config] of this._serverConfigs) {
          if (!this._clients.has(name)) {
            servers.push({
              name,
              enabled: false,
              connected: false,
              tools: [],
            });
          }
        }
        return { success: true, servers };
      },
    });

    // 注册 mcp_reload 工具
    framework.registerTool({
      name: 'mcp_reload',
      description:
        '重新加载 MCP 服务器配置。当配置文件 .agent/mcp_config.json 修改后使用此工具重载配置',
      inputSchema: z.object({}),
      execute: async () => {
        log.info(' mcp_reload called');
        try {
          const fs = require('fs');
          const path = require('path');
          const configPath = path.resolve('.agent/mcp_config.json');

          log.info(' Reading config from:', configPath);
          if (!fs.existsSync(configPath)) {
            return { success: false, error: `配置文件不存在: ${configPath}` };
          }

          const configContent = fs.readFileSync(configPath, 'utf8');
          const config = JSON.parse(configContent);
          log.info(' Config loaded, reloading...');

          await this.reloadConfig(config);
          log.info(' Reload complete');

          return {
            success: true,
            message: 'MCP 配置已重载',
            servers: Object.keys(config.mcpServers || {}),
          };
        } catch (err) {
          log.error(' Reload error:', err);
          return { success: false, error: `重载失败: ${err.message}` };
        }
      },
    });

    // 注册 mcp_set_enabled 工具 - 动态开启/关闭 MCP 服务器
    framework.registerTool({
      name: 'mcp_set_enabled',
      description: '动态开启或关闭某个 MCP 服务器',
      inputSchema: z.object({
        server: z.string().describe('MCP 服务器名称'),
        enabled: z.boolean().describe('true=开启，false=关闭'),
      }),
      execute: async (args) => {
        const { server, enabled } = args;
        const clientInfo = this._clients.get(server);
        const serverConfig = this._serverConfigs.get(server);

        if (enabled) {
          // 启用服务器
          if (clientInfo && clientInfo.enabled) {
            return { success: true, message: `MCP 服务器 '${server}' 已经是开启状态` };
          }
          // 如果服务器从未连接过，也检查配置中的 enabled 状态
          if (!clientInfo && serverConfig && serverConfig.enabled === false) {
            // 服务器是被禁用的，可以尝试启用
          }
          log.info(
            `[MCP] Enabling server: ${server}, clientInfo=${!!clientInfo}, serverConfig.enabled=${serverConfig?.enabled}`
          );
          try {
            if (serverConfig) {
              const result = await this.addServer({ ...serverConfig, enabled: true });
              log.info(`[MCP] addServer result:`, JSON.stringify(result));
              if (!result || result.success === false) {
                this._refreshAllAgentsMCPPrompt(this._framework);
                return result;
              }
              // 保存 enabled 状态到配置文件
              await this._saveMCPServerEnabled(server, true);
              this._refreshAllAgentsMCPPrompt(this._framework);
              return { success: true, message: `MCP 服务器 '${server}' 已开启` };
            } else {
              return { success: false, error: '服务器配置不存在，需要重载配置' };
            }
          } catch (err) {
            log.error(`[MCP] Enabling failed:`, err.message);
            return { success: false, error: `开启失败: ${err.message}` };
          }
        } else {
          // 禁用服务器
          if (!clientInfo) {
            return { success: false, error: `MCP server '${server}' not found` };
          }
          log.info(` Disabling MCP server: ${server}`);
          try {
            clientInfo.client.close?.();
          } catch (e) {}
          // 从 clients 中移除
          this._clients.delete(server);
          // 移除该服务器注册的工具
          for (const key of Object.keys(this.tools)) {
            if (key.startsWith(`${server}_`)) {
              delete this.tools[key];
            }
          }
          // 保存 enabled 状态到配置文件
          await this._saveMCPServerEnabled(server, false);
          this._refreshAllAgentsMCPPrompt(this._framework);
          return { success: true, message: `MCP 服务器 '${server}' 已关闭` };
        }

        return { success: true, message: `MCP 服务器 '${server}' 状态未变化` };
      },
    });

    // 监听 agent 创建事件，附加 MCP 信息到系统提示词
    framework.on('agent:created', (agent) => {
      if (!this._mainAgent) {
        this._mainAgent = agent;
      }
      this._refreshAgentMCPPrompt(agent);
    });

    // 等待框架就绪后，刷新所有已有 agent 的 MCP 提示词
    if (framework._ready) {
      this._refreshAllAgentsMCPPrompt(framework);
    } else {
      framework.once('framework:ready', () => {
        this._refreshAllAgentsMCPPrompt(framework);
      });
    }

    return this;
  }

  /**
   * 刷新所有 agent 的 MCP 提示词（包括子 agent）
   */
  _refreshAllAgentsMCPPrompt(framework) {
    const visited = new Set();

    const traverse = (agent) => {
      if (!agent || visited.has(agent)) return;
      visited.add(agent);
      //this._refreshAgentMCPPrompt(agent);

      // 递归处理子 agent
      const subAgents = agent.getSubAgents?.() || agent._subAgents || new Map();
      for (const [name, subAgentInfo] of subAgents) {
        traverse(subAgentInfo.agent);
      }
    };

    for (const agent of framework._agents || []) {
      traverse(agent);
    }
  }

  /**
   * 刷新单个 agent 的 MCP 提示词
   */
  _refreshAgentMCPPrompt(agent) {
    // 检查是否已刷新过（通过检查系统提示词是否已包含 MCP 描述）
    const existingPrompt = agent._originalPrompt || '';
    if (existingPrompt.includes('【MCP Servers】')) {
      return;
    }

    // const mcpDesc = this._buildMCPServersDescription();
    // if (!mcpDesc) return;

    // 将 MCP 描述追加到系统提示词
    //agent.setSystemPrompt(existingPrompt + '\n\n' + mcpDesc);
  }

  /**
   * 从 inputSchema 中提取实际 schema
   */
  _extractSchema(inputSchema) {
    if (!inputSchema) return {};
    // 处理 {jsonSchema: {...}} 格式
    if (inputSchema.jsonSchema) return inputSchema.jsonSchema;
    // 处理 {inputSchema: {...}} 格式 (某些 MCP 服务器返回这种格式)
    if (inputSchema.inputSchema) return inputSchema.inputSchema;
    // 处理直接是 schema 的格式
    return inputSchema;
  }

  /**
   * 构建 MCP 服务器描述
   */
  _buildMCPServersDescription() {
    if (this._clients.size === 0) {
      return '';
    }

    let desc = '## 【MCP Servers】 工具合集\n\n';
    desc += 'MCP 服务器工具已注册为 `服务器_工具名` 格式（如 github_search）。\n';
    desc += '通过 `ext_call` 调用：\n\n';

    for (const [serverName, info] of this._clients) {
      desc += `### ${serverName}\n\n`;
      for (const tool of info.tools) {
        const fullName = `${serverName}_${tool.name}`;
        desc += `- **${fullName}**: ${tool.description || '无描述'}\n`;

        // 使用 zodSchemaToMarkdown 生成参数文档
        const rawSchema = tool.inputSchema;
        const schema = this._extractSchema(rawSchema);
        if (schema) {
          try {
            let schemaResult = null;
            let zodSchemaForFallback = null; // 保存 Zod schema 供 fallback 使用
            // 检查是否是 Zod schema (有 shape 方法或 _def 属性)
            const isZodSchema =
              typeof schema.shape === 'function' || (schema._def && schema._def.typeName);
            if (isZodSchema) {
              // Zod schema 直接转换
              schemaResult = zodSchemaToMarkdown(schema);
              zodSchemaForFallback = schema;
            } else if (schema.jsonSchema) {
              // JSON Schema 格式，尝试转换为 Zod schema
              const zodSchema = this._jsonSchemaToZod(schema.jsonSchema || schema);
              if (zodSchema) {
                schemaResult = zodSchemaToMarkdown(zodSchema);
                zodSchemaForFallback = zodSchema;
              }
            } else if (schema.properties) {
              // 已经是对象格式
              const zodSchema = this._jsonSchemaToZod(schema);
              if (zodSchema) {
                schemaResult = zodSchemaToMarkdown(zodSchema);
                zodSchemaForFallback = zodSchema;
              }
            }

            // 检查是否包含未解析的原始 Zod 类型名或只有类型信息没有参数
            if (schemaResult) {
              const hasUnparsedTypes = /\|.*\bZod\w+\b.*\|/.test(schemaResult);
              // 检查是否只有类型信息而没有实际参数（如 "Type: Object" 或 "Type: ZodAny"）
              const hasOnlyType =
                /^-\s+\w+:\s+.+\n?$/.test(schemaResult.trim()) && !schemaResult.includes('`');
              if (hasUnparsedTypes || hasOnlyType) {
                // zodSchemaToMarkdown 未正确解析，使用 fallback
                desc += this._fallbackParamsDesc(zodSchemaForFallback || schema);
              } else {
                desc += `**参数:**\n\n`;
                desc += schemaResult + '\n\n';
              }
            }
          } catch (e) {
            // 如果转换失败，使用 fallback
            try {
              desc += this._fallbackParamsDesc(zodSchemaForFallback || schema);
            } catch (e2) {
              // fallback 也失败，忽略参数描述
            }
          }
        }
      }
      desc += '\n';
    }

    desc += '**调用格式:**\n';
    desc += '```\next_call({ plugin: "mcp", tool: "服务器_工具名", args: {参数} })\n';
    desc += '```\n';
    return desc.trim();
  }

  _bindMcpParamsDesc(rawSchema) {
    let desc = '';
    const schema = this._extractSchema(rawSchema);
    if (!schema) return desc;
    try {
      let schemaResult = null;
      let zodSchemaForFallback = null; // 保存 Zod schema 供 fallback 使用
      // 检查是否是 Zod schema (有 shape 方法或 _def 属性)
      const isZodSchema =
        typeof schema.shape === 'function' || (schema._def && schema._def.typeName);
      if (isZodSchema) {
        // Zod schema 直接转换
        schemaResult = zodSchemaToMarkdown(schema);
        zodSchemaForFallback = schema;
      } else if (schema.jsonSchema) {
        // JSON Schema 格式，尝试转换为 Zod schema
        const zodSchema = this._jsonSchemaToZod(schema.jsonSchema || schema);
        if (zodSchema) {
          schemaResult = zodSchemaToMarkdown(zodSchema);
          zodSchemaForFallback = zodSchema;
        }
      } else if (schema.properties) {
        // 已经是对象格式
        const zodSchema = this._jsonSchemaToZod(schema);
        if (zodSchema) {
          schemaResult = zodSchemaToMarkdown(zodSchema);
          zodSchemaForFallback = zodSchema;
        }
      }

      // 检查是否包含未解析的原始 Zod 类型名或只有类型信息没有参数
      if (schemaResult) {
        const hasUnparsedTypes = /\|.*\bZod\w+\b.*\|/.test(schemaResult);
        // 检查是否只有类型信息而没有实际参数（如 "Type: Object" 或 "Type: ZodAny"）
        const hasOnlyType =
          /^-\s+\w+:\s+.+\n?$/.test(schemaResult.trim()) && !schemaResult.includes('`');
        if (hasUnparsedTypes || hasOnlyType) {
          // zodSchemaToMarkdown 未正确解析，使用 fallback
          desc += this._fallbackParamsDesc(zodSchemaForFallback || schema);
        } else {
          desc += `**参数:**\n\n`;
          desc += schemaResult + '\n\n';
        }
      }
    } catch (e) {
      // 如果转换失败，使用 fallback
      try {
        desc += this._fallbackParamsDesc(zodSchemaForFallback || schema);
      } catch (e2) {
        // fallback 也失败，忽略参数描述
      }
    }
    return desc;
  }

  /**
   * 将 JSON Schema 转换为 Zod schema
   */
  _jsonSchemaToZod(jsonSchema) {
    if (!jsonSchema || !jsonSchema.properties) {
      return null;
    }

    try {
      const shape = {};
      const properties = jsonSchema.properties;
      const required = jsonSchema.required || [];

      for (const [key, prop] of Object.entries(properties)) {
        shape[key] = this._jsonSchemaPropToZod(prop, required.includes(key));
      }

      return z.object(shape);
    } catch (e) {
      return null;
    }
  }

  /**
   * 将 JSON Schema 属性转换为 Zod 类型
   */
  _jsonSchemaPropToZod(prop, isRequired) {
    if (prop.$ref) {
      return isRequired ? z.any() : z.any().optional();
    }

    if (prop.enum) {
      let zodType = z.string().enum(prop.enum);
      if (prop.nullable) {
        zodType = zodType.nullable();
      }
      return isRequired ? zodType : zodType.optional();
    }

    const type = prop.type || 'string';

    switch (type) {
      case 'string':
        return isRequired ? z.string() : z.string().optional();
      case 'number':
      case 'integer':
        return isRequired ? z.number() : z.number().optional();
      case 'boolean':
        return isRequired ? z.boolean() : z.boolean().optional();
      case 'array':
        return isRequired ? z.array(z.any()) : z.array(z.any()).optional();
      case 'object':
        if (prop.properties) {
          const nested = {};
          for (const [k, v] of Object.entries(prop.properties)) {
            nested[k] = this._jsonSchemaPropToZod(v, prop.required?.includes(k) || false);
          }
          return isRequired ? z.object(nested) : z.object(nested).optional();
        }
        return isRequired ? z.record(z.any()) : z.record(z.any()).optional();
      default:
        return isRequired ? z.any() : z.any().optional();
    }
  }

  /**
   * 回退的参数描述（当 zodSchemaToMarkdown 失败时）
   */
  _fallbackParamsDesc(schema) {
    // 优先尝试 JSON Schema 格式
    const props = schema.properties || {};
    const required = schema.required || [];

    if (Object.keys(props).length > 0) {
      let desc = '**参数:**\n\n';
      for (const [key, prop] of Object.entries(props)) {
        const isRequired = required.includes(key);
        const type = prop.type || 'any';
        const desc_text = prop.description || '';
        desc += `- \`${key}\`${isRequired ? ' (必填)' : ''}: ${type} ${desc_text}\n`;
      }
      return desc + '\n';
    }

    // 尝试 Zod schema 格式
    if (typeof schema.shape === 'function' || (schema._def && schema._def.shape)) {
      const shape = typeof schema.shape === 'function' ? schema.shape() : schema._def.shape();
      if (shape && typeof shape === 'object') {
        let desc = '**参数:**\n\n';
        for (const [key, field] of Object.entries(shape)) {
          const typeInfo = this._extractZodFieldType(field);
          const isOptional = typeInfo.isOptional ? ' (可选)' : ' (必填)';
          desc += `- \`${key}\`${isOptional}: ${typeInfo.type}\n`;
        }
        return desc + '\n';
      }
    }

    return '';
  }

  /**
   * 从 Zod schema 字段提取类型信息
   */
  _extractZodFieldType(field) {
    if (!field) {
      return { type: 'unknown', isOptional: false, description: '' };
    }

    const typeName = field._def?.typeName || field.constructor?.name || '';
    const description = field.description || field._def?.description || '';

    switch (typeName) {
      case 'ZodOptional': {
        const inner = field._def?.innerType;
        if (!inner) return { type: 'optional', isOptional: true, description };
        return this._extractZodFieldType(inner);
      }
      case 'ZodArray': {
        const inner = field._def?.type;
        if (!inner) return { type: 'array', isOptional: false, description };
        const innerInfo = this._extractZodFieldType(inner);
        return { type: `${innerInfo.type}[]`, isOptional: false, description };
      }
      case 'ZodObject': {
        const shapeFn = field._def?.shape;
        if (typeof shapeFn !== 'function')
          return { type: 'object', isOptional: false, description };
        const shape = shapeFn();
        if (!shape) return { type: 'object', isOptional: false, description };
        const props = Object.keys(shape).join(', ');
        return { type: `object{${props}}`, isOptional: false, description };
      }
      case 'ZodString':
        return { type: 'string', isOptional: false, description };
      case 'ZodNumber':
        return { type: 'number', isOptional: false, description };
      case 'ZodBoolean':
        return { type: 'boolean', isOptional: false, description };
      case 'ZodEnum': {
        const values = field._def?.values;
        if (!values) return { type: 'enum', isOptional: false, description };
        return {
          type: values.map((v) => `"${v}"`).join(' | '),
          isOptional: false,
          description,
        };
      }
      case 'ZodUnion': {
        const options = field._def?.options;
        if (!options) return { type: 'union', isOptional: false, description };
        const types = options.map((opt) => this._extractZodFieldType(opt).type);
        return { type: `union(${types.join(' | ')})`, isOptional: false, description };
      }
      case 'ZodLiteral':
        return { type: JSON.stringify(field._def?.value), isOptional: false, description };
      case 'ZodRecord': {
        const keyType = this._extractZodFieldType(field._def?.keyType);
        const valueType = this._extractZodFieldType(field._def?.valueType);
        return {
          type: `record<${keyType?.type || 'any'}, ${valueType?.type || 'any'}>`,
          isOptional: false,
          description,
        };
      }
      case 'ZodMap': {
        const keyType = this._extractZodFieldType(field._def?.keyType);
        const valueType = this._extractZodFieldType(field._def?.valueType);
        return {
          type: `map<${keyType?.type || 'any'}, ${valueType?.type || 'any'}>`,
          isOptional: false,
          description,
        };
      }
      case 'ZodSet': {
        const valueType = this._extractZodFieldType(field._def?.valueType);
        return { type: `set<${valueType?.type || 'any'}>`, isOptional: false, description };
      }
      case 'ZodAny':
        return { type: 'any', isOptional: false, description };
      case 'ZodUnknown':
        return { type: 'unknown', isOptional: false, description };
      case 'ZodNever':
        return { type: 'never', isOptional: false, description };
      case 'ZodNull':
        return { type: 'null', isOptional: false, description };
      case 'ZodUndefined':
        return { type: 'undefined', isOptional: false, description };
      case 'ZodDate':
        return { type: 'date', isOptional: false, description };
      case 'ZodBigInt':
        return { type: 'bigint', isOptional: false, description };
      case 'ZodFunction':
        return { type: 'function', isOptional: false, description };
      case 'ZodLazy':
        return { type: 'lazy', isOptional: false, description };
      case 'ZodNativeEnum':
        return { type: 'nativeEnum', isOptional: false, description };
      case 'ZodDefault': {
        const inner = field._def?.innerType;
        if (!inner) return { type: 'default', isOptional: false, description };
        const innerInfo = this._extractZodFieldType(inner);
        return { type: innerInfo.type, isOptional: false, description };
      }
      case 'ZodEffects':
        return { type: 'effects', isOptional: false, description };
      case 'ZodPipeline':
        return { type: 'pipeline', isOptional: false, description };
      default:
        return {
          type: typeName.replace('Zod', '').toLowerCase() || 'any',
          isOptional: false,
          description,
        };
    }
  }

  _getParentAgent() {
    // 优先返回已缓存的主 agent
    if (this._mainAgent) {
      return this._mainAgent;
    }

    // 尝试从 framework 获取
    if (this._framework._mainAgent) {
      this._mainAgent = this._framework._mainAgent;
      return this._mainAgent;
    }

    // 查找最后一个创建的 agent 作为父 agent
    const agents = this._framework._agents || [];
    if (agents.length > 0) {
      this._mainAgent = agents[agents.length - 1];
      return this._mainAgent;
    }

    return null;
  }

  /**
   * 带超时的 Promise
   */
  _withTimeout(promise, ms, name) {
    return Promise.race([
      promise,
      new Promise((_, reject) =>
        setTimeout(() => reject(new Error(`${name} timeout (${ms}ms)`)), ms)
      ),
    ]);
  }

  /**
   * 添加 MCP 服务器
   */
  async addServer(config) {
    const {
      name,
      command,
      args = [],
      env,
      url,
      type,
      headers = {},
      authProvider,
      enabled,
    } = config;
    log.info(
      `[MCP] addServer called: ${name}, enabled=${enabled}, hasClient=${this._clients.has(name)}`
    );

    if (this._clients.has(name)) {
      log.warn(` Server '${name}' already exists, skipping`);
      return { success: false, error: `Server '${name}' already connected` };
    }

    // 如果 enabled === false，跳过连接（用于 mcp_set_enabled 禁用后再开启的场景）
    if (enabled === false) {
      log.info(` Server '${name}' is disabled, skipping connection`);
      return { success: false, error: `Server '${name}' is disabled` };
    }

    // 保存配置，用于重新启用
    this._serverConfigs.set(name, {
      name,
      command,
      args,
      env,
      url,
      type,
      headers,
      authProvider,
      enabled,
    });
    log.info(` Connecting to ${name}...`);
    let client;
    try {
      if (['sse', 'http'].includes(type)) {
        client = await this._withTimeout(
          createMCPClient({
            transport: {
              type: type,
              url: url,
              headers: headers,
              authProvider: authProvider,
              redirect: 'error',
              env: env,
            },
          }),
          10000,
          `createMCPClient ${name}`
        );
      } else {
        client = await this._withTimeout(
          createMCPClient({
            transport: new StdioClientTransport({
              command: command,
              args: args,
              env: env,
            }),
          }),
          10000,
          `createMCPClient ${name}`
        );
      }
    } catch (err) {
      log.error(` Failed to create client '${name}':`, err.message);
      return { success: false, error: `创建客户端失败: ${err.message}` };
    }

    // 获取 MCP 服务器的工具列表
    let mcpTools;
    try {
      mcpTools = await this._withTimeout(client.tools(), 10000, `client.tools ${name}`);
    } catch (err) {
      log.error(` Failed to get tools from '${name}':`, err.message);
      client.close?.();
      return { success: false, error: `获取工具列表失败: ${err.message}` };
    }

    // 提取工具信息和实际工具对象
    const toolsInfo = [];
    const toolObjects = {}; // 缓存实际工具对象
    if (mcpTools && typeof mcpTools === 'object') {
      for (const [toolName, tool] of Object.entries(mcpTools)) {
        if (!tool) continue;
        toolObjects[toolName] = tool; // 保存实际工具对象
        toolsInfo.push({
          name: toolName,
          description: tool.description || '',
          inputSchema: tool.inputSchema || {},
        });

        // 注册为 server_toolname 格式，供 ext_call 使用
        const registeredName = `${name}_${toolName}`;
        this.tools[registeredName] = {
          name: registeredName,
          description: `[${name}] ${tool.description || ''}`,
          inputSchema: tool.inputSchema || {},
          execute: async (args) => {
            // 路由到 mcp_call
            return await this._framework.executeTool('mcp_call', {
              server: name,
              tool: toolName,
              args_json: JSON.stringify(args || {}),
            });
          },
        };
      }
    }

    // 保存客户端、工具信息和实际工具对象
    this._clients.set(name, {
      client,
      tools: toolsInfo,
      toolObjects, // 实际工具对象，供 mcp_call 直接调用
      enabled: config.enabled !== false,
    });

    log.info(
      ` Added server '${name}' with ${toolsInfo.length} tools (ext_call names: ${Object.keys(
        this.tools
      )
        .filter((k) => k.startsWith(name + '_'))
        .join(', ')})`
    );

    return { success: true, name, toolsCount: toolsInfo.length };
  }

  /**
   * 移除 MCP 服务器
   */
  async removeServer(name) {
    const clientInfo = this._clients.get(name);
    if (clientInfo) {
      try {
        // 添加超时保护，避免 close/destroy 阻塞
        const closePromise = clientInfo.client.close?.() || clientInfo.client.destroy?.();
        if (closePromise && typeof closePromise.then === 'function') {
          await Promise.race([
            closePromise,
            new Promise((resolve) => setTimeout(() => resolve(), 3000)),
          ]);
        }
      } catch (e) {
        // ignore
      }

      // 清理已注册的工具
      for (const toolName of Object.keys(this.tools)) {
        if (toolName.startsWith(name + '_')) {
          delete this.tools[toolName];
        }
      }

      this._clients.delete(name);
    }
  }

  /**
   * 获取所有服务器
   */
  getServers() {
    return Array.from(this._clients.entries()).map(([name, info]) => ({
      name,
      tools: info.tools.map((t) => t.name),
    }));
  }

  reload(framework) {
    log.info(' Reloading...');
    this._framework = framework;
  }

  /**
   * 重新加载 MCP 配置
   * @param {Object} config - 新的配置对象，包含 mcpServers
   */
  async reloadConfig(config) {
    log.info(' reloadConfig start');
    const newServers = config?.mcpServers || {};

    // 1. 先快速清理所有旧服务器（不等待 close 完成）
    log.info(' Clearing old servers...');
    for (const [name, clientInfo] of this._clients) {
      try {
        // 不等待 close，直接删除
        clientInfo.client.close?.()?.catch?.(() => {});
      } catch (e) {}
    }
    this._clients.clear();
    // 清理服务器配置
    this._serverConfigs.clear();

    // 2. 并行添加新服务器
    log.info(' Adding new servers...');
    const addPromises = Object.entries(newServers).map(async ([name, serverConfig]) => {
      if (serverConfig.enabled === false) {
        log.info(` Skipping disabled server: ${name}`);
        // 仍保存配置，以便后续动态启用
        this._serverConfigs.set(name, { name, ...serverConfig });
        return;
      }
      const normalizedConfig = {
        name,
        type: serverConfig.type,
        url: serverConfig.url,
        headers: serverConfig.headers,
        authProvider: serverConfig.authProvider,
        command: serverConfig.command,
        args: serverConfig.args,
        env: serverConfig.env,
        enabled: true,
      };
      await this.addServer(normalizedConfig);
    });

    await Promise.all(addPromises);
    log.info(' reloadConfig complete');

    // 3. 刷新所有 agent 的 MCP 提示词
    if (this._framework) {
      this._refreshAllAgentsMCPPrompt(this._framework);
    }
  }

  /**
   * 保存 MCP 服务器的 enabled 状态到配置文件
   */
  async _saveMCPServerEnabled(serverName, enabled) {
    const fs = require('fs');
    const path = require('path');
    const configPath = path.resolve('.agent/mcp_config.json');

    try {
      if (!fs.existsSync(configPath)) {
        log.warn(` MCP config file not found: ${configPath}`);
        return false;
      }

      const configContent = fs.readFileSync(configPath, 'utf8');
      const config = JSON.parse(configContent);

      if (!config.mcpServers || !config.mcpServers[serverName]) {
        log.warn(` Server '${serverName}' not found in MCP config`);
        return false;
      }

      config.mcpServers[serverName].enabled = enabled;
      fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
      log.info(` Saved enabled=${enabled} for server '${serverName}' to config`);
      return true;
    } catch (err) {
      log.error(` Failed to save MCP config:`, err.message);
      return false;
    }
  }

  async uninstall(framework) {
    // 断开所有 MCP 连接
    for (const [name, clientInfo] of this._clients) {
      try {
        (await clientInfo.client.close?.()) || clientInfo.client.destroy?.();
      } catch (e) {
        // ignore
      }
    }
    this._clients.clear();
    this._framework = null;
  }
}

module.exports = {
  MCPExecutorPlugin,
  MCPClientWrapper,
};
