/* WITNESS · menu-selector  (W-052 mosaic_v2-menu-selector)
 *
 * THE PROMISE: a restaurant runs two menus at once; the diner picks between them and only
 * that menu's sub-categories show; the order they place is stamped with the menu they used
 * and the waiter sees which menu it came from.
 *
 * I do the diner's half first, because it is the half a person owns: is there anything on
 * my screen that lets me choose a menu at all? Then I look at the owner's Menu page to see
 * how many menus are live at the same time, so the answer is measured against reality.
 * NOTHING is ordered and nothing is changed.
 */
import { test } from "@playwright/test";
import { journal, look, arriveAsDiner, openCourse, roleContext, deskContext, closeRole,
         signInOwner, account, OWNER, PATRON, DWELL } from "../lib-witness.mjs";
import fs from "node:fs";

const RID = "28ae37ab-706c-4e20-83d7-52f5d2dff747";   // Canary Mosaic — dev
const TABLE = 9952;

const chooserScan = page => page.evaluate(() => {
  const vis = e => e.offsetParent !== null;
  const ids = [...document.querySelectorAll("[data-testid]")].filter(vis)
    .map(e => e.getAttribute("data-testid"));
  return {
    menuish: [...new Set(ids.filter(t => /menu-(switch|select|tab|pick|chooser)|switcher|slide-host/i.test(t)))].sort(),
    slideHost: (document.querySelector('[data-testid="m2-menu-slide-host"]')?.innerText || "")
                 .replace(/\s+/g, " ").trim().slice(0, 300),
    tiles: document.querySelectorAll('[data-testid^="m2-tile-"]').length,
    subcat: (document.querySelector('[data-testid="m2-subcat-nav"]')?.innerText || "")
                 .replace(/\s+/g, " ").trim(),
  };
});

test("menu-selector", async ({ browser }) => {
  test.setTimeout(28 * 60_000);
  const jr = journal("menu-selector");
  jr.target({ patronApp: PATRON, ownerApp: OWNER, restaurantId: RID, fixture: "canary-mosaic",
              table: TABLE });
  jr.note("**Where:** Canary Mosaic — dev, table 9952 — the restaurant whose owner Menu page "
        + "carries the journey's own `M2MS MenuA` and `M2MS MenuB`.");
  jr.note("**No order is placed and nothing is changed.**");

  const pc = await roleContext(browser, jr, "patron");
  const oc = await deskContext(browser, jr, "owner");
  const diner = await pc.newPage(), owner = await oc.newPage();
  const state = {};
  let verdict = "INCOMPLETE", why = "";

  try {
    await jr.step("PATRON", "I sit down and look for a way to choose a menu", async id => {
      await arriveAsDiner(diner, RID, TABLE, "mosaic_v2");
      const t = await look(diner, jr, "patron", id, "arrival — is there a menu chooser?");
      state.arrival = await chooserScan(diner);
      jr.note(`> **Anything on screen that looks like a menu chooser:** `
            + `${state.arrival.menuish.join(" · ") || "**nothing**"}`);
      jr.note(`> **What the slide host contains:** \`${state.arrival.slideHost || "(empty)"}\``);
      return `controls: ${state.arrival.menuish.join(", ") || "none"} · `
           + `${state.arrival.tiles} tiles · subcat rail "${state.arrival.subcat}"`;
    });

    await jr.soft("PATRON", "I switch to a different menu and the sub-categories change",
      async id => {
        const host = diner.locator('[data-testid="m2-menu-slide-host"]');
        const before = state.arrival.subcat;
        // A slide host is swiped, so swipe it the way a thumb would before concluding.
        if (await host.count()) {
          const b = await host.boundingBox();
          if (b) {
            await diner.mouse.move(b.x + b.width * 0.85, b.y + b.height * 0.5);
            await diner.mouse.down();
            for (const f of [0.7, 0.55, 0.4, 0.25, 0.12]) {
              await diner.mouse.move(b.x + b.width * f, b.y + b.height * 0.5); await diner.waitForTimeout(80);
            }
            await diner.mouse.up();
            await diner.waitForTimeout(DWELL);
          }
        }
        const t = await look(diner, jr, "patron", id, "after I try to change menu");
        const after = await chooserScan(diner);
        state.afterSwipe = after;
        jr.note(`> **Sub-category rail before:** \`${before}\` · **after swiping the slide host:** `
              + `\`${after.subcat}\``);
        if (!state.arrival.menuish.length && after.subcat === before)
          throw new Error(
            "There is no menu chooser on my screen and swiping changed nothing. As a diner I "
          + "have no way to pick between this restaurant's menus.");
        return `rail "${before}" -> "${after.subcat}"; controls now: ${after.menuish.join(", ") || "none"}`;
      });

    await jr.step("OWNER", "How many menus is this restaurant actually running at once?",
      async id => {
        const a = account("canaryOwner");
        await signInOwner(owner, a.email, a.password, RID);
        await owner.goto(`${OWNER}/owner/menu/?restaurantId=${RID}`, { waitUntil: "domcontentloaded" });
        await owner.waitForTimeout(DWELL * 2);
        const t = await look(owner, jr, "owner", id, "the owner's menu list");
        const menus = await owner.evaluate(() =>
          [...document.querySelectorAll('[data-testid^="menu-tab-"]')]
            .filter(e => !/-sub$/.test(e.getAttribute("data-testid")))
            .map(e => (e.innerText || "").replace(/\s+/g, " ").trim()).filter(Boolean));
        state.menus = menus;
        const active = menus.filter(m => /ACTIVE/i.test(m) && !/INACTIVE/i.test(m));
        state.activeCount = active.length;
        jr.note(`> **Menus this owner has:** ${menus.length}, of which **${active.length} are ACTIVE**`
              + ` at the same time. Two of them are this journey's own: `
              + `${menus.filter(m => /M2MS/i.test(m)).join(" · ") || "(none named M2MS)"}`);
        return `${menus.length} menus, ${active.length} ACTIVE. M2MS: `
             + `${menus.filter(m => /M2MS/i.test(m)).join(" | ") || "none"}`;
      });

    verdict = "WALKED"; why = "Looked for the diner's menu chooser and counted the live menus.";
  } catch (e) {
    verdict = "STOPPED"; why = String(e.message||e).split("\n")[0].slice(0,300);
  } finally {
    fs.writeFileSync(`${jr.dir}/state.json`, JSON.stringify(state, null, 1));
    jr.finish(verdict, why);
    await closeRole(pc, jr, "patron"); await closeRole(oc, jr, "owner");
  }
});
