import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath, pathToFileURL } from "node:url";
import { dirname, join } from "node:path";

const here = dirname(fileURLToPath(import.meta.url));

// Load the shared map (classic-script side-effect sets the global).
// pathToFileURL: Windows ESM import() requires a file:// URL, not a c:\ path.
await import(pathToFileURL(join(here, "dashboard-routes.js")).href);
const shared = globalThis.NEXUS_DASHBOARD_ROUTES || {};

// Extract the action keys declared inside background.js's DASHBOARD_ROUTES object.
function backgroundRouteKeys() {
  const src = readFileSync(join(here, "background.js"), "utf8");
  const start = src.indexOf("const DASHBOARD_ROUTES = {");
  assert.ok(start >= 0, "DASHBOARD_ROUTES literal found in background.js");
  const end = src.indexOf("function isDashboardAction", start); // immediately follows the object
  assert.ok(end > start, "end of DASHBOARD_ROUTES located");
  const block = src.slice(start, end);
  const keys = new Set();
  // Match both quoted ("grd-list": { method) and unquoted (today: { method)
  // keys. Prettier's quoteProps:"as-needed" strips quotes from plain-identifier
  // keys, so a quote-only regex would miss `today`/`capabilities` and report
  // false drift the moment background.js is reformatted.
  const re = /["']?([a-zA-Z0-9_$-]+)["']?:\s*\{\s*method/g;
  let m;
  while ((m = re.exec(block))) keys.add(m[1]);
  return keys;
}

test("dashboard-routes.js is a complete copy of background.js DASHBOARD_ROUTES (no drift)", () => {
  const bg = backgroundRouteKeys();
  assert.ok(bg.size > 300, `expected the full background route set, got ${bg.size}`);
  const sharedKeys = new Set(Object.keys(shared));
  // Every server-backed action the extension knows MUST be in the shared map,
  // else the /web build silently can't reach that surface. If this fails after
  // adding a route to background.js, re-copy DASHBOARD_ROUTES into dashboard-routes.js.
  const missing = [...bg].filter((k) => !sharedKeys.has(k));
  assert.deepEqual(
    missing,
    [],
    `routes in background.js missing from dashboard-routes.js: ${missing.join(", ")}`,
  );
  // …and the reverse: a route added to dashboard-routes.js (the /web copy) but
  // NOT to background.js is dead in the packaged extension (the SW dispatches
  // off background.js's own literal). Assert set EQUALITY so drift fails either way.
  const extra = [...sharedKeys].filter((k) => !bg.has(k));
  assert.deepEqual(
    extra,
    [],
    `routes in dashboard-routes.js missing from background.js (dead in the packaged extension): ${extra.join(", ")}`,
  );
});

test("shared route entries have the expected { method, path() } shape", () => {
  const sample = ["today", "signals-list", "crm-deals", "notifications-list", "vc-queue"];
  for (const k of sample) {
    const r = shared[k];
    assert.ok(r, `shared map has ${k}`);
    assert.equal(typeof r.path, "function", `${k}.path is a function`);
    assert.equal(
      typeof r.path({ id: "1", queryString: "?x=1" }),
      "string",
      `${k}.path(m) returns a string`,
    );
  }
});
