import assert from "node:assert/strict";
import test from "node:test";
import { createPageLifecycleDispatcher } from "../src/sdk/lifecycle.ts";

test("maps page visibility transitions to show, hide and unload events", () => {
  const dispatcher = createPageLifecycleDispatcher();
  const events = [];
  dispatcher.lifecycle.onShow((event) => events.push(event));
  dispatcher.lifecycle.onHide((event) => events.push(event));
  dispatcher.lifecycle.onUnload((event) => events.push(event));

  assert.equal(dispatcher.lifecycle.state(), "initializing");
  dispatcher.dispatch("show", "host");
  dispatcher.dispatch("hide", "host");
  dispatcher.dispatch("show", "host");
  dispatcher.dispatch("unload", "host");

  assert.equal(dispatcher.lifecycle.state(), "unloaded");
  assert.deepEqual(
    events.map(({ type, previous, current, source }) => ({
      type,
      previous,
      current,
      source,
    })),
    [
      { type: "show", previous: "initializing", current: "visible", source: "host" },
      { type: "hide", previous: "visible", current: "hidden", source: "host" },
      { type: "show", previous: "hidden", current: "visible", source: "host" },
      { type: "unload", previous: "visible", current: "unloaded", source: "host" },
    ],
  );
});

test("deduplicates lifecycle events and ignores transitions after unload", () => {
  const dispatcher = createPageLifecycleDispatcher();
  const events = [];
  dispatcher.lifecycle.on("show", (event) => events.push(event.type));
  dispatcher.lifecycle.on("unload", (event) => events.push(event.type));

  assert.equal(dispatcher.dispatch("show", "host")?.type, "show");
  assert.equal(dispatcher.dispatch("show", "host"), null);
  assert.equal(dispatcher.dispatch("unload", "host")?.type, "unload");
  assert.equal(dispatcher.dispatch("unload", "document"), null);
  assert.equal(dispatcher.dispatch("show", "host"), null);
  assert.deepEqual(events, ["show", "unload"]);
});

test("unsubscribe removes a page lifecycle listener", () => {
  const dispatcher = createPageLifecycleDispatcher();
  let calls = 0;
  const unsubscribe = dispatcher.lifecycle.onHide(() => {
    calls += 1;
  });

  unsubscribe();
  unsubscribe();
  dispatcher.dispatch("hide", "host");
  assert.equal(calls, 0);
});

test("show and hide helpers replay current state for lazy pages", () => {
  const dispatcher = createPageLifecycleDispatcher();
  dispatcher.dispatch("show", "host");

  const replayed = [];
  dispatcher.lifecycle.onShow((event) => replayed.push(event.type));
  dispatcher.lifecycle.onHide((event) => replayed.push(event.type));
  dispatcher.lifecycle.on("show", (event) => replayed.push(`future:${event.type}`));
  assert.deepEqual(replayed, ["show"]);

  dispatcher.dispatch("hide", "host");
  dispatcher.lifecycle.onHide((event) => replayed.push(`late:${event.type}`));
  assert.deepEqual(replayed, ["show", "hide", "late:hide"]);
});
