/* WITNESS · DISH lane — the mains. Does ANY dish on these fixtures offer a diner a choice?
 *
 * ⚠️ GRADES NOTHING. Six of my eight journeys promise something INSIDE the dish sheet: a
 * spice level, a priced option, a sides section, a build-your-own picker, a lunch/dinner
 * variant. Starters hold one plain salad on every fixture, so before I can honestly say
 * "there is nothing here to test" I have to open every main course on every one of them.
 *
 * My first attempt at this was WRONG and I am not repeating it: the sheet never closed
 * between dishes, so every reading after the first was the first dish again. Here I close
 * it and PROVE it closed (the tile grid is back) before opening the next one.
 *
 * Read-only: nothing added to a cart, no order placed, no owner setting changed.
 */
import { test } from "@playwright/test";
import fs from "node:fs";
import { journal, look, arriveAsDiner, roleContext, closeRole, DWELL, PATRON }
  from "../lib-witness.mjs";

const PLACES = [
  ["e881f420-175c-52e7-b828-1736de3d87f8", "Canary Spice Mod"],
  ["e8e9a568-066e-5bee-8d48-0b54e90eb5f7", "Canary Includes"],
  ["c2cb26f6-73ca-5306-ac22-07f4131b2753", "Canary Groupings"],
  ["1268ba64-18a8-504f-b1c2-b1f5528dd97a", "Canary Grouping Dietary"],
  ["f469b191-ec79-585d-916a-e6c497617eb8", "Canary Mosaic V2 Dining"],
];
const TABLE = 9944;
/** The sheet a plain dish shows: hero, price, a note box, a stepper, an Add button.
 *  Anything BEYOND this set is a choice the dish is offering. */
const PLAIN = new Set(["m2-compact-header", "m2-compact-hero-photo", "m2-comp-scroll",
  "m2-dish-hero", "m2-dish-hero-photo", "m2-dish-price", "m2-composition-body",
  "m2-cmp-slot-before-note", "m2-cmp-note", "m2-cmp-kb-spacer", "m2-comp-stepper",
  "m2-comp-dec", "m2-comp-qty", "m2-comp-inc", "composition-add"]);

test("dish-entrees-survey", async ({ browser }) => {
  const jr = journal("dish-entrees-survey");
  jr.target({ app: "patron (mosaic_v2)", baseUrl: PATRON, table: TABLE });
  jr.note("⚠️ **This grades nothing.** It answers one question before I grade six journeys: "
        + "is there any dish, in any main course, on any of these fixtures, that offers a "
        + "diner a spice level, a side, a modifier, a variant or a build-your-own choice? "
        + "Every read is scoped to the open sheet — the menu paints through it.");
  jr.note("_A plain dish's sheet is a known set of fifteen controls. I list, for each dish, "
        + "anything BEYOND that set — that is what a choice would look like._");

  const out = {};
  let verdict = "INCOMPLETE", why = "";

  try {
    for (const [rid, name] of PLACES) {
      const role = `diner-${name.replace(/\W+/g, "-")}`;
      await jr.soft("PATRON", `I open every main course at ${name}`, async id => {
        const c = await roleContext(browser, jr, role);
        const p = await c.newPage();
        const rec = { rid, dishes: [] };
        try {
          await arriveAsDiner(p, rid, TABLE, "mosaic_v2");
          const mains = p.locator('[data-testid="m2-section-Entrees"]').first();
          if (!(await mains.count())) throw new Error("this menu has no Mains section at all");
          await mains.evaluate(el => el.click());
          await p.waitForTimeout(DWELL);
          const n = await p.locator('[data-testid^="m2-tile-"]').count();
          for (let i = 0; i < n; i++) {
            // Always start from a known state: the tile grid, this course.
            if (!(await p.locator('[data-testid^="m2-tile-"]').count())) {
              await arriveAsDiner(p, rid, TABLE, "mosaic_v2");
              await p.locator('[data-testid="m2-section-Entrees"]').first().evaluate(el => el.click());
              await p.waitForTimeout(DWELL);
            }
            const tile = p.locator('[data-testid^="m2-tile-"]').nth(i);
            const tid = await tile.getAttribute("data-testid");
            await tile.click({ timeout: 20000 }).catch(async () => { await tile.evaluate(el => el.click()); });
            await p.waitForTimeout(3500);
            const s = p.locator('[data-testid="m2-composition"]');
            if (!(await s.count())) { rec.dishes.push({ tid, opened: false }); continue; }
            const text = (await s.innerText()).replace(/\s+/g, " ").trim();
            const ids = [...new Set(await s.evaluate(el =>
              [...el.querySelectorAll("[data-testid]")].map(e => e.getAttribute("data-testid"))))];
            const extra = ids.filter(x => !PLAIN.has(x));
            const title = (text.split(" $")[0] || text).slice(0, 60);
            rec.dishes.push({ tid, opened: true, title, text: text.slice(0, 700), extra });
            await look(p, jr, role, `${id}-${i}`, `main ${i + 1}`);
            // Close it, and PROVE it closed before moving on.
            for (let k = 0; k < 4 && (await p.locator('[data-testid="m2-composition"]').count()); k++) {
              await p.keyboard.press("Escape").catch(() => {});
              await p.waitForTimeout(1800);
            }
            rec.dishes[rec.dishes.length - 1].closed =
              !(await p.locator('[data-testid="m2-composition"]').count());
          }
          out[name] = rec;
          const withChoices = rec.dishes.filter(d => d.opened && d.extra && d.extra.length);
          return `${n} main(s): ${rec.dishes.map(d => d.title || d.tid).join(" | ").slice(0, 300)}. `
               + (withChoices.length
                   ? `OFFERS A CHOICE: ${withChoices.map(d => `${d.title} -> ${d.extra.join(",")}`).join(" ; ")}`
                   : "Not one of them offers a choice — every sheet is hero, price, a note box, "
                     + "a quantity stepper and Add to order, and nothing else.");
        } finally { await closeRole(c, jr, role); }
      });
    }
    verdict = "RECON"; why = "opened every main on five fixtures; graded nothing";
  } catch (e) {
    verdict = "STOPPED"; why = String(e.message || e).split("\n")[0].slice(0, 300);
  } finally {
    fs.writeFileSync(`${jr.dir}/mains.json`, JSON.stringify(out, null, 1));
    jr.note("_Full record: `mains.json` beside this file._");
    jr.finish(verdict, why);
  }
});
