/**
 * Async concurrency semaphore — limits the number of concurrent async operations.
 */
export class ConcurrencySemaphore {
  private running = 0;
  private waitQueue: Array<() => void> = [];

  constructor(private readonly maxConcurrency: number) {}

  async acquire(): Promise<void> {
    if (this.running < this.maxConcurrency) {
      this.running++;
      return;
    }
    return new Promise<void>((resolve) => {
      this.waitQueue.push(() => {
        this.running++;
        resolve();
      });
    });
  }

  release(): void {
    this.running--;
    const next = this.waitQueue.shift();
    if (next) next();
  }
}
