#!/usr/bin/env node
/**
 * engine/kb-sweep-runner.js — Detached entrypoint for the KB sweep.
 *
 * Spawned by dashboard.js `handleKnowledgeSweep` with `{ detached: true,
 * stdio: ['ignore', logFd, logFd] }` so the sweep survives dashboard /
 * engine restarts. The sweep regularly runs 1h+ and was previously killed
 * mid-stream every `minions restart`.
 *
 * Args:
 *   --sweep-token <token>   Opaque token from the dashboard (string/number).
 *   --body-file <path>      Optional path to a JSON file with request body
 *                           fields (pinnedKeys, dryRun). Deleted on exit.
 *   --dry-run               Equivalent to `body.dryRun = true`.
 *
 * State protocol: runKbSweep itself writes `engine/kb-sweep-state.json`
 * (in-flight → completed/failed) and includes `pid: process.pid` (this
 * runner's pid) so the dashboard can liveness-check via `process.kill(pid, 0)`.
 * Exits 0 on success, 1 on error. stdout/stderr land in engine/kb-sweep.log.
 */

const fs = require('fs');

function getArg(argv, name) {
  const idx = argv.indexOf(name);
  if (idx >= 0 && idx + 1 < argv.length) return argv[idx + 1];
  return null;
}
function hasFlag(argv, name) {
  return argv.indexOf(name) >= 0;
}

const argv = process.argv.slice(2);
const sweepToken = getArg(argv, '--sweep-token') || String(Date.now());
const bodyFile = getArg(argv, '--body-file');
const cliDryRun = hasFlag(argv, '--dry-run');

let body = {};
if (bodyFile) {
  try {
    const raw = fs.readFileSync(bodyFile, 'utf8');
    body = JSON.parse(raw || '{}');
  } catch (e) {
    console.error(`[kb-sweep-runner] failed to read body-file ${bodyFile}: ${e.message}`);
  }
}
const dryRun = cliDryRun || body.dryRun === true;

// Lazy-require AFTER args are parsed so a malformed body-file doesn't drag in
// the whole sweep stack before we've reported the failure.
const queries = require('./queries');
const { runKbSweep } = require('./kb-sweep');

function cleanupBodyFile() {
  if (!bodyFile) return;
  try { fs.unlinkSync(bodyFile); } catch { /* ignore */ }
}

(async () => {
  const startedIso = new Date().toISOString();
  console.log(`[kb-sweep-runner] ${startedIso} starting pid=${process.pid} token=${sweepToken} dryRun=${dryRun}`);
  try {
    const engineConfig = (queries.getConfig() || {}).engine || {};
    const result = await runKbSweep({
      pinnedKeys: body.pinnedKeys,
      engineConfig,
      sweepToken,
      dryRun,
    });
    const summary = result && result.summary ? result.summary : 'ok';
    console.log(`[kb-sweep-runner] ${new Date().toISOString()} done: ${summary}`);
    cleanupBodyFile();
    process.exit(0);
  } catch (e) {
    const msg = e && e.message ? e.message : String(e);
    console.error(`[kb-sweep-runner] ${new Date().toISOString()} error: ${msg}`);
    if (e && e.stack) console.error(e.stack);
    cleanupBodyFile();
    process.exit(1);
  }
})();
