import { afterEach, describe, expect, it, vi } from "vitest";
import { createRateLimitedPublisher } from "./rateLimitedPublisher";

afterEach(() => vi.useRealTimers());

describe("createRateLimitedPublisher", () => {
  it("publishes immediately, then coalesces a burst into one trailing update", () => {
    vi.useFakeTimers();
    let now = 0;
    const publish = vi.fn();
    const limiter = createRateLimitedPublisher(publish, 100, () => now);

    limiter.request();
    limiter.request();
    limiter.request();
    expect(publish).toHaveBeenCalledTimes(1);

    now = 99;
    vi.advanceTimersByTime(99);
    expect(publish).toHaveBeenCalledTimes(1);

    now = 100;
    vi.advanceTimersByTime(1);
    expect(publish).toHaveBeenCalledTimes(2);
  });

  it("cancels pending work when the owning display unmounts", () => {
    vi.useFakeTimers();
    let now = 0;
    const publish = vi.fn();
    const limiter = createRateLimitedPublisher(publish, 100, () => now);

    limiter.request();
    now = 1;
    limiter.request();
    limiter.dispose();
    now = 101;
    vi.advanceTimersByTime(100);

    expect(publish).toHaveBeenCalledTimes(1);
  });

  it("can cancel a pending publish and resume for a reconnected display", () => {
    vi.useFakeTimers();
    let now = 0;
    const publish = vi.fn();
    const limiter = createRateLimitedPublisher(publish, 100, () => now);

    limiter.request();
    now = 1;
    limiter.request();
    limiter.cancel();
    now = 101;
    vi.advanceTimersByTime(100);
    expect(publish).toHaveBeenCalledTimes(1);

    limiter.request();
    expect(publish).toHaveBeenCalledTimes(2);
  });
});
