/**
 * MCPEngine Studio — Server Compiler
 *
 * Takes a ServerBundle of generated TypeScript files and produces a single
 * bundled JavaScript string ready for Cloudflare Workers deployment.
 *
 * NOTE: This is Phase-1 concatenation. Real esbuild bundling will be added later.
 */

import type { ServerBundle, GeneratedFile } from '@mcpengine/ai-pipeline/types';

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

/** Strip TypeScript type annotations in a best-effort way (imports, type-only
 *  exports, interface/type blocks).  Good enough for simple generated code. */
function stripTypes(src: string): string {
  return src
    // Remove `import type …` lines
    .replace(/^import\s+type\s+.*$/gm, '')
    // Remove `export type …` and `export interface …` blocks (single-line + multi-line)
    .replace(/^export\s+(type|interface)\s+\w+[^{]*\{[^}]*\}/gm, '')
    .replace(/^export\s+(type|interface)\s+.*$/gm, '')
    // Remove inline type annotations  `: Foo` after parameter names (rough)
    .replace(/:\s*[A-Z]\w+(\[\])?\s*(,|\)|\s*=>)/g, (_m, _arr, tail) => tail)
    // Remove `as Type` casts
    .replace(/\s+as\s+\w+/g, '')
    // Collapse blank lines
    .replace(/\n{3,}/g, '\n\n');
}

/** Convert TS import paths to inline references (they all live in the same
 *  concatenated scope so we just drop the import statements). */
function stripImports(src: string): string {
  return src.replace(/^import\s+.*$/gm, '');
}

/** Wrap file content in an IIFE-scoped module to avoid collisions. */
function wrapModule(name: string, code: string): string {
  return [
    `// ── ${name} ${'─'.repeat(Math.max(0, 60 - name.length))}`,
    `const __mod_${safeId(name)} = (() => {`,
    `  const exports = {};`,
    `  const module = { exports };`,
    code,
    `  return module.exports;`,
    `})();`,
    '',
  ].join('\n');
}

function safeId(path: string): string {
  return path.replace(/[^a-zA-Z0-9]/g, '_').replace(/_+/g, '_');
}

// ---------------------------------------------------------------------------
// Main compiler
// ---------------------------------------------------------------------------

export function compileServer(bundle: ServerBundle): string {
  const sections: string[] = [];

  // 1. Banner
  sections.push(
    '// ═══════════════════════════════════════════════════════════',
    '// MCPEngine Studio — Compiled MCP Server',
    `// Generated at ${new Date().toISOString()}`,
    `// Tools: ${bundle.toolCount}`,
    '// ═══════════════════════════════════════════════════════════',
    '',
  );

  // 2. Sort files: put the entry point last
  const sorted = [...bundle.files].sort((a, b) => {
    if (a.path === bundle.entryPoint) return 1;
    if (b.path === bundle.entryPoint) return -1;
    // Utility / shared modules first
    if (a.path.includes('utils') || a.path.includes('shared')) return -1;
    if (b.path.includes('utils') || b.path.includes('shared')) return 1;
    return a.path.localeCompare(b.path);
  });

  // 3. Process each file
  for (const file of sorted) {
    if (file.language === 'json' || file.language === 'markdown') continue;
    let code = file.content;
    code = stripTypes(code);
    code = stripImports(code);
    sections.push(wrapModule(file.path, code));
  }

  // 4. Export a fetch handler that the Worker template will consume
  sections.push(
    '// ── Fetch handler export ──────────────────────────────────',
    `const __entryModule = __mod_${safeId(bundle.entryPoint)};`,
    'export const serverModule = __entryModule;',
    '',
  );

  return sections.join('\n');
}

/** Compile and return metadata useful for deploy targets. */
export function compileWithMeta(bundle: ServerBundle) {
  const compiledCode = compileServer(bundle);
  const toolNames = bundle.files
    .filter((f) => f.path.includes('tools/'))
    .map((f) => f.path.replace(/^.*tools\//, '').replace(/\.ts$/, ''));

  return {
    code: compiledCode,
    toolNames,
    toolCount: bundle.toolCount,
    fileCount: bundle.files.length,
    sizeBytes: new TextEncoder().encode(compiledCode).byteLength,
  };
}
