/**
 * OODA HITL gate — sprint-525:quick-2.
 *
 * Blocks the OODA `act` phase until a human approves (or rejects) the
 * pending decision. In `dry-run` execution mode the gate is a no-op
 * (auto-approve) so simulation runs do not require human attention.
 *
 * Live mode persists a row in `hitl_approvals` (status=`pending`) and
 * polls every 2s until a row reaches `approved` / `rejected` or until
 * the configured timeout elapses. On timeout, the `onTimeout` policy
 * decides the verdict.
 *
 * The DbClient interface is the same minimal subset used elsewhere in
 * the SDK (compatible with pg.Pool, pg.Client, and test mocks).
 *
 * @public
 */
// ─── Defaults ─────────────────────────────────────────────────────────────────
const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000;
const DEFAULT_POLL_INTERVAL_MS = 2000;
const DEFAULT_ON_TIMEOUT = "reject";
/**
 * Wait for a HITL approval before allowing the agent to commit the act
 * phase. In `dry-run` mode this short-circuits to `approved=true` so
 * simulation runs are non-blocking.
 *
 * Live mode contract:
 *   1. INSERT a row in `hitl_approvals` with status='pending'
 *   2. Poll every `pollIntervalMs` (default 2s) for status change
 *   3. Resolve when status transitions to approved/rejected
 *   4. On timeout: apply onTimeout policy (default 'reject')
 *
 * The polling interval is intentionally generous (2s) to avoid DB
 * pressure under sustained workloads — UX latency is bounded by the
 * human approval round-trip anyway.
 */
export async function waitForHITLApproval(db, args, options = {}) {
    // Auto-approve in dry-run regardless of DB state.
    if (args.executionMode === "dry-run") {
        return { approved: true, timedOut: false, resolvedBy: "dry-run-auto" };
    }
    if (args.executionMode !== "live") {
        throw new Error(`[ooda/hitl-gate] invalid executionMode: ${String(args.executionMode)}`);
    }
    const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
    const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
    const onTimeout = options.onTimeout ?? DEFAULT_ON_TIMEOUT;
    // 1. INSERT pending row (returns id).
    const insert = await db.query(`INSERT INTO hitl_approvals
       (run_id, agent_id, decision_payload, status, requested_at)
     VALUES
       ($1, $2, $3::jsonb, 'pending', now())
     RETURNING id`, [args.runId, args.agentId, JSON.stringify(args.decisionPayload)]);
    const row = insert.rows[0];
    if (!row) {
        throw new Error("[ooda/hitl-gate] insert returned no row");
    }
    const hitlId = row.id;
    // 2. Poll loop with hard deadline.
    const deadline = Date.now() + timeoutMs;
    while (Date.now() < deadline) {
        const remaining = deadline - Date.now();
        const sleepMs = Math.min(pollIntervalMs, Math.max(remaining, 0));
        await sleep(sleepMs);
        const poll = await db.query(`SELECT id, status, rationale, resolved_by
         FROM hitl_approvals
        WHERE id = $1`, [hitlId]);
        const current = poll.rows[0];
        if (!current) {
            // Row vanished (cancellation) — treat as rejected.
            return { approved: false, timedOut: false, rationale: "row-missing" };
        }
        if (current.status === "approved") {
            return {
                approved: true,
                timedOut: false,
                rationale: current.rationale ?? undefined,
                resolvedBy: current.resolved_by ?? undefined,
            };
        }
        if (current.status === "rejected") {
            return {
                approved: false,
                timedOut: false,
                rationale: current.rationale ?? undefined,
                resolvedBy: current.resolved_by ?? undefined,
            };
        }
    }
    // 3. Timeout reached — apply policy.
    const approvedOnTimeout = onTimeout === "approve" || onTimeout === "continue-skip";
    return {
        approved: approvedOnTimeout,
        timedOut: true,
        rationale: `timeout:${onTimeout}`,
    };
}
function sleep(ms) {
    return new Promise((resolve) => {
        if (ms <= 0) {
            resolve();
            return;
        }
        setTimeout(resolve, ms);
    });
}
//# sourceMappingURL=hitl-gate.js.map