#!/usr/bin/env node
// Suppress Node 25 deprecation warning for shell spawn (safe: args are not user-controlled)
process.removeAllListeners('warning')
/**
 * SANDCODE CLI Entry Point
 *
 * Spawns the CLI using the best available TypeScript runtime:
 *   1. Bun (preferred — native bun:bundle support)
 *   2. tsx (fallback — with shims for bun:bundle)
 *
 * npm link installs this as the global `sandcode` command.
 */
import { cpSync, existsSync, mkdirSync, readdirSync } from 'fs'
import { execFileSync, spawn } from 'child_process'
import { dirname, join, resolve } from 'path'
import { fileURLToPath, pathToFileURL } from 'url'

const __dirname = dirname(fileURLToPath(import.meta.url))
const root = resolve(__dirname, '..')

// Copy vendored @sandcode/* packages to node_modules on first run
// (replaces postinstall — avoids CWD crash on npm install -g)
const vendorDir = join(root, 'src', 'vendor')
const targetDir = join(root, 'node_modules', '@sandcode')
if (existsSync(vendorDir) && !existsSync(join(targetDir, 'sdk'))) {
  try {
    mkdirSync(targetDir, { recursive: true })
    const entries = readdirSync(vendorDir).filter((e) => e.startsWith('sandcode-'))
    for (const entry of entries) {
      const pkgName = entry.replace('sandcode-', '')
      cpSync(join(vendorDir, entry), join(targetDir, pkgName), { recursive: true, force: true })
    }
    // color-diff-napi goes to node_modules/color-diff-napi (not @sandcode/)
    const cdSrc = join(vendorDir, 'sandcode-color-diff-napi')
    if (existsSync(cdSrc)) {
      cpSync(cdSrc, join(root, 'node_modules', 'color-diff-napi'), { recursive: true, force: true })
    }
  } catch {
    /* non-fatal */
  }
}
const entry = resolve(root, 'src', 'entrypoints', 'cli.tsx')
const bunPreload = resolve(root, 'shims', 'bun-preload.ts')
const loaderScript = pathToFileURL(resolve(root, 'shims', 'loader.js')).href

function hasBinary(cmd) {
  try {
    const lookupCmd = process.platform === 'win32' ? 'where' : 'which'
    execFileSync(lookupCmd, [cmd], { stdio: 'pipe' })
    return true
  } catch {
    return false
  }
}

const isWindows = process.platform === 'win32'
const hasBun = hasBinary('bun')
const hasTsx = hasBinary('tsx')

let command, args

if (hasBun) {
  command = 'bun'
  args = [
    'run',
    '--preload',
    bunPreload,
    '--feature=TOKEN_BUDGET',
    '--feature=DUMP_SYSTEM_PROMPT',
    '--feature=HOOK_PROMPTS',
    '--feature=FORGE',
    entry,
    ...process.argv.slice(2),
  ]
} else if (hasTsx) {
  command = 'tsx'
  args = ['--import', loaderScript, entry, ...process.argv.slice(2)]
} else {
  // Auto-install tsx as fallback runtime
  console.error('SANDCODE: No TypeScript runtime found. Installing tsx...')
  try {
    execFileSync('npm', ['install', '-g', 'tsx'], { stdio: 'inherit', shell: isWindows })
    command = 'tsx'
    args = ['--import', loaderScript, entry, ...process.argv.slice(2)]
  } catch {
    console.error('Failed to install tsx automatically.')
    console.error('Please install manually:')
    console.error('  npm install -g tsx')
    console.error('  or: https://bun.sh')
    process.exit(1)
  }
}

const child = spawn(command, args, {
  stdio: 'inherit',
  env: { ...process.env, NODE_NO_WARNINGS: '1' },
  shell: isWindows,
})

child.on('error', (err) => {
  console.error(`Error launching SANDCODE: ${err.message}`)
  process.exit(1)
})

child.on('exit', (code) => {
  process.exit(code ?? 0)
})
