import { describe, it, expect } from "vitest";
import { letramentoEventBus, LETRAMENTO_EVENTS } from "../letramentoEvents";

function listenOnce(bus, eventName) {
  return new Promise((resolve) => {
    bus.addEventListener(eventName, (e) => resolve(e), { once: true });
  });
}

describe("LETRAMENTO_EVENTS", () => {
  it("has the expected constant values", () => {
    expect(LETRAMENTO_EVENTS).toEqual({
      STARTED: "started",
      RUNNING: "running",
      SUCCESS: "success",
      FAILURE: "failure",
      COMPLETED: "completed",
    });
  });
});

describe("letramentoEventBus", () => {
  it("is an EventTarget", () => {
    expect(letramentoEventBus).toBeInstanceOf(EventTarget);
  });

  describe("dispatch", () => {
    it("fires a CustomEvent with the given name and detail", async () => {
      const p = listenOnce(letramentoEventBus, "started");
      letramentoEventBus.dispatch("started", { score: 10 });
      const e = await p;
      expect(e.type).toBe("started");
      expect(e.detail).toEqual({ score: 10 });
    });

    it("uses empty object as default detail", async () => {
      const p = listenOnce(letramentoEventBus, "running");
      letramentoEventBus.dispatch("running");
      const e = await p;
      expect(e.detail).toEqual({});
    });
  });

  describe("named helpers", () => {
    const cases = [
      ["started",   () => letramentoEventBus.started({ x: 1 }),   { x: 1 }],
      ["running",   () => letramentoEventBus.running({ y: 2 }),   { y: 2 }],
      ["success",   () => letramentoEventBus.success({ ok: true }),{ ok: true }],
      ["failure",   () => letramentoEventBus.failure({ err: "e" }),{ err: "e" }],
      ["completed", () => letramentoEventBus.completed({ n: 3 }), { n: 3 }],
    ];

    for (const [eventName, trigger, expectedDetail] of cases) {
      it(`${eventName}() dispatches "${eventName}" with detail`, async () => {
        const p = listenOnce(letramentoEventBus, eventName);
        trigger();
        const e = await p;
        expect(e.type).toBe(eventName);
        expect(e.detail).toEqual(expectedDetail);
      });
    }
  });
});
