/**
 * Platform Verification Plan — ref AS/AEGIS-CYBER/VERIFY/2026/001
 * VF-S7 (JIT — silent-failure sweep module 1): JIT-access fire-and-forget
 * durable-write loss — STEP-1 FUNCTIONAL-FAILURE DEMONSTRATION (pre-fix).
 *
 * STATUS: pre-fix. No fix is applied. This script PROVES the defect and
 * determines the failure MODE EMPIRICALLY. It deliberately does NOT inherit
 * PAM/VF-S6's Mode-A answer: JIT's timing differs — the route handler is
 * synchronous and fires `JitDB.saveJitGrant(grant).catch(() => {})`
 * fire-and-forget AFTER building the grant, where PAM fired in-request. That
 * post-construction timing is exactly why JIT's mode could differ, so the
 * fire-and-forget real-path leg (S5) is load-bearing, not ceremony.
 *
 * Root cause (re-derived from JIT's OWN substrate, server/lib/jit-access.ts):
 *   - jit-access-db.saveJitGrant accepts an optional `tenantId` — the DB layer is
 *     tenant-READY. BUT the JITAccessGrant interface (L22-41) has NO tenantId
 *     field and the manager NEVER threads one (grep: zero tenantId references in
 *     jit-access.ts). So grant.tenantId is always undefined → jit_grants.tenant_id
 *     lands NULL → RLS WITH CHECK reject (42501) → swallowed by .catch(() => {}).
 *   - This differs in SHAPE from PAM (PAM had no tenant param at all; JIT has the
 *     param but the caller never supplies a value) — same NULL outcome.
 *   - jit_grants IS RLS-protected (server/lib/rls-init.ts TENANT_TABLES, L77).
 *
 * Legs (mirror VF-S6 PART-A + a JIT-specific fire-and-forget real-path leg):
 *   S0 harness soundness — owner direct insert observable.
 *   S1 POSITIVE control — raw saveJitGrant WITH tenant + GUC match, awaited →
 *      row LANDS (count=1, tenant-correct). Proves the sink CAN persist (the fix
 *      shape) AND doubles as a non-tenant second-bug detector.
 *   S2 NEGATIVE — raw saveJitGrant NO tenant (the real caller), awaited
 *      in-request → 42501, lost (count=0). The headline defect.
 *   S3 THE DISEASE (Mode-A probe, awaited) — legit co-write + tenant-blind write
 *      in ONE request tx → does the tenant-blind write poison the tx and destroy
 *      the correct co-write?
 *   S4 DETACHED (Mode-B reference) — tenant-blind write with NO request context →
 *      42501, lost alone, no shared tx to poison.
 *   S5 REAL-PATH FIRE-AND-FORGET (load-bearing) — the actual
 *      jitAccessManager.requestAccess() fires saveJitGrant fire-and-forget
 *      (UNAWAITED) inside a request tx after a legit co-write; the handler returns
 *      and the tx commits. Determines which mode JIT's real timing lands.
 *   S6 SECOND-BUG ISOLATION — take the REAL manager-constructed grant, inject a
 *      correct tenant, await the write. Lands → only the missing tenant is the
 *      bug; fails for another reason → a second bug exists.
 *
 * Connections (mirror VF-S6):
 *   - owner = pg.Pool on DATABASE_URL (dev owner; bypasses RLS; out-of-band
 *     observer for count / positive-control insert / cleanup).
 *   - real path = imported JitDB sinks + jitAccessManager singleton via the module
 *     `db` proxy (appPool = aegis_app restricted role; RLS-enforced). The request
 *     context uses a pinned client + manual BEGIN + LOCAL tenant GUC +
 *     tenantContext ALS, and reports whether COMMIT silently degraded to ROLLBACK
 *     (the Mode-A signature). saveJitGrant opens no nested transaction, so manual
 *     BEGIN reproduces the production request tx for this defect exactly.
 *
 * Run: npx tsx scripts/vf-s7-jit-persistence-demonstration.ts   (DEV only)
 */

import pg from "pg";
import { appPool, tenantContext, makeClientRunner } from "../server/db";
import * as JitDB from "../server/lib/jit-access-db";
import { jitAccessManager } from "../server/lib/jit-access";

const owner = new pg.Pool({ connectionString: process.env.DATABASE_URL });

const DEMO_TENANT = "vf-s7-tenant";
const base = Date.now();
const ID = {
  s0: `VF-S7-GR-S0-${base}`,
  s1: `VF-S7-GR-S1POS-${base}`,
  s2: `VF-S7-GR-S2NEG-${base}`,
  s3legit: `VF-S7-GR-S3LEGIT-${base}`,
  s3broken: `VF-S7-GR-S3BROKEN-${base}`,
  s4: `VF-S7-GR-S4DETACH-${base}`,
  s5legit: `VF-S7-GR-S5LEGIT-${base}`,
};
const captured: { grantIds: string[] } = { grantIds: [] };

const settle = (ms = 300) => new Promise((r) => setTimeout(r, ms));
const errStr = (e: any) => `${e?.code ?? ""} ${e?.message ?? String(e)}`.trim();

async function countGrant(id: string): Promise<number> {
  if (!id) return -1;
  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 tenantOfGrant(id: string): Promise<string | null> {
  const r = await owner.query<{ t: string | null }>(
    "SELECT tenant_id AS t FROM jit_grants WHERE id = $1",
    [id],
  );
  return r.rows[0]?.t ?? null;
}

/** A jit_grants payload in the exact shape saveJitGrant expects.
 *  tenantId is the ONLY variable — omitting it reproduces the real pre-fix caller
 *  (whose grant object has no tenantId field at all). */
function grantPayload(id: string, tenantId?: string) {
  const now = new Date();
  return {
    id,
    userId: "vf-s7-user",
    username: "VF-S7 User",
    originalRole: "auditor",
    elevatedRole: "auditor",
    reason: "vf-s7 demonstration sentinel",
    status: "active",
    policyId: "auditor-elevation",
    resources: ["audit-logs"],
    actions: ["read"],
    actionsUsed: 0,
    auditLog: [{ timestamp: now, action: "requested", details: "vf-s7" }],
    expiresAt: new Date(now.getTime() + 3_600_000),
    grantedAt: now,
    tenantId,
  };
}

interface PhaseDiag {
  commitCommand: string; // "COMMIT" = clean; "ROLLBACK" = tx was poisoned/aborted
  commitErr: string;
  phaseErr: string;
}

/** Request runtime faithful to tenantMiddleware's shape for this defect: a pinned
 *  appPool client + manual BEGIN + LOCAL tenant GUC + tenantContext ALS active.
 *  COMMIT is attempted after fn returns (as the middleware commits after the
 *  handler returns / res finishes) and the actual command tag is reported
 *  (PG returns "ROLLBACK" for COMMIT on an aborted tx — the Mode-A signature). */
async function runRequestPhase(
  tenantId: string,
  fn: () => Promise<void> | void,
): Promise<PhaseDiag> {
  const client = await appPool.connect();
  const diag: PhaseDiag = { commitCommand: "", commitErr: "", phaseErr: "" };
  try {
    await client.query("BEGIN");
    await client.query("SELECT set_config('app.current_tenant_id', $1, true)", [
      tenantId,
    ]);
    const runner = makeClientRunner(client);
    try {
      await tenantContext.run({ runner, tenantId }, () => fn());
    } catch (e: any) {
      diag.phaseErr = errStr(e);
    }
    try {
      const r = await client.query("COMMIT");
      diag.commitCommand = r.command; // "ROLLBACK" if the tx was poisoned
    } catch (e: any) {
      diag.commitErr = errStr(e);
      try {
        await client.query("ROLLBACK");
      } catch {}
    }
  } finally {
    client.release();
  }
  return diag;
}

type Row = {
  id: string;
  scenario: string;
  expectation: string;
  observed: string;
  verdict: string;
};
const rows: Row[] = [];
const record = (r: Row) => rows.push(r);

async function main() {
  console.log("=".repeat(80));
  console.log(
    "VF-S7 — JIT-access fire-and-forget durable-write loss — STEP-1 PROOF (pre-fix, DEV)",
  );
  console.log("=".repeat(80));

  // ── S0 — harness soundness ────────────────────────────────────────────────
  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)`,
    [
      ID.s0, "vf-s7-user", "VF-S7 User", "auditor", "auditor",
      "vf-s7 s0 harness", "active", "[]", "[]", 0, "[]",
      new Date(Date.now() + 3_600_000), DEMO_TENANT,
    ],
  );
  const s0n = await countGrant(ID.s0);
  record({
    id: "S0",
    scenario: "harness soundness — owner direct insert (bypasses RLS)",
    expectation: "owner observer sees the row (count=1)",
    observed: `count=${s0n} tenant=${await tenantOfGrant(ID.s0)}`,
    verdict:
      s0n === 1
        ? "PASS (harness sound)"
        : "ANOMALY (harness broken — later legs unreliable)",
  });

  // ── S1 — POSITIVE control (fix shape) + non-tenant second-bug detector ─────
  const d1 = await runRequestPhase(DEMO_TENANT, async () => {
    await JitDB.saveJitGrant(grantPayload(ID.s1, DEMO_TENANT));
  });
  const s1n = await countGrant(ID.s1);
  const s1t = await tenantOfGrant(ID.s1);
  record({
    id: "S1",
    scenario:
      "raw saveJitGrant WITH tenant threaded + GUC match (awaited, in-request)",
    expectation: "row LANDS durable + tenant-correct (count=1); clean COMMIT",
    observed: `count=${s1n} tenant=${s1t ?? "-"} commit=${d1.commitCommand} phaseErr=${d1.phaseErr || "-"}`,
    verdict:
      s1n === 1 && s1t === DEMO_TENANT && d1.commitCommand === "COMMIT"
        ? "PASS (POSITIVE: the sink CAN persist when a tenant is threaded — fix shape valid; no non-tenant second bug)"
        : `ANOMALY${d1.phaseErr ? ` — phaseErr=${d1.phaseErr} (POSSIBLE SECOND BUG: correct-tenant write still failed)` : ""}`,
  });

  // ── S2 — NEGATIVE (the real pre-fix caller shape: no tenant) ───────────────
  const d2 = await runRequestPhase(DEMO_TENANT, async () => {
    await JitDB.saveJitGrant(grantPayload(ID.s2)); // NO tenant
  });
  const s2n = await countGrant(ID.s2);
  const rls2 = d2.phaseErr.includes("42501");
  record({
    id: "S2",
    scenario:
      "raw saveJitGrant NO tenant (the real pre-fix caller), awaited in-request",
    expectation: "RLS WITH CHECK reject (42501); durable row lost (count=0)",
    observed: `count=${s2n} phaseErr=${d2.phaseErr || "-"} commit=${d2.commitCommand}`,
    verdict:
      s2n === 0 && rls2
        ? "PASS (NEGATIVE: tenant-blind write rejected by RLS, durable row lost — the headline defect)"
        : "ANOMALY",
  });

  // ── S3 — THE DISEASE (Mode-A probe, awaited) ───────────────────────────────
  let s3legitErr = "";
  let s3brokenErr = "";
  const d3 = await runRequestPhase(DEMO_TENANT, async () => {
    try {
      await JitDB.saveJitGrant(grantPayload(ID.s3legit, DEMO_TENANT)); // legit co-write
    } catch (e: any) {
      s3legitErr = errStr(e);
    }
    try {
      await JitDB.saveJitGrant(grantPayload(ID.s3broken)); // NO tenant → poisons tx
    } catch (e: any) {
      s3brokenErr = errStr(e);
    }
  });
  const s3legitN = await countGrant(ID.s3legit);
  const s3brokenN = await countGrant(ID.s3broken);
  const modeA =
    s3legitN === 0 && s3brokenN === 0 && d3.commitCommand === "ROLLBACK";
  const modeBish = s3legitN === 1 && s3brokenN === 0;
  record({
    id: "S3",
    scenario:
      "legit co-write + tenant-blind write in ONE request tx (Mode-A probe)",
    expectation:
      "tenant-blind write poisons tx → correct co-write DESTROYED (legit=0, broken=0, COMMIT→ROLLBACK)",
    observed: `legitN=${s3legitN} brokenN=${s3brokenN} commit=${d3.commitCommand} brokenErr=${s3brokenErr || "-"} legitErr=${s3legitErr || "-"}`,
    verdict: modeA
      ? "PASS (Mode A CONFIRMED: a correct, unrelated co-tx write is collaterally DESTROYED by the swallowed tenant-blind write)"
      : modeBish
        ? "MODE B (no collateral: broken write lost alone, co-write survived)"
        : "ANOMALY",
  });

  // ── S4 — DETACHED (Mode-B reference) ───────────────────────────────────────
  let s4err = "";
  try {
    await JitDB.saveJitGrant(grantPayload(ID.s4)); // no context, no tenant
  } catch (e: any) {
    s4err = errStr(e);
  }
  const s4n = await countGrant(ID.s4);
  record({
    id: "S4",
    scenario: "tenant-blind write with NO request context (detached)",
    expectation:
      "rejected; total loss (count=0); no co-tx collateral (nothing else in flight)",
    observed: `count=${s4n} err=${s4err || "-"}`,
    verdict:
      s4n === 0 && s4err
        ? "PASS (Mode B reference: detached tenant-blind write lost alone, no shared tx to poison)"
        : "ANOMALY",
  });

  // ── S5 — REAL-PATH FIRE-AND-FORGET (the load-bearing JIT-specific leg) ──────
  const rtUser = `vf-s7-rt-${base}`;
  let mintedId = "";
  let rtNote = "";
  let rtSuccess = "no";
  const d5 = await runRequestPhase(DEMO_TENANT, async () => {
    // (a) a legit co-write that WOULD persist on its own (proven by S1) —
    //     models any durable co-tx write that shares the request transaction
    await JitDB.saveJitGrant(grantPayload(ID.s5legit, DEMO_TENANT));
    // (b) the REAL path: the manager fires saveJitGrant fire-and-forget
    //     (UNAWAITED) and returns synchronously — exactly the production timing
    const res = jitAccessManager.requestAccess(
      rtUser,
      "VF-S7 RealPath User",
      "auditor",
      "auditor-elevation",
      "vf-s7 real-path fire-and-forget",
    );
    if (res.success && res.grant) {
      rtSuccess = "yes";
      mintedId = res.grant.id;
      captured.grantIds.push(mintedId);
    } else {
      rtNote = `requestAccess error: ${res.error}`;
    }
    // fn returns WITHOUT awaiting the fire-and-forget insert
  });
  await settle();
  const s5legitN = await countGrant(ID.s5legit);
  const s5grantN = await countGrant(mintedId);
  const realModeA =
    rtSuccess === "yes" &&
    s5grantN === 0 &&
    s5legitN === 0 &&
    d5.commitCommand === "ROLLBACK";
  const realModeB =
    rtSuccess === "yes" &&
    s5grantN === 0 &&
    s5legitN === 1 &&
    d5.commitCommand === "COMMIT";
  record({
    id: "S5",
    scenario:
      "REAL jitAccessManager.requestAccess() fire-and-forget in a request tx (post-construction timing)",
    expectation:
      "requestAccess returns success; the durable grant row is LOST (count=0); mode determined empirically",
    observed: `requestAccessSuccess=${rtSuccess} mintedGrantN=${s5grantN} legitCoWriteN=${s5legitN} commit=${d5.commitCommand}${rtNote ? ` note=${rtNote}` : ""}`,
    verdict: realModeA
      ? "PASS (REAL PATH = Mode A: requestAccess reports success while the grant row is silently lost AND the co-tx write is collaterally destroyed)"
      : realModeB
        ? "PASS (REAL PATH = Mode B: requestAccess reports success while the grant row is silently lost; co-tx write survived — no collateral)"
        : rtNote
          ? `INCONCLUSIVE — ${rtNote}`
          : "ANOMALY",
  });

  // ── S6 — SECOND-BUG ISOLATION (real manager grant + correct tenant) ────────
  const res6 = jitAccessManager.requestAccess(
    `vf-s7-s6-${base}`,
    "VF-S7 S6 User",
    "auditor",
    "auditor-elevation",
    "vf-s7 second-bug isolation",
  );
  if (res6.success && res6.grant) {
    const s6id = res6.grant.id;
    captured.grantIds.push(s6id);
    let s6err = "";
    const d6 = await runRequestPhase(DEMO_TENANT, async () => {
      try {
        await JitDB.saveJitGrant({
          ...(res6.grant as any),
          tenantId: DEMO_TENANT,
        });
      } catch (e: any) {
        s6err = errStr(e);
      }
    });
    const s6n = await countGrant(s6id);
    const s6t = await tenantOfGrant(s6id);
    record({
      id: "S6",
      scenario:
        "REAL manager-constructed grant + correct tenant injected, awaited",
      expectation:
        "row LANDS (count=1, tenant-correct) → only the missing tenant is the bug; no second persistence defect",
      observed: `count=${s6n} tenant=${s6t ?? "-"} commit=${d6.commitCommand} err=${s6err || "-"}`,
      verdict:
        s6n === 1 && s6t === DEMO_TENANT
          ? "PASS (no second bug: the real manager grant persists cleanly once a correct tenant is supplied)"
          : `SECOND BUG SUSPECTED — ${s6err || "row did not land for a non-tenant reason"}`,
    });
  } else {
    record({
      id: "S6",
      scenario:
        "REAL manager-constructed grant + correct tenant injected, awaited",
      expectation: "n/a",
      observed: `SKIPPED — requestAccess failed: ${res6.error}`,
      verdict: "INCONCLUSIVE",
    });
  }

  // ── Report ─────────────────────────────────────────────────────────────────
  console.log("");
  for (const r of rows) {
    console.log("-".repeat(80));
    console.log(`[${r.id}] ${r.scenario}`);
    console.log(`     expect  : ${r.expectation}`);
    console.log(`     observed: ${r.observed}`);
    console.log(`     VERDICT : ${r.verdict}`);
  }
  console.log("-".repeat(80));

  // ── Cleanup (owner bypasses RLS) ────────────────────────────────────────────
  const ids = [
    ID.s0, ID.s1, ID.s2, ID.s3legit, ID.s3broken, ID.s4, ID.s5legit,
    ...captured.grantIds,
  ];
  const del = await owner.query(
    "DELETE FROM jit_grants WHERE id = ANY($1::text[]) OR tenant_id = $2",
    [ids, DEMO_TENANT],
  );
  console.log(`cleanup: deleted ${del.rowCount} jit_grants sentinel row(s).`);
  console.log("=".repeat(80));

  await owner.end();
  await appPool.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 {}
  try {
    await appPool.end();
  } catch {}
  process.exit(1);
});
