/**
 * MemoryHITLStateStore — in-process HITL state store.
 *
 * Suitable for tests, local dev, and single-instance deployments.
 * Multi-instance prod deployments must use PostgresHITLStateStore.
 *
 * @public
 */
import { HITLNotFoundError, validateTransition, } from "../../ports/hitl.js";
const POLL_INTERVAL_MS = 100;
export class MemoryHITLStateStore {
    #store = new Map();
    async request(req) {
        this.#store.set(req.id, { request: req, state: "pending" });
        return req.id;
    }
    async getState(id) {
        const entry = this.#store.get(id);
        if (!entry)
            throw new HITLNotFoundError(id);
        return entry.state;
    }
    async await(id, timeoutMs) {
        const deadline = timeoutMs != null ? Date.now() + timeoutMs : Infinity;
        for (;;) {
            const state = await this.getState(id);
            if (state !== "pending")
                return state;
            if (Date.now() >= deadline)
                return state;
            // Wait one poll tick (or remaining budget, whichever is shorter)
            const remaining = deadline - Date.now();
            const wait = Math.min(POLL_INTERVAL_MS, remaining > 0 ? remaining : 0);
            await new Promise((resolve) => setTimeout(resolve, wait));
            // Re-check deadline after sleeping
            if (Date.now() >= deadline)
                return await this.getState(id);
        }
    }
    async resolve(id, decision, by) {
        const entry = this.#store.get(id);
        if (!entry)
            throw new HITLNotFoundError(id);
        validateTransition(entry.state, decision);
        entry.state = decision;
        entry.decision = decision;
        entry.decidedBy = by;
        entry.decidedAt = new Date();
    }
    async expire(id) {
        const entry = this.#store.get(id);
        if (!entry)
            throw new HITLNotFoundError(id);
        validateTransition(entry.state, "expired");
        entry.state = "expired";
    }
    /**
     * Called by runExpireJob to expire all overdue pending requests.
     * Not part of HITLPort — called via the _expireOverdue duck-type hook.
     */
    async _expireOverdue() {
        const now = new Date();
        for (const [id, entry] of this.#store.entries()) {
            if (entry.state === "pending" && new Date(entry.request.deadline) < now) {
                entry.state = "expired";
                // Best-effort: if validateTransition would throw, we already checked state=pending above
                void id; // keep the binding in scope
            }
        }
    }
}
//# sourceMappingURL=memory-state-store.js.map