/**
 * Rate Limit Tracker Service
 *
 * An in-memory service that tracks which executables are rate-limited
 * and when their limits reset. Used by the dispatch system to avoid
 * spawning sessions against rate-limited executables and to select
 * fallback executables when the primary is throttled.
 *
 * Key features:
 * - Track rate-limited executables with reset timestamps
 * - Auto-expire stale entries (past reset times)
 * - Walk fallback chains to find available executables
 * - Query soonest reset time for scheduling retries
 *
 * @module
 */
// ============================================================================
// Implementation
// ============================================================================
/**
 * In-memory implementation of the RateLimitTracker.
 *
 * Uses a Map keyed by executable name. Stale entries (resetsAt in the past)
 * are lazily cleaned up during read operations.
 */
class RateLimitTrackerImpl {
    limits = new Map();
    markLimited(executable, resetsAt) {
        const existing = this.limits.get(executable);
        if (existing && existing.resetsAt.getTime() >= resetsAt.getTime()) {
            // Existing entry has a later (or equal) reset time — don't downgrade
            return;
        }
        this.limits.set(executable, {
            resetsAt,
            recordedAt: new Date(),
        });
    }
    isLimited(executable) {
        const entry = this.limits.get(executable);
        if (!entry) {
            return false;
        }
        if (entry.resetsAt.getTime() <= Date.now()) {
            // Stale — auto-expire
            this.limits.delete(executable);
            return false;
        }
        return true;
    }
    getAvailableExecutable(fallbackChain) {
        for (const executable of fallbackChain) {
            if (!this.isLimited(executable)) {
                return executable;
            }
        }
        return undefined;
    }
    getSoonestResetTime() {
        this.expireStale();
        let soonest;
        for (const entry of this.limits.values()) {
            if (!soonest || entry.resetsAt.getTime() < soonest.getTime()) {
                soonest = entry.resetsAt;
            }
        }
        return soonest;
    }
    getAllLimits() {
        this.expireStale();
        const entries = [];
        for (const [executable, entry] of this.limits) {
            entries.push({
                executable,
                resetsAt: entry.resetsAt,
                recordedAt: entry.recordedAt,
            });
        }
        return entries;
    }
    isAllLimited(fallbackChain) {
        if (fallbackChain.length === 0) {
            return false;
        }
        return fallbackChain.every((executable) => this.isLimited(executable));
    }
    clear() {
        this.limits.clear();
    }
    // ----------------------------------------
    // Private Helpers
    // ----------------------------------------
    /**
     * Remove all entries whose resetsAt is in the past.
     */
    expireStale() {
        const now = Date.now();
        for (const [executable, entry] of this.limits) {
            if (entry.resetsAt.getTime() <= now) {
                this.limits.delete(executable);
            }
        }
    }
}
// ============================================================================
// Factory Function
// ============================================================================
/**
 * Creates a RateLimitTracker instance.
 *
 * No constructor arguments — this is purely in-memory with no DB or
 * service dependencies.
 */
export function createRateLimitTracker() {
    return new RateLimitTrackerImpl();
}
//# sourceMappingURL=rate-limit-tracker.js.map