import { readFile } from 'node:fs/promises'
import { spawn } from 'node:child_process'
import { join } from 'node:path'
import { requireCodeWorkDir } from '../hooks.js'

/** 仅允许 package.json scripts 中声明的脚本名 */
async function listAllowedScripts(cwd: string): Promise<Set<string>> {
  const allowed = new Set<string>()
  try {
    const raw = await readFile(join(cwd, 'package.json'), 'utf8')
    const pkg = JSON.parse(raw) as { scripts?: Record<string, string> }
    for (const k of Object.keys(pkg.scripts ?? {})) {
      allowed.add(k)
    }
  } catch {
    // 无 package.json 则无允许脚本
  }
  return allowed
}

export async function runScript(script: string): Promise<Record<string, unknown>> {
  const cwd = requireCodeWorkDir()
  const allowed = await listAllowedScripts(cwd)
  if (!allowed.has(script)) {
    throw new Error(
      `脚本 "${script}" 不在 package.json scripts 白名单中；允许: ${[...allowed].join(', ') || '(无)'}`,
    )
  }
  return new Promise((resolve, reject) => {
    const child = spawn('npm', ['run', script], {
      cwd,
      shell: false,
      stdio: ['ignore', 'pipe', 'pipe'],
      env: process.env,
    })
    let stdout = ''
    let stderr = ''
    child.stdout.on('data', (d: Buffer) => {
      stdout += d.toString()
    })
    child.stderr.on('data', (d: Buffer) => {
      stderr += d.toString()
    })
    child.on('close', code => {
      resolve({
        script,
        exitCode: code ?? 1,
        stdout: stdout.slice(-20_000),
        stderr: stderr.slice(-20_000),
      })
    })
    child.on('error', reject)
  })
}
