import type { Clock } from "../../src/scheduler";

interface Pending {
  fn: () => void;
  due: number;
  handle: number;
}

/** Deterministic clock for scheduler tests: no real sleeps, time and firing are advanced explicitly. */
export class ManualClock implements Clock {
  private currentTime = 0;
  private nextHandle = 1;
  private pending: Pending[] = [];

  now(): number {
    return this.currentTime;
  }

  setTimeout(fn: () => void, ms: number): unknown {
    const handle = this.nextHandle++;
    this.pending.push({ fn, due: this.currentTime + ms, handle });
    return handle;
  }

  clearTimeout(handle: unknown): void {
    this.pending = this.pending.filter((p) => p.handle !== handle);
  }

  /** Advances time by ms, synchronously firing any timers now due (in due-time order). */
  async advance(ms: number): Promise<void> {
    const target = this.currentTime + ms;
    while (this.pending.some((p) => p.due <= target)) {
      this.pending.sort((a, b) => a.due - b.due);
      const next = this.pending.shift();
      if (!next) break;
      this.currentTime = next.due;
      next.fn();
      // let any queued microtasks (async poll handlers) settle before checking for more due timers
      await Promise.resolve();
      await Promise.resolve();
    }
    this.currentTime = target;
  }
}
