import { spawn } from 'child_process';
import fs from 'fs/promises';
import path from 'path';

export function exportApp(platform?: string): Promise<void> {
  const args = ['expo', 'export', '--output-dir', 'dist', '--clear'];
  if (platform) args.push('--platform', platform);

  return new Promise((resolve, reject) => {
    const child = spawn('npx', args, {
      stdio: ['inherit', 'pipe', 'inherit'],
      env: { ...process.env, FORCE_COLOR: '1' },
    });

    let done = false;

    child.stdout.on('data', (chunk: Buffer) => {
      process.stdout.write(chunk);
      // "Exported: dist" means all files are written. Static pre-rendering
      // can leave open HTTP handles that prevent the process from exiting.
      // Kill cleanly once we know the work is complete.
      if (!done && chunk.toString().includes('Exported:')) {
        done = true;
        setTimeout(() => { if (!child.killed) child.kill(); }, 2000);
      }
    });

    child.on('close', (code, signal) => {
      if (code === 0 || (done && signal === 'SIGTERM')) resolve();
      else reject(new Error(`Export failed with exit code ${code}`));
    });

    child.on('error', reject);
  });
}

/**
 * Check if dist/ is stale by comparing its mtime against known source files.
 * Returns true if any source file (app.json, app.config.js, app.config.ts, app/)
 * was modified after dist/ was last written.
 */
export async function isDistStale(distDir: string, projectDir?: string): Promise<boolean> {
  const baseDir = projectDir ?? process.cwd();
  const distMtime = (await fs.stat(distDir)).mtimeMs;
  const sourceChecks = ['app.json', 'app.config.js', 'app.config.ts', 'app'].map(async (f) => {
    try {
      const s = await fs.stat(path.resolve(baseDir, f));
      return s.mtimeMs > distMtime;
    } catch { return false; }
  });
  return (await Promise.all(sourceChecks)).some(Boolean);
}
