/**
 * Platform Verification Plan — ref AS/AEGIS-CYBER/VERIFY/2026/001
 * VF-S7 (JIT) — recordAction MISSING-WRITE loss-confirmation (pre-fix, DEV).
 *
 * Fold-in prove-first (advisor 2026-06-11): recordAction was added to the VF-S7
 * scope AFTER the original Step-1 failure-proof (which covered the 4 swallow
 * sinks). Per the advisor it must NOT ride through on that proof — its loss is
 * confirmed separately, here, before the persist is designed.
 *
 * SHAPE differs from the 4 swallow sinks (re-derived from its OWN substrate,
 * server/lib/jit-access.ts L340-381):
 *   - recordAction has NO saveJitGrant call at all (grep: zero DB writes in the
 *     method body). It is a MISSING write, not a swallowed one.
 *   - recordAction has NO route/caller (grep: the only repo-wide reference is its
 *     own definition). So the gap is LATENT — nothing exercises it in production
 *     today. It is demonstrated here by DIRECT method call (no real-path route
 *     exists to exercise), and that latency is stated honestly (Rule 19).
 *
 * Legs:
 *   RA0 harness soundness — owner seeds a durable jit_grants row (actions_used=0)
 *       matching a real in-memory active grant minted by the manager.
 *   RA1 LOSS — call recordAction on that grant; it returns success and bumps
 *       actionsUsed IN MEMORY, but the durable row's actions_used STAYS 0 — the
 *       mutation never reaches storage (the missing-write gap is real).
 *
 * owner = pg.Pool on DATABASE_URL (dev owner; bypasses RLS; out-of-band observer
 * for seed / count / read / cleanup). recordAction itself touches no DB, so no
 * request-tx scaffolding is needed for this leg.
 *
 * Run: npx tsx scripts/vf-s7-jit-recordaction-loss-confirmation.ts   (DEV only)
 */

import pg from "pg";
import { jitAccessManager } from "../server/lib/jit-access";

const owner = new pg.Pool({ connectionString: process.env.DATABASE_URL });
const DEMO_TENANT = "vf-s7-ra-tenant";
const base = Date.now();
const user = `vf-s7-ra-user-${base}`;

async function dbActionsUsed(id: string): Promise<number | null> {
  const r = await owner.query<{ a: number | null }>(
    "SELECT actions_used AS a FROM jit_grants WHERE id = $1",
    [id],
  );
  return r.rows[0]?.a ?? null;
}
async function dbCount(id: string): Promise<number> {
  const r = await owner.query<{ n: string }>(
    "SELECT count(*)::int AS n FROM jit_grants WHERE id = $1",
    [id],
  );
  return Number(r.rows[0].n);
}

async function main() {
  console.log("=".repeat(80));
  console.log(
    "VF-S7 — JIT recordAction MISSING-WRITE loss-confirmation (pre-fix, DEV)",
  );
  console.log("=".repeat(80));

  // Mint a real ACTIVE in-memory grant via the manager. auditor-elevation
  // requiresApproval=false, so the grant is active immediately (no approval leg).
  const req = jitAccessManager.requestAccess(
    user,
    "VF-S7 RA User",
    "auditor",
    "auditor-elevation",
    "vf-s7 recordAction loss-confirmation",
  );
  if (!req.success || !req.grant) {
    console.log(`INCONCLUSIVE — requestAccess failed: ${req.error}`);
    await owner.end();
    process.exit(1);
  }
  const grant = req.grant;
  const id = grant.id;
  console.log(
    `in-memory grant minted: id=${id} status=${grant.status} actionsUsed=${grant.actionsUsed} maxActions=${grant.maxActions ?? "-"}`,
  );

  // ── RA0 — seed a matching DURABLE row (owner bypasses RLS), actions_used=0 ──
  await owner.query(
    `INSERT INTO jit_grants
       (id, user_id, username, original_role, elevated_role, reason, status,
        resources, actions, actions_used, audit_log, expires_at, tenant_id)
     VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13)
     ON CONFLICT (id) DO NOTHING`,
    [
      id, user, "VF-S7 RA User", "auditor", "auditor", "vf-s7 ra seed", "active",
      "[]", JSON.stringify(["read"]), 0, "[]",
      new Date(Date.now() + 3_600_000), DEMO_TENANT,
    ],
  );
  const baseCount = await dbCount(id);
  const baseUsed = await dbActionsUsed(id);
  console.log("-".repeat(80));
  console.log("[RA0] harness soundness — durable row seeded (actions_used=0)");
  console.log(`     observed: count=${baseCount} durableActionsUsed=${baseUsed}`);
  console.log(
    `     VERDICT : ${
      baseCount === 1 && baseUsed === 0
        ? "PASS (durable baseline present)"
        : "ANOMALY (baseline broken — RA1 unreliable)"
    }`,
  );

  // ── RA1 — recordAction mutates IN MEMORY only; durable row must stay 0 ──────
  const ra = jitAccessManager.recordAction(id, "read", "audit-logs", "127.0.0.1");
  await new Promise((r) => setTimeout(r, 200)); // settle (recordAction is sync + DB-free; defensive)
  const memGrant = jitAccessManager.getUserGrants(user).find((g) => g.id === id);
  const memUsed = memGrant?.actionsUsed ?? -1;
  const durUsed = await dbActionsUsed(id);
  const loss = ra.success && memUsed === 1 && durUsed === 0;
  console.log("-".repeat(80));
  console.log("[RA1] recordAction loss — memory mutates, durable row does not");
  console.log(
    "     expect  : recordAction reports success; in-memory actionsUsed=1; durable actions_used STAYS 0 (mutation lost)",
  );
  console.log(
    `     observed: recordActionSuccess=${ra.success}${ra.error ? ` err=${ra.error}` : ""} memActionsUsed=${memUsed} durableActionsUsed=${durUsed}`,
  );
  console.log(
    `     VERDICT : ${
      loss
        ? "PASS (LOSS CONFIRMED: recordAction reports success and bumps memory, but the durable row's actions_used never changes — the missing-write gap is real)"
        : "ANOMALY (loss not reproduced as predicted)"
    }`,
  );
  console.log("-".repeat(80));

  // ── Cleanup (owner bypasses RLS) ───────────────────────────────────────────
  const del = await owner.query(
    "DELETE FROM jit_grants WHERE id = $1 OR tenant_id = $2",
    [id, DEMO_TENANT],
  );
  console.log(`cleanup: deleted ${del.rowCount} jit_grants sentinel row(s).`);
  console.log("=".repeat(80));

  await owner.end();
  process.exit(0); // jitAccessManager's expiration-checker setInterval keeps the loop alive
}

main().catch(async (e) => {
  console.error("FATAL:", e);
  try {
    await owner.end();
  } catch {}
  process.exit(1);
});
