import assert from "node:assert/strict";
import test from "node:test";

import { createReconnectingEventSource } from "./event-stream.js";

test("event streams reconnect with bounded backoff and reset after opening", () => {
  const sources = [];
  const timers = [];
  let verificationCount = 0;
  const connection = createReconnectingEventSource({
    url: "/api/sessions/example/events",
    eventSourceFactory(url, options) {
      const source = { url, options, closeCount: 0, close() { this.closeCount += 1; } };
      sources.push(source);
      return source;
    },
    onSource() {},
    onError() { verificationCount += 1; },
    schedule(callback, delay) {
      const timer = { callback, delay, cancelled: false };
      timers.push(timer);
      return timer;
    },
    cancel(timer) { timer.cancelled = true; }
  });

  assert.equal(sources.length, 1);
  assert.deepEqual(sources[0].options, { withCredentials: true });
  sources[0].onerror();
  assert.equal(sources[0].closeCount, 1);
  assert.equal(verificationCount, 1);
  assert.equal(timers[0].delay, 1000);

  timers[0].callback();
  sources[1].onerror();
  assert.equal(timers[1].delay, 2000);

  timers[1].callback();
  sources[2].onopen();
  sources[2].onerror();
  assert.equal(timers[2].delay, 1000);

  connection.stop();
  assert.equal(timers[2].cancelled, true);
  assert.equal(sources[2].closeCount, 1);
  timers[2].callback();
  assert.equal(sources.length, 3);
});

test("stale event source errors cannot create duplicate reconnects", () => {
  const sources = [];
  const timers = [];
  const connection = createReconnectingEventSource({
    url: "/events",
    eventSourceFactory() {
      const source = { close() {} };
      sources.push(source);
      return source;
    },
    onSource() {},
    schedule(callback, delay) { const timer = { callback, delay }; timers.push(timer); return timer; },
    cancel() {}
  });

  const first = sources[0];
  first.onerror();
  first.onerror();
  assert.equal(timers.length, 1);
  connection.stop();
});
