#!/usr/bin/env node
/**
 * build.mjs — Build Claude Code from source using esbuild
 *
 * Strategy:
 *   1. Copy src/ → build-src/ (working copy)
 *   2. Transform all `from 'bun:bundle'` imports → `from './stubs/bun-bundle'`
 *   3. Inject MACRO globals via esbuild --define (replaces MACRO.X at compile time)
 *   4. Bundle with esbuild into a single cli.js
 */

import { readdir, readFile, writeFile, mkdir, cp, rm } from 'node:fs/promises'
import { join, relative, dirname } from 'node:path'
import { execSync } from 'node:child_process'
import { fileURLToPath } from 'node:url'

const __dirname = dirname(fileURLToPath(import.meta.url))
const ROOT = join(__dirname, '..')

const VERSION = '2.1.88'

// ── Step 1: Clean & Create build directory ─────────────────────────────────

const BUILD_DIR = join(ROOT, 'build-src')
await rm(BUILD_DIR, { recursive: true, force: true })
await mkdir(BUILD_DIR, { recursive: true })

// Copy src/ → build-src/
await cp(join(ROOT, 'src'), join(BUILD_DIR, 'src'), { recursive: true })
// Copy stubs/ → build-src/stubs/
await cp(join(ROOT, 'stubs'), join(BUILD_DIR, 'stubs'), { recursive: true })

console.log('✅ Copied source to build-src/')

// ── Step 2: Transform imports ──────────────────────────────────────────────

async function* walkFiles(dir) {
  for (const entry of await readdir(dir, { withFileTypes: true })) {
    const full = join(dir, entry.name)
    if (entry.isDirectory()) yield* walkFiles(full)
    else if (entry.name.endsWith('.ts') || entry.name.endsWith('.tsx')) yield full
  }
}

let transformCount = 0

for await (const file of walkFiles(join(BUILD_DIR, 'src'))) {
  let content = await readFile(file, 'utf8')
  let modified = false

  // Replace bun:bundle import with our stub
  if (content.includes("from 'bun:bundle'") || content.includes('from "bun:bundle"')) {
    const rel = relative(dirname(file), join(BUILD_DIR, 'stubs', 'bun-bundle.ts'))
    const importPath = rel.startsWith('.') ? rel : './' + rel
    content = content.replace(
      /import\s*\{\s*feature\s*\}\s*from\s*['"]bun:bundle['"]/g,
      `import { feature } from '${importPath.replace(/\.ts$/, '.js')}'`
    )
    modified = true
  }

  if (modified) {
    await writeFile(file, content, 'utf8')
    transformCount++
  }
}

console.log(`✅ Transformed ${transformCount} files (bun:bundle → stub)`)

// ── Step 3: Create entrypoint wrapper ──────────────────────────────────────

const ENTRY = join(BUILD_DIR, 'entry.ts')
await writeFile(ENTRY, `
// MACRO globals — normally injected by Bun's --define at compile time
// We inject them here as globals so MACRO.X references resolve
const MACRO = {
  VERSION: '${VERSION}',
  BUILD_TIME: '',
  FEEDBACK_CHANNEL: 'https://github.com/anthropics/claude-code/issues',
  ISSUES_EXPLAINER: 'https://github.com/anthropics/claude-code/issues/new/choose',
  FEEDBACK_CHANNEL_URL: 'https://github.com/anthropics/claude-code/issues',
  ISSUES_EXPLAINER_URL: 'https://github.com/anthropics/claude-code/issues/new/choose',
  NATIVE_PACKAGE_URL: '@anthropic-ai/claude-code',
  PACKAGE_URL: '@anthropic-ai/claude-code',
  VERSION_CHANGELOG: '',
}

// Make it global
globalThis.MACRO = MACRO

// Now load the real entrypoint
import './src/entrypoints/cli.tsx'
`)

console.log('✅ Created entry wrapper with MACRO injection')

// ── Step 4: esbuild bundle ─────────────────────────────────────────────────

const OUT_FILE = join(ROOT, 'dist', 'cli.js')

try {
  // Check if esbuild is available
  execSync('npx esbuild --version', { stdio: 'pipe' })
} catch {
  console.log('\n📦 Installing esbuild...')
  execSync('npm install --save-dev esbuild', { cwd: ROOT, stdio: 'inherit' })
}

console.log('\n🔨 Bundling with esbuild...')

try {
  execSync(`npx esbuild \\
    "${ENTRY}" \\
    --bundle \\
    --platform=node \\
    --target=node18 \\
    --format=esm \\
    --outfile="${OUT_FILE}" \\
    --banner:js='#!/usr/bin/env node' \\
    --define:process.env.USER_TYPE='"external"' \\
    --define:process.env.CLAUDE_CODE_VERSION='"${VERSION}"' \\
    --external:bun:ffi \\
    --external:bun:bundle \\
    --allow-overwrite \\
    --log-level=info \\
    --sourcemap \\
    ${process.argv.includes('--minify') ? '--minify' : ''}`, {
    cwd: ROOT,
    stdio: 'inherit',
    shell: true
  })
} catch (e) {
  console.error('\n❌ esbuild failed. This is expected — the source has complex Bun-specific patterns.')
  console.error('   The source is primarily meant for reading/analysis, not recompilation.')
  console.error('\n   To proceed with fixing, you would need to:')
  console.error('   1. Install Bun runtime (bun.sh)')
  console.error('   2. Create a bun build script that uses Bun.defineMacro / feature() natively')
  console.error('   3. Or manually resolve each compile-time intrinsic')
  process.exit(1)
}

console.log(`\n✅ Build complete: ${OUT_FILE}`)
console.log(`   Run with: node ${OUT_FILE}`)
