/**
 * API-KEY REVOCATION-RACE FIX — verification battery
 * (Shelf-Sweep AS/PLATFORM/2026/003, revocation-race class).
 *
 * Proves the response-before-commit race on the api_keys ADMIN surface
 * (POST /api/api-keys create, DELETE /api/api-keys/:id revoke) is closed by routing
 * both DML paths through withBypassRls (commit-before-return) instead of the request-tx
 * `db` proxy (which committed at res.finish — AFTER the response was flushed).
 *
 * Why owner read-back (not the auth path) is the authoritative durable signal here:
 *   apiKeyAuth validates via storage.getApiKeyByHash on the PLAIN RLS-bound `db` at the
 *   global /api mount, where the request GUC is "default" (pre-session). A key minted
 *   with the admin's real tenant is therefore NOT visible to that lookup (the documented
 *   RLS-blind api-key quirk — a pre-existing, out-of-scope issue). So an auth-path
 *   "reuse" leg would be hollow. The fix's effect is the DURABLE COMMIT ORDERING, which
 *   we prove by independent (owner / separate-connection) read-back + a deterministic
 *   commit-visibility control. (A black-box HTTP "zero-delay negative" cannot
 *   deterministically reproduce a res.finish micro-window race — any subsequent HTTP
 *   request observes the row after res.finish has fired — so we do NOT claim one; the
 *   class is closed by commit-before-respond wiring + durable read-back + the mechanism
 *   control below. Rule 19 honesty.)
 *
 * Legs (Rule 18 — each pass carries discriminating signals):
 *   1  CREATE durable-before-response  + TII-06 fence (body.tenantId ignored) + hygiene
 *   2  REVOKE durable-before-response  (is_active=false on independent read-back)
 *   3  commit-visibility MECHANISM control (deterministic, paired):
 *        known-good  committed row  → VISIBLE to an independent connection
 *        seeded-gap  uncommitted tx → INVISIBLE to an independent connection
 *      i.e. an independent reader (concurrent request / apiKeyAuth's own connection)
 *      sees a mutation ONLY after commit — exactly the property the fix establishes by
 *      committing before the response instead of at res.finish.
 *
 * DEV/TEST tooling only — never ships in product runtime. Secret discipline (Rule 1):
 * no secret/connection value is printed.
 */

import {
  ProofRun,
  verdict,
  mkSeed,
  seedUser,
  login,
  sessionClient,
  ownerQuery,
  ownerPool,
  deleteByColIn,
  deactivateUsers,
  allocateActorIps,
  endOwnerPool,
  randomUUID,
} from "./lib/proof-harness";

const TENANT = "aegis-sovereign";

interface ApiKeyRow {
  is_active: boolean;
  key_hash: string | null;
  tenant_id: string | null;
}

async function readKey(id: string): Promise<ApiKeyRow | undefined> {
  const rows = await ownerQuery<ApiKeyRow>(
    `SELECT is_active, key_hash, tenant_id FROM api_keys WHERE id = $1`,
    [id],
  );
  return rows[0];
}

/** Independent-connection existence check (a DIFFERENT pooled connection than any
 *  checked-out client) — the "concurrent reader" stand-in. */
async function visibleToIndependentReader(id: string): Promise<boolean> {
  const rows = await ownerQuery<{ one: number }>(
    `SELECT 1 AS one FROM api_keys WHERE id = $1`,
    [id],
  );
  return rows.length === 1;
}

async function main(): Promise<void> {
  const run = new ProofRun(
    "API-KEY REVOCATION-RACE FIX — verify (Shelf-Sweep AS/PLATFORM/2026/003)",
    "DEV",
  );
  const [ip] = allocateActorIps(1);
  const admin = mkSeed("admin", "apikeyfix", "adm");
  await seedUser(admin, TENANT, "APIKEY-FIX probe admin (synthetic, TEST_DELETE_OK)");
  const createdKeyIds: string[] = [];

  try {
    const s = await login(admin, ip);
    const c = sessionClient(s);

    // ── LEG 1 — CREATE commits before response; TII-06 fence; hygiene ──────────
    const bogusTenant = "attacker-tenant-should-be-ignored";
    const post = await c.post("/api/api-keys", {
      name: "race-probe-key",
      permissions: ["read"],
      tenantId: bogusTenant, // TII-06: must be IGNORED (source of truth = session)
    });
    const b1 = post.json as Record<string, unknown>;
    const keyId = typeof b1.id === "string" ? (b1.id as string) : undefined;
    const plainKey = typeof b1.plainKey === "string" ? (b1.plainKey as string) : undefined;
    if (keyId) createdKeyIds.push(keyId);
    const row1 = keyId ? await readKey(keyId) : undefined;
    const s1 = {
      httpStatus: post.status,
      plainKeyAegisPrefixed: !!plainKey && plainKey.startsWith("aegis_"),
      keyHashNotInResponse: b1.keyHash === undefined,
      rowPresentDurable: !!row1,
      rowActive: row1?.is_active === true,
      keyHashedAtRest: !!row1?.key_hash && row1.key_hash !== plainKey,
      tenantFromSessionNotBody: row1?.tenant_id === TENANT,
      bogusTenantSent: bogusTenant,
    };
    const pass1 =
      s1.httpStatus === 200 &&
      s1.plainKeyAegisPrefixed &&
      s1.keyHashNotInResponse &&
      s1.rowPresentDurable &&
      s1.rowActive &&
      s1.keyHashedAtRest &&
      s1.tenantFromSessionNotBody;
    run.leg({
      id: "1",
      scenario:
        "CREATE — key durable before response; plainKey returned once; keyHash never echoed; key hashed at rest; tenant from session not body (TII-06)",
      expectation:
        "POST 200; body.plainKey aegis_-prefixed + body.keyHash undefined; owner read-back present + is_active=true + key_hash present≠plaintext + tenant_id=session tenant (bogus body.tenantId ignored)",
      observed: `HTTP ${post.status}; id=${keyId}; active=${row1?.is_active}; tenant=${row1?.tenant_id} (sent bogus '${bogusTenant}'); keyHashEchoed=${b1.keyHash !== undefined}`,
      verdict: pass1
        ? verdict.verified(
            "the awaited withBypassRls wrapper commits the create BEFORE res is sent (ordering proof); the independent owner read-back proves the durable effect (row present, active); TII-06 + at-rest-hash + single-disclosure hygiene intact",
          )
        : verdict.fail(),
      pass: pass1,
      signals: s1,
    });

    // ── LEG 2 — REVOKE commits before response (durable is_active=false) ───────
    let delStatus = 0;
    let delSuccess = false;
    let row2: ApiKeyRow | undefined;
    if (keyId) {
      const del = await c.del(`/api/api-keys/${keyId}`);
      delStatus = del.status;
      delSuccess = (del.json as Record<string, unknown>).success === true;
      row2 = await readKey(keyId); // independent read-back immediately after the 200
    }
    const s2 = {
      httpStatus: delStatus,
      successTrue: delSuccess,
      rowStillPresent: !!row2,
      durablyInactive: row2?.is_active === false,
    };
    const pass2 = s2.httpStatus === 200 && s2.successTrue && s2.rowStillPresent && s2.durablyInactive;
    run.leg({
      id: "2",
      scenario:
        "REVOKE — deactivation durable before the 200 (no fail-OPEN window on this authentication surface)",
      expectation:
        "DELETE 200 success:true; owner read-back immediately after the response shows is_active=false (row retained, not hard-deleted)",
      observed: `HTTP ${delStatus}; success=${delSuccess}; is_active(after)=${row2?.is_active}`,
      verdict: pass2
        ? verdict.verified(
            "the awaited withBypassRls wrapper commits the revoke BEFORE res is sent (ordering proof, closing the res.finish race); the independent read-back taken right after the 200 proves the durable effect (is_active=false, row retained)",
          )
        : verdict.fail(),
      pass: pass2,
      signals: s2,
    });

    // ── LEG 3 — commit-visibility MECHANISM control (deterministic, paired) ────
    // Known-good: a COMMITTED row is visible to an independent connection.
    const goodId = randomUUID();
    createdKeyIds.push(goodId);
    await ownerPool().query(
      `INSERT INTO api_keys (id, name, key_hash, key_prefix, tenant_id, permissions, rate_limit, is_active)
       VALUES ($1,$2,$3,$4,$5,$6,$7,true)`,
      [goodId, "race-sentinel-committed", `h_${goodId}`, "aegis_se", "default", JSON.stringify(["read"]), 1000],
    );
    const visibleAfterCommit = await visibleToIndependentReader(goodId);

    // Seeded-gap: an UNCOMMITTED insert (open tx) is INVISIBLE to an independent
    // connection — the shape of the bug (response sent while the tx is still open).
    const gapId = randomUUID();
    const holdClient = await ownerPool().connect();
    let visibleDuringOpenTx = true; // pessimistic default — must be flipped to false
    try {
      await holdClient.query("BEGIN");
      await holdClient.query(
        `INSERT INTO api_keys (id, name, key_hash, key_prefix, tenant_id, permissions, rate_limit, is_active)
         VALUES ($1,$2,$3,$4,$5,$6,$7,true)`,
        [gapId, "race-sentinel-uncommitted", `h_${gapId}`, "aegis_se", "default", JSON.stringify(["read"]), 1000],
      );
      visibleDuringOpenTx = await visibleToIndependentReader(gapId); // separate conn → must be false
      await holdClient.query("ROLLBACK");
    } finally {
      holdClient.release();
    }

    const s3 = {
      knownGood_committedRowVisible: visibleAfterCommit === true,
      seededGap_uncommittedRowInvisible: visibleDuringOpenTx === false,
    };
    const pass3 = s3.knownGood_committedRowVisible && s3.seededGap_uncommittedRowInvisible;
    run.leg({
      id: "3",
      scenario:
        "MECHANISM control — an independent reader sees a write ONLY after commit (the property the fix establishes by committing before the response, not at res.finish)",
      expectation:
        "committed row → VISIBLE to an independent connection (known-good); uncommitted open-tx row → INVISIBLE to an independent connection (seeded-gap)",
      observed: `committedVisible=${visibleAfterCommit}; uncommittedVisible=${visibleDuringOpenTx}`,
      verdict: pass3
        ? verdict.verified(
            "paired control deterministically discriminates committed (visible) from uncommitted (invisible) — so the LEG-1/2 read-backs are meaningful proof the routes commit before responding",
          )
        : verdict.fail(),
      pass: pass3,
      signals: s3,
    });

    run.report();
    await run.writeJson("scripts/.artifacts/apikey-revocation-race-results.json");
    const { allPass } = run.acceptance();
    if (!allPass) process.exitCode = 1;
  } finally {
    // Carry-safe teardown: api_keys is a NON-audit table → hard-delete the synthetic
    // probe rows; deactivate the synthetic admin (hard-delete blocked by audit FK).
    if (createdKeyIds.length) await deleteByColIn("api_keys", "id", createdKeyIds).catch(() => {});
    await deactivateUsers([admin.id]).catch(() => {});
    await endOwnerPool();
  }
}

main().catch((e) => {
  console.error("verify-apikey-revocation-race FAILED:", e);
  process.exit(1);
});
