import { spawn } from 'child_process';

export async function runCommand(binary, args = [], options = {}) {
  const {
    cwd = process.cwd(),
    env = {},
    timeoutMs = 15000
  } = options;

  return await new Promise((resolve) => {
    let stdout = '';
    let stderr = '';
    let timedOut = false;
    let settled = false;

    const child = spawn(binary, args, {
      cwd,
      env: { ...process.env, ...env },
      stdio: ['ignore', 'pipe', 'pipe']
    });

    const finalize = (result) => {
      if (settled) {
        return;
      }

      settled = true;
      clearTimeout(timer);
      resolve({
        ...result,
        stdout: result.stdout ?? stdout,
        stderr: result.stderr ?? stderr,
        command: [binary, ...args].join(' ')
      });
    };

    const timer = setTimeout(() => {
      timedOut = true;
      child.kill('SIGKILL');
    }, timeoutMs);

    child.stdout.on('data', (chunk) => {
      stdout += chunk.toString();
    });

    child.stderr.on('data', (chunk) => {
      stderr += chunk.toString();
    });

    child.on('error', (error) => {
      finalize({
        ok: false,
        code: 127,
        stdout,
        stderr: stderr || error.message,
        timedOut: false,
        signal: null
      });
    });

    child.on('close', (code, signal) => {
      finalize({
        ok: code === 0 && !timedOut,
        code: timedOut ? 124 : (code ?? 1),
        stdout,
        stderr,
        timedOut,
        signal
      });
    });
  });
}
