type Task<T> = () => Promise<T>;
type TaskWithPriority<T> = { task: Task<T>; priority: number; resolve: (value: T) => void; reject: (error: any) => void };

class AsyncQueue<T = any> {
  private queue: TaskWithPriority<T>[] = [];
  private running = 0;
  private concurrency: number;

  constructor(concurrency: number = 3) {
    this.concurrency = concurrency;
  }

  async add(task: Task<T>, priority: number = 0): Promise<T> {
    return new Promise<T>((resolve, reject) => {
      this.queue.push({ task, priority, resolve, reject });
      this.queue.sort((a, b) => b.priority - a.priority);
      this.process();
    });
  }

  private async process(): Promise<void> {
    if (this.running >= this.concurrency || this.queue.length === 0) {
      return;
    }

    this.running++;
    const { task, resolve, reject } = this.queue.shift()!;

    try {
      const result = await task();
      resolve(result);
    } catch (error) {
      reject(error);
    } finally {
      this.running--;
      this.process();
    }
  }

  get size(): number {
    return this.queue.length;
  }

  get active(): number {
    return this.running;
  }
}

export default AsyncQueue;