/**
 * `everystack deploy` — deploy the stack's infrastructure.
 *
 * A thin wrapper over `sst deploy` so a consumer never has to type or know about SST: the
 * framework owns the infra tool, the consumer just runs `everystack deploy --stage <name>`.
 * Infra only — migrations (`db:migrate`) and OTA (`update`) stay explicit, the same split
 * `sst deploy` itself has.
 *
 * The arg build is pure (unit-tested); the command streams sst's output through and exits
 * with its code so CI sees a failed deploy.
 */

import { spawn } from 'node:child_process';
import { step, success, fail, info } from '../output.js';

/** The `sst` argv `everystack deploy` runs. Pure, so the mapping is unit-tested. */
export function buildDeployArgs(flags: Record<string, string>): string[] {
  const stage = flags.stage || 'dev';
  return ['sst', 'deploy', '--stage', stage];
}

export async function deployCommand(flags: Record<string, string>): Promise<void> {
  const stage = flags.stage || 'dev';
  const args = buildDeployArgs(flags);

  step(`Deploying stage "${stage}"...`);
  await new Promise<void>((resolve) => {
    // `npx` resolves the consumer's local sst (the same way the export step runs expo).
    const child = spawn('npx', args, { stdio: 'inherit', env: { ...process.env, FORCE_COLOR: '1' } });
    child.on('close', (code) => {
      if (code === 0) {
        resolve();
      } else {
        fail(`Deploy failed (exit ${code}).`);
        process.exit(code ?? 1);
      }
    });
    child.on('error', (err) => {
      fail(`Could not run sst: ${err.message}`);
      info('Install it as a dev dependency: `pnpm add -D sst`.');
      process.exit(1);
    });
  });
  success(`Deployed stage "${stage}".`);
  info('Next: `everystack db:migrate --stage ' + stage + '` to apply migrations, `everystack update` to publish the app bundle.');
}
