// SPDX-FileCopyrightText: 2026 Stan Grams <sjg@haxx.space>
//
// SPDX-License-Identifier: GPL-2.0-or-later

import assert from "node:assert/strict";
import test from "node:test";
import vm from "node:vm";
import { createHost } from "./host-fixture.mjs";
import { bundleEntry } from "./bundle-entry.mjs";

test("scheduler registers a typed module service without lifecycle globals", async () => {
  // No role known yet: the entry registers its service and waits for the
  // application to drive initialization.
  const window = { ...createHost({ state: { authRole: null } }), trxUi: { confirm: async () => true } };
  const context = vm.createContext({
    window,
    document: {
      activeElement: null,
      addEventListener() {},
      getElementById: () => null,
      querySelector: () => null,
    },
    localStorage: { getItem: () => null, setItem() {} },
    setInterval: () => 1,
    clearInterval() {},
    setTimeout: () => 1,
    HTMLElement: class HTMLElement {},
    Element: class Element {},
    Date,
    Number,
    String,
    Array,
    Promise,
    WeakSet,
    console,
  });
  const source = await bundleEntry(new URL("../src/plugins/scheduler.ts", import.meta.url));
  new vm.Script(source).runInContext(context);

  const service = window.trx.modules.scheduler;
  assert.equal(typeof service.initialize, "function");
  assert.equal(typeof service.setRig, "function");
  assert.equal(typeof service.getConfig, "function");
  assert.equal(window.initScheduler, undefined);
  assert.equal(window.schedulerBridge, undefined);
});

// Lazy-load case: the settings tab is opened after boot, so the application has
// already passed initSettingsUI() and the entry must initialize itself from the
// host state.  This read used to come from a bare window property that the
// module graph stopped publishing, so the scheduler never started.
test("scheduler self-initializes for the active rig when a role is already known", async () => {
  class ElementFixture {
    constructor() {
      this.value = "";
      this.textContent = "";
      this.innerHTML = "";
      this.style = {};
      this.dataset = {};
      this.options = [];
      this.classList = { add() {}, remove() {}, toggle() {}, contains: () => false };
      this.children = [];
    }
    addEventListener() {}
    appendChild(child) { this.children.push(child); return child; }
    remove() {}
    focus() {}
    closest() { return null; }
    querySelector() { return null; }
    querySelectorAll() { return []; }
  }
  const elements = new Map();
  const fetched = [];
  const element = (id) => {
    if (!elements.has(id)) elements.set(id, new ElementFixture());
    return elements.get(id);
  };
  const window = {
    ...createHost({ state: { authRole: "control", lastActiveRigId: "sdr" } }),
    trxUi: { confirm: async () => true },
  };
  const context = vm.createContext({
    window,
    document: {
      activeElement: null,
      addEventListener() {},
      getElementById: element,
      querySelector: () => new ElementFixture(),
      querySelectorAll: () => [],
      createElement: () => new ElementFixture(),
    },
    localStorage: { getItem: () => null, setItem() {} },
    fetch: async (url) => { fetched.push(String(url)); return { ok: true, json: async () => ({}) }; },
    setInterval: () => 1,
    clearInterval() {},
    setTimeout: () => 1,
    HTMLElement: ElementFixture,
    Element: ElementFixture,
    Date,
    Number,
    String,
    Array,
    Promise,
    WeakSet,
    console,
  });
  const source = await bundleEntry(new URL("../src/plugins/scheduler.ts", import.meta.url));
  new vm.Script(source).runInContext(context);
  await new Promise((resolve) => setImmediate(resolve));

  assert.ok(fetched.some((url) => url.includes("scheduler") && url.includes("sdr")),
    `expected a scheduler load for the active rig, saw ${JSON.stringify(fetched)}`);
});
