const COOLDOWN_MS = 50;
// A single inference lane prevents Whisper and Marian from competing for all
// renderer CPU at the same time. ASR is always selected before translation so
// stale translations can wait or be dropped without delaying fresh captions.
export class InferenceScheduler {
    asrQueue = [];
    translationQueue = [];
    active = false;
    drainTimer;
    run(priority, task) {
        return new Promise((resolve, reject) => {
            const job = {
                priority,
                task: task,
                resolve: resolve,
                reject,
            };
            (priority === "asr" ? this.asrQueue : this.translationQueue).push(job);
            void this.drain();
        });
    }
    pending(priority) {
        if (priority === "asr")
            return this.asrQueue.length;
        if (priority === "translation")
            return this.translationQueue.length;
        return this.asrQueue.length + this.translationQueue.length;
    }
    async drain() {
        if (this.active || this.drainTimer !== undefined)
            return;
        const job = this.asrQueue.shift() ?? this.translationQueue.shift();
        if (!job)
            return;
        this.active = true;
        try {
            job.resolve(await job.task());
        }
        catch (error) {
            job.reject(error);
        }
        finally {
            this.active = false;
            if (this.pending() > 0 && this.drainTimer === undefined) {
                this.drainTimer = setTimeout(() => { this.drainTimer = undefined; void this.drain(); }, COOLDOWN_MS);
            }
        }
    }
}
