#!/usr/bin/env node
/**
 * MCP Factory — Fix Unknown Tool Error
 * Patches all 30 servers to properly throw McpError for unknown tools
 * instead of catching and returning isError:true (which MCP spec treats as success).
 * 
 * The fix:
 * 1. Import McpError and ErrorCode from the SDK
 * 2. Check tool name against known tools before calling handler
 * 3. Throw McpError(ErrorCode.MethodNotFound) for unknown tools
 */

import { readFileSync, writeFileSync, readdirSync, existsSync } from 'fs';
import { execSync } from 'child_process';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';

const __dirname = dirname(fileURLToPath(import.meta.url));
const FACTORY_ROOT = resolve(__dirname, '..');
const registry = JSON.parse(readFileSync(resolve(FACTORY_ROOT, 'server-registry.json'), 'utf-8'));
const SERVERS_ROOT = resolve(FACTORY_ROOT, registry.servers_root);

let fixed = 0;
let skipped = 0;
let errors = 0;

for (const [name] of Object.entries(registry.servers)) {
  const srcPath = resolve(SERVERS_ROOT, name, 'src/index.ts');
  
  if (!existsSync(srcPath)) {
    console.log(`⚠️  ${name}: No src/index.ts`);
    skipped++;
    continue;
  }

  let src = readFileSync(srcPath, 'utf-8');

  // Check if already fixed
  if (src.includes('McpError')) {
    console.log(`⏭️  ${name}: Already has McpError import`);
    skipped++;
    continue;
  }

  try {
    // Step 1: Add McpError and ErrorCode to imports
    // Find the import from types.js
    const typesImportMatch = src.match(/(import\s*\{[^}]*\}\s*from\s*"@modelcontextprotocol\/sdk\/types\.js";)/);
    if (typesImportMatch) {
      const oldImport = typesImportMatch[1];
      // Extract existing imports
      const existingImports = oldImport.match(/\{([^}]+)\}/)[1].trim();
      const newImport = oldImport.replace(
        `{${existingImports}}`,
        `{${existingImports}, McpError, ErrorCode}`
      );
      src = src.replace(oldImport, newImport);
    }

    // Step 2: Add tool name validation before the try/catch in CallToolRequestSchema handler
    // Pattern: Find the handler and add a check
    const toolNames = [...src.matchAll(/name:\s*"([^"]+)"/g)].map(m => m[1]);
    // Filter to only tool names (in the tools array, not other name fields)
    const validToolNames = toolNames.filter(n => !['text', 'object'].includes(n));
    
    // Find the CallToolRequestSchema handler and add validation
    const handlerPattern = /server\.setRequestHandler\(CallToolRequestSchema,\s*async\s*\(request\)\s*=>\s*\{\s*const\s*\{\s*name,\s*arguments:\s*args\s*\}\s*=\s*request\.params;\s*\n\s*try\s*\{/;
    
    if (handlerPattern.test(src)) {
      src = src.replace(
        handlerPattern,
        `server.setRequestHandler(CallToolRequestSchema, async (request) => {
    const { name, arguments: args } = request.params;

    // Validate tool exists (MCP spec requires proper error for unknown tools)
    const knownTools = tools.map(t => t.name);
    if (!knownTools.includes(name)) {
      throw new McpError(ErrorCode.MethodNotFound, \`Unknown tool: \${name}\`);
    }
    
    try {`
      );
    } else {
      // Try a more flexible pattern
      const altPattern = /server\.setRequestHandler\(CallToolRequestSchema,\s*async\s*\(request\)\s*=>\s*\{/;
      if (altPattern.test(src)) {
        // Check if there's already a tool validation
        const handlerBlock = src.substring(src.search(altPattern));
        if (handlerBlock.includes('const { name') && !handlerBlock.includes('knownTools')) {
          // Insert after the destructuring
          src = src.replace(
            /const\s*\{\s*name,\s*arguments:\s*args\s*\}\s*=\s*request\.params;\s*\n/,
            `const { name, arguments: args } = request.params;

    // Validate tool exists (MCP spec requires proper error for unknown tools)
    const knownTools = tools.map(t => t.name);
    if (!knownTools.includes(name)) {
      throw new McpError(ErrorCode.MethodNotFound, \`Unknown tool: \${name}\`);
    }
    
`
          );
        }
      }
    }

    writeFileSync(srcPath, src);
    console.log(`✅ ${name}: Patched`);
    fixed++;

    // Rebuild
    try {
      execSync('npm run build', { cwd: resolve(SERVERS_ROOT, name), timeout: 15000, stdio: 'pipe' });
      console.log(`   🔨 ${name}: Rebuilt`);
    } catch (buildErr) {
      console.log(`   ⚠️  ${name}: Build warning (check manually)`);
    }
  } catch (err) {
    console.log(`❌ ${name}: ${err.message}`);
    errors++;
  }
}

console.log('\n' + '═'.repeat(60));
console.log(`Fixed: ${fixed} | Skipped: ${skipped} | Errors: ${errors}`);
