'use strict';

// Minimal FIFO hand-off semaphore for bounding concurrent async operations.
//
// Used to cap how many heavy db-owner-worker ops are in flight at once (e.g. the
// restore-time scrollback loads) so a single serial worker queue can't be flooded
// — which would starve smaller ops into their timeout/main-thread-fallback path.
//
// Hand-off semantics: on release, a queued waiter is resumed DIRECTLY (the freed
// slot is passed to it) so `active` never transiently exceeds the limit and order
// is strict FIFO. acquire() resolves when a slot is held; the caller must call
// release() exactly once (use try/finally).
function createSemaphore(limit) {
  const max = Math.max(1, Math.floor(Number(limit) || 1));
  let active = 0;
  const waiters = [];

  function acquire() {
    if (active < max) {
      active++;
      return Promise.resolve();
    }
    return new Promise((resolve) => waiters.push(resolve));
  }

  function release() {
    const next = waiters.shift();
    if (next) {
      next(); // hand the slot directly to the next waiter — active stays at the cap
    } else if (active > 0) {
      active--;
    }
  }

  return {
    acquire,
    release,
    get limit() { return max; },
    get active() { return active; },
    get pending() { return waiters.length; },
  };
}

module.exports = { createSemaphore };
