// lib/util/autonomy-gate.mjs
// Autonomy-gate state machine for /ultraexecute-local + /ultraplan-local
// (plan-v2 Step 4 — drives the --gates flag).
//
// States:
//   idle             — not yet started
//   gates_on         — gates enabled, between phases
//   auto_running     — running phases continuously without pausing
//   paused_for_gate  — stopped at a phase boundary; awaiting `resume`
//   completed        — terminal
//
// Events:
//   start            — begin a run (gates flag chooses route)
//   phase_boundary   — a phase finished
//   resume           — operator confirmed; leave the gate
//   finish           — pipeline reached its end
//
// CLI shim:
//   node lib/util/autonomy-gate.mjs --state X --event Y [--gates true|false]
//   → JSON: { ok: true, next_state: "..." }   (success)
//   → JSON: { ok: false, error: "..." }       (invalid transition; exit 1)
//
// Pure data; no I/O. Re-entry to `completed` is idempotent.

export const STATES = Object.freeze({
  IDLE: 'idle',
  GATES_ON: 'gates_on',
  AUTO_RUNNING: 'auto_running',
  PAUSED_FOR_GATE: 'paused_for_gate',
  COMPLETED: 'completed',
});

export const EVENTS = Object.freeze({
  START: 'start',
  PHASE_BOUNDARY: 'phase_boundary',
  RESUME: 'resume',
  FINISH: 'finish',
});

const STATE_SET = new Set(Object.values(STATES));
const EVENT_SET = new Set(Object.values(EVENTS));

/**
 * Compute the next state given the current state, event, and (optional)
 * gates-flag intent (only consulted on `start` from `idle`).
 *
 * @param {string} state
 * @param {string} event
 * @param {{ gates?: boolean }} [opts]
 * @returns {{ ok: true, next_state: string } | { ok: false, error: string }}
 */
export function transition(state, event, opts = {}) {
  if (!STATE_SET.has(state)) {
    return { ok: false, error: `unknown state: ${state}` };
  }
  if (!EVENT_SET.has(event)) {
    return { ok: false, error: `unknown event: ${event}` };
  }

  // completed is terminal & idempotent
  if (state === STATES.COMPLETED) {
    return { ok: true, next_state: STATES.COMPLETED };
  }

  if (state === STATES.IDLE) {
    if (event === EVENTS.START) {
      const gates = opts.gates === true;
      return { ok: true, next_state: gates ? STATES.GATES_ON : STATES.AUTO_RUNNING };
    }
    return { ok: false, error: `invalid transition: idle + ${event} (only \`start\` allowed from idle)` };
  }

  if (state === STATES.GATES_ON) {
    if (event === EVENTS.PHASE_BOUNDARY) return { ok: true, next_state: STATES.PAUSED_FOR_GATE };
    if (event === EVENTS.FINISH) return { ok: true, next_state: STATES.COMPLETED };
    return { ok: false, error: `invalid transition: gates_on + ${event}` };
  }

  if (state === STATES.AUTO_RUNNING) {
    if (event === EVENTS.PHASE_BOUNDARY) return { ok: true, next_state: STATES.AUTO_RUNNING };
    if (event === EVENTS.FINISH) return { ok: true, next_state: STATES.COMPLETED };
    return { ok: false, error: `invalid transition: auto_running + ${event}` };
  }

  if (state === STATES.PAUSED_FOR_GATE) {
    if (event === EVENTS.RESUME) return { ok: true, next_state: STATES.GATES_ON };
    if (event === EVENTS.FINISH) return { ok: true, next_state: STATES.COMPLETED };
    return { ok: false, error: `invalid transition: paused_for_gate + ${event}` };
  }

  return { ok: false, error: `unhandled state: ${state}` };
}

/**
 * Convenience: is this state terminal?
 */
export function isTerminal(state) {
  return state === STATES.COMPLETED;
}

// ---- CLI shim ----------------------------------------------------------------

function parseArgs(argv) {
  const out = {};
  for (let i = 0; i < argv.length; i++) {
    const a = argv[i];
    if (a === '--state') out.state = argv[++i];
    else if (a === '--event') out.event = argv[++i];
    else if (a === '--gates') {
      const v = argv[++i];
      out.gates = v === 'true';
    }
  }
  return out;
}

if (import.meta.url === `file://${process.argv[1]}`) {
  const args = parseArgs(process.argv.slice(2));
  if (!args.state || !args.event) {
    process.stdout.write(JSON.stringify({
      ok: false,
      error: 'usage: autonomy-gate.mjs --state <state> --event <event> [--gates true|false]',
    }) + '\n');
    process.exit(1);
  }
  const result = transition(args.state, args.event, { gates: args.gates });
  process.stdout.write(JSON.stringify(result) + '\n');
  process.exit(result.ok ? 0 : 1);
}
