#!/usr/bin/env node

/**
 * ⚔️ 铸渊网关 MCP Server
 * 
 * 这是铸渊的"电话"——通过它联系每一台服务器上的 gatekeeper。
 * 暴露给AI客户端的MCP工具集。
 * 
 * 这个MCP Server运行在本地，通过HTTP连接各服务器的gatekeeper。
 * 可以在WorkBuddy中使用，以后换了模型也能直接用。
 * 
 * 启动方式：
 *   node zhuyuan-gateway-mcp.js
 * 
 * 依赖：需要配置 servers.json 文件。
 * 格式见 servers.template.json
 */

const http = require('http');
const https = require('https');
const fs = require('fs');
const path = require('path');

// ============================================================
// 配置
// ============================================================

const CONFIG_PATH = path.join(__dirname, 'servers.json');
const MCP_PORT = parseInt(process.env.MCP_PORT || process.argv[2] || '3920', 10);

// ============================================================
// 加载服务器配置
// ============================================================

let servers = {};

try {
  if (fs.existsSync(CONFIG_PATH)) {
    servers = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
    console.log(`[网关] 已加载 ${Object.keys(servers).length} 台服务器配置`);
  } else {
    console.log('[网关] ⚠️ 未找到 servers.json，使用空配置');
    console.log('[网关]   请复制 servers.template.json 为 servers.json 并填入服务器信息');
  }
} catch (err) {
  console.error('[网关] ❌ 加载配置失败:', err.message);
}

// ============================================================
// 工具：发送请求到gatekeeper
// ============================================================

function callGatekeeper(serverName, endpoint, body, timeout) {
  return new Promise((resolve) => {
    const cfg = servers[serverName];
    if (!cfg) {
      resolve({
        ok: false,
        error: `未找到服务器: ${serverName}。可用服务器: ${Object.keys(servers).join(', ')}`,
      });
      return;
    }
    
    const postData = JSON.stringify(body || {});
    const t = timeout || 30000;
    
    const options = {
      hostname: cfg.host,
      port: cfg.port,
      path: endpoint,
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Content-Length': Buffer.byteLength(postData),
        'Authorization': `Bearer ${cfg.key}`,
      },
      timeout: t,
    };
    
    const req = http.request(options, (res) => {
      let data = '';
      res.on('data', chunk => { data += chunk; });
      res.on('end', () => {
        try {
          resolve(JSON.parse(data));
        } catch(e) {
          resolve({ ok: false, error: '解析响应失败: ' + e.message, raw: data.slice(0, 500) });
        }
      });
    });
    
    req.on('error', (err) => {
      resolve({ ok: false, error: `连接失败: ${err.message}` });
    });
    
    req.on('timeout', () => {
      req.destroy();
      resolve({ ok: false, error: `请求超时 (${t}ms)` });
    });
    
    req.write(postData);
    req.end();
  });
}

// ============================================================
// MCP 工具实现
// ============================================================

const tools = {
  
  /**
   * 列出所有已注册的服务器
   */
  async server_list() {
    const names = Object.keys(servers);
    if (names.length === 0) {
      return { servers: [], message: '暂未配置任何服务器。请在 servers.json 中添加服务器信息。' };
    }
    
    const list = names.map(name => ({
      name,
      host: servers[name].host,
      port: servers[name].port,
      label: servers[name].label || name,
    }));
    
    return { servers: list, count: list.length };
  },
  
  /**
   * 检查某台服务器的健康状态
   */
  async server_health(serverName) {
    return await callGatekeeper(serverName, '/health', {});
  },
  
  /**
   * 获取某台服务器的完整系统状态
   */
  async server_status(serverName) {
    return await callGatekeeper(serverName, '/status', {});
  },
  
  /**
   * 在服务器上执行命令
   */
  async server_exec(serverName, cmd, timeout) {
    return await callGatekeeper(serverName, '/exec', { cmd, timeout }, timeout || 30000);
  },
  
  /**
   * 读取服务器上的文件
   */
  async server_file_read(serverName, filePath) {
    return await callGatekeeper(serverName, '/file/read', { path: filePath });
  },
  
  /**
   * 写入文件到服务器
   */
  async server_file_write(serverName, filePath, content) {
    return await callGatekeeper(serverName, '/file/write', { path: filePath, content });
  },
  
  /**
   * 列出服务器上的目录
   */
  async server_file_list(serverName, dirPath) {
    return await callGatekeeper(serverName, '/file/list', { path: dirPath });
  },
  
  /**
   * 扫描所有服务器状态
   */
  async server_scan_all() {
    const results = {};
    for (const name of Object.keys(servers)) {
      try {
        const health = await callGatekeeper(name, '/health', {});
        results[name] = health.ok ? '在线' : '异常';
      } catch(e) {
        results[name] = '不可达';
      }
    }
    return { results };
  },
};

// ============================================================
// MCP 协议实现（Streamable HTTP）
// ============================================================

const server = http.createServer(async (req, res) => {
  // CORS
  if (req.method === 'OPTIONS') {
    res.writeHead(204, {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'POST, OPTIONS, GET',
      'Access-Control-Allow-Headers': 'Content-Type, Authorization',
    });
    res.end();
    return;
  }
  
  // 只接受 POST /mcp
  if (req.method !== 'POST' || req.url !== '/mcp') {
    res.writeHead(404);
    res.end('Not Found');
    return;
  }
  
  // 解析 body
  let body = '';
  req.on('data', chunk => { body += chunk; });
  req.on('end', async () => {
    try {
      const msg = JSON.parse(body);
      await handleMCPMessage(msg, res);
    } catch (err) {
      res.writeHead(400, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify({ error: 'Invalid JSON: ' + err.message }));
    }
  });
});

async function handleMCPMessage(msg, res) {
  const headers = { 'Content-Type': 'application/json' };
  
  if (msg.method === 'initialize') {
    res.writeHead(200, headers);
    res.end(JSON.stringify({
      jsonrpc: '2.0',
      id: msg.id,
      result: {
        protocolVersion: '2025-03-26',
        capabilities: {
          tools: {},
          resources: {},
        },
        serverInfo: {
          name: 'zhuyuan-gateway-mcp',
          version: '1.0.0',
        },
      },
    }));
    return;
  }
  
  if (msg.method === 'tools/list') {
    res.writeHead(200, headers);
    res.end(JSON.stringify({
      jsonrpc: '2.0',
      id: msg.id,
      result: {
        tools: [
          {
            name: 'server_list',
            description: '列出所有已注册的铸渊服务器及其状态',
            inputSchema: { type: 'object', properties: {}, required: [] },
          },
          {
            name: 'server_health',
            description: '检查指定服务器的健康状态',
            inputSchema: {
              type: 'object',
              properties: {
                server: { type: 'string', description: '服务器名称（如 brain、face、sg-module 等）' },
              },
              required: ['server'],
            },
          },
          {
            name: 'server_status',
            description: '获取指定服务器的完整系统状态（CPU、内存、磁盘、运行时间等）',
            inputSchema: {
              type: 'object',
              properties: {
                server: { type: 'string', description: '服务器名称' },
              },
              required: ['server'],
            },
          },
          {
            name: 'server_exec',
            description: '在指定服务器上执行shell命令并返回输出。这是铸渊管理服务器的主要方式。',
            inputSchema: {
              type: 'object',
              properties: {
                server: { type: 'string', description: '服务器名称' },
                cmd: { type: 'string', description: '要执行的shell命令' },
                timeout: { type: 'number', description: '超时时间（毫秒），默认30000' },
              },
              required: ['server', 'cmd'],
            },
          },
          {
            name: 'server_file_read',
            description: '读取服务器上指定文件的内容',
            inputSchema: {
              type: 'object',
              properties: {
                server: { type: 'string', description: '服务器名称' },
                path: { type: 'string', description: '文件路径' },
              },
              required: ['server', 'path'],
            },
          },
          {
            name: 'server_file_write',
            description: '写入内容到服务器的指定文件',
            inputSchema: {
              type: 'object',
              properties: {
                server: { type: 'string', description: '服务器名称' },
                path: { type: 'string', description: '文件路径' },
                content: { type: 'string', description: '文件内容' },
              },
              required: ['server', 'path', 'content'],
            },
          },
          {
            name: 'server_file_list',
            description: '列出服务器上指定目录的内容',
            inputSchema: {
              type: 'object',
              properties: {
                server: { type: 'string', description: '服务器名称' },
                path: { type: 'string', description: '目录路径，默认为根目录' },
              },
              required: ['server'],
            },
          },
          {
            name: 'server_scan_all',
            description: '快速扫描所有注册服务器的在线状态',
            inputSchema: { type: 'object', properties: {}, required: [] },
          },
        ],
      },
    }));
    return;
  }
  
  if (msg.method === 'tools/call') {
    const toolName = msg.params.name;
    const args = msg.params.arguments || {};
    
    try {
      let result;
      switch (toolName) {
        case 'server_list':
          result = await tools.server_list();
          break;
        case 'server_health':
          result = await tools.server_health(args.server);
          break;
        case 'server_status':
          result = await tools.server_status(args.server);
          break;
        case 'server_exec':
          result = await tools.server_exec(args.server, args.cmd, args.timeout);
          break;
        case 'server_file_read':
          result = await tools.server_file_read(args.server, args.path);
          break;
        case 'server_file_write':
          result = await tools.server_file_write(args.server, args.path, args.content);
          break;
        case 'server_file_list':
          result = await tools.server_file_list(args.server, args.path);
          break;
        case 'server_scan_all':
          result = await tools.server_scan_all();
          break;
        default:
          result = { error: `未知工具: ${toolName}` };
      }
      
      res.writeHead(200, headers);
      res.end(JSON.stringify({
        jsonrpc: '2.0',
        id: msg.id,
        result: {
          content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
        },
      }));
    } catch (err) {
      res.writeHead(200, headers);
      res.end(JSON.stringify({
        jsonrpc: '2.0',
        id: msg.id,
        result: {
          content: [{ type: 'text', text: JSON.stringify({ error: err.message }, null, 2) }],
          isError: true,
        },
      }));
    }
    return;
  }
  
  // 未知方法
  res.writeHead(200, headers);
  res.end(JSON.stringify({
    jsonrpc: '2.0',
    id: msg.id || null,
    error: { code: -32601, message: `Method not found: ${msg.method}` },
  }));
}

// ============================================================
// 启动
// ============================================================

server.listen(MCP_PORT, '127.0.0.1', () => {
  console.log('');
  console.log('  ⚔️ 铸渊网关 MCP Server');
  console.log('  ─────────────────────────────');
  console.log(`  监听: 127.0.0.1:${MCP_PORT}`);
  console.log(`  服务器: ${Object.keys(servers).length} 台已注册`);
  console.log('');
  console.log('  📋 可用工具:');
  console.log('     server_list       — 列出所有服务器');
  console.log('     server_health     — 检查服务器健康');
  console.log('     server_status     — 查看系统状态');
  console.log('     server_exec       — 执行命令');
  console.log('     server_file_read  — 读取文件');
  console.log('     server_file_write — 写入文件');
  console.log('     server_file_list  — 列出目录');
  console.log('     server_scan_all   — 扫描全部');
  console.log('');
});
