/**
 * Pure decision predicate for auto-redeeming a saved OpenAI Codex rate-limit
 * reset, plus the process-wide coordinator that serializes attempts.
 *
 * WHY THIS IS REACTIVE-ONLY (never proactive):
 * The only trustworthy "blocked right now" signal is a live 429 /
 * `usage_limit_reached` from a request authenticated as the session's active
 * Codex credential. The session hook calls this predicate from the usage-limit
 * branch of the retry pipeline, *after* free remedies (sibling-account switch)
 * fail and *before* model fallback. A proactive surface (the status-line usage
 * poll) cannot be used: at `used_percent < 100` the account is not actually
 * limited, so redeeming would be a credit-wasting no-op; at exactly 100 the
 * user may be idle, so the freshly-reset weekly window would tick away with
 * nobody working. Saved resets are a scarce, ~monthly, effectively
 * irreversible resource — every gate here is biased to precision over recall:
 * we would rather miss a redeem than waste a credit.
 *
 * THE DECISION-2 TRAP (status MUST NOT be used to find the blocker):
 * `openai-codex.ts` applies the top-level `rate_limit.limit_reached` flag to
 * BOTH the primary (5h) and secondary (weekly) `buildUsageLimit` calls, so when
 * an account is blocked, *both* limit entries carry `status: "exhausted"`
 * regardless of which window is actually at 100%. Only `amount.usedFraction`
 * disambiguates which window is the real blocker. This module therefore keys
 * eligibility off exact limit ids (`openai-codex:primary` /
 * `openai-codex:secondary`) and `usedFraction`, never off `status`.
 *
 * ANTI-WASTE GATES (in evaluation order): the policy must not be set to "no";
 * the active model must be Codex (not Spark — a Spark block lives on a
 * separate meter and it is unknown whether a credit even resets it); a fresh
 * usage report for the active account must confirm `limitReached`; the WEEKLY
 * (secondary) window must be genuinely exhausted — a 5h-only block self-heals
 * within the hour, so a credit spent there buys nothing; the natural reset must be far
 * enough away to justify spending a ~30-day credit yet within one plausible
 * window length; a credit must be verifiably available above the reserve; and
 * the same block episode must not have been attempted already (debounce +
 * per-account cooldown). All of this is pure — no fetches, no IO. The only
 * stateful piece is the {@link CodexAutoRedeemCoordinator} container, whose
 * read-only views are passed in so the predicate itself stays deterministic.
 */
import type { OAuthAccountIdentity, ResetCreditTarget, UsageReport } from "@oh-my-pi/pi-ai";
import type { CodexAutoRedeemMode } from "../config/settings-schema.js";
/** Weekly window counts as exhausted at `usedFraction >= 0.999` (used_percent >= 99.9). */
export declare const WEEKLY_EXHAUSTED_MIN_FRACTION = 0.999;
/** A weekly reset can never be more than one window length (7d) away; +1h slack for skew. */
export declare const MAX_PLAUSIBLE_REMAINING_MS: number;
/** Report must be no older than the 5-min usage cache TTL plus slack. */
export declare const REPORT_FRESHNESS_MS: number;
/** Per-account cooldown that catches blockKey drift across a minute boundary. */
export declare const ATTEMPT_COOLDOWN_MS = 60000;
/** Minute bucket for blockKey, absorbing `reset_after_seconds`-derived jitter. */
export declare const DEBOUNCE_BUCKET_MS = 60000;
export declare function shouldEvaluateCodexAutoRedeem(mode: CodexAutoRedeemMode): boolean;
export declare function shouldPromptCodexAutoRedeem(mode: CodexAutoRedeemMode): boolean;
export type CodexAutoRedeemSkipReason = "disabled" | "wrong-provider" | "spark-model" | "no-identity" | "no-report" | "stale-report" | "not-limit-reached" | "weekly-not-exhausted" | "no-reset-time" | "reset-too-soon" | "reset-implausible" | "credits-unknown" | "reserve" | "already-attempted" | "cooldown";
export interface CodexAutoRedeemInput {
    nowMs: number;
    /** `this.model.provider`. */
    provider: string;
    /** `this.model.id`. */
    modelId: string;
    settings: {
        autoRedeem: boolean;
        minBlockedMinutes: number;
        keepCredits: number;
    };
    /** `getOAuthAccountIdentity("openai-codex", sessionId)`, captured at hook entry before any await. */
    identity: OAuthAccountIdentity | undefined;
    /** `session.fetchUsageReports()` (≤5-min cache). */
    reports: UsageReport[] | null;
    attemptedBlockKeys: ReadonlySet<string>;
    lastAttemptAtByAccount: ReadonlyMap<string, number>;
}
export interface CodexAutoRedeemRedeemDecision {
    redeem: true;
    target: ResetCreditTarget;
    accountKey: string;
    blockKey: string;
    weeklyResetAtMs: number;
    remainingMs: number;
    availableCount: number;
}
export type CodexAutoRedeemDecision = CodexAutoRedeemRedeemDecision | {
    redeem: false;
    reason: CodexAutoRedeemSkipReason;
};
/**
 * Decide whether to auto-redeem a saved Codex reset for the active account.
 *
 * Pure: every gate below is a function of the snapshot inputs only. Order
 * matters — cheapest / most-decisive gates first so the common "not eligible"
 * paths short-circuit before any account/report matching.
 */
export declare function evaluateCodexAutoRedeem(input: CodexAutoRedeemInput): CodexAutoRedeemDecision;
/**
 * Process-wide (NOT per-session) coordinator state. Parallel subagent sessions
 * share the same Codex accounts and must not race a double-spend, so this is a
 * single shared container, not a per-session field.
 *
 * - `attemptedBlockKeys`: one attempt EVER per block episode, regardless of
 *   outcome — recorded before calling the consume so exceptions can't re-enter.
 * - `lastAttemptAtByAccount`: per-account cooldown timestamps (epoch ms),
 *   catching blockKey drift across a minute boundary.
 * - `inFlightByAccount`: serializes per account — a second session for the same
 *   account adopts the in-flight promise instead of starting a second consume.
 */
export interface CodexAutoRedeemCoordinator {
    attemptedBlockKeys: Set<string>;
    lastAttemptAtByAccount: Map<string, number>;
    inFlightByAccount: Map<string, Promise<boolean>>;
}
export declare const defaultCodexAutoRedeemCoordinator: CodexAutoRedeemCoordinator;
