import { IdleAwareCadence } from './IdleAwareCadence.js';
export class TokenLedgerPoller {
    ledger;
    intervalMs;
    idleIntervalMs;
    isIdle;
    timer = null;
    cadence = null;
    running = false;
    onError;
    afterTick;
    codexProjectDir;
    codexMaxFileAgeMs;
    constructor(opts) {
        this.ledger = opts.ledger;
        this.intervalMs = opts.intervalMs ?? 60_000;
        this.isIdle = opts.isIdle ?? null;
        this.idleIntervalMs = opts.idleIntervalMs && opts.idleIntervalMs > 0 ? opts.idleIntervalMs : 5 * 60_000;
        this.codexProjectDir = opts.codexProjectDir ?? null;
        this.codexMaxFileAgeMs = opts.codexMaxFileAgeMs && opts.codexMaxFileAgeMs > 0
            ? opts.codexMaxFileAgeMs
            : 30 * 24 * 60 * 60 * 1000;
        this.onError = opts.onError ?? ((err) => {
            console.warn('[token-ledger] scan error:', err);
        });
        this.afterTick = opts.afterTick ?? null;
    }
    start() {
        if (this.timer || this.cadence)
            return;
        // Immediate first tick (non-blocking) so the dashboard has data fast.
        queueMicrotask(() => this.tick());
        if (this.isIdle) {
            // Idle-aware: full cadence while active, back off while idle.
            this.cadence = new IdleAwareCadence({
                activeMs: this.intervalMs,
                idleMs: this.idleIntervalMs,
                isIdle: this.isIdle,
                tick: () => this.tick(),
            });
            this.cadence.start();
        }
        else {
            this.timer = setInterval(() => this.tick(), this.intervalMs);
            if (typeof this.timer.unref === 'function')
                this.timer.unref();
        }
    }
    stop() {
        if (this.timer) {
            clearInterval(this.timer);
            this.timer = null;
        }
        if (this.cadence) {
            this.cadence.stop();
            this.cadence = null;
        }
    }
    tick() {
        if (this.running)
            return;
        this.running = true;
        // Fire-and-forget the async scan; reentry guard above prevents stacking.
        // We do NOT await — setInterval already drives cadence, and awaiting
        // here would block other interval callbacks in this microtask queue.
        // The Codex scan (when configured) runs after the Claude scan; a failure
        // in either is reported but never stops the other or stacks ticks.
        this.ledger
            .scanAllAsync()
            .catch((err) => this.onError(err))
            .then(() => {
            if (!this.codexProjectDir)
                return undefined;
            return this.ledger
                .scanCodexRolloutsAsync({ projectDir: this.codexProjectDir, maxFileAgeMs: this.codexMaxFileAgeMs })
                .then(() => undefined)
                .catch((err) => this.onError(err));
        })
            .finally(() => {
            this.running = false;
            if (this.afterTick) {
                Promise.resolve()
                    .then(() => this.afterTick())
                    .catch((err) => this.onError(err));
            }
        });
    }
}
//# sourceMappingURL=TokenLedgerPoller.js.map