/* WITNESS · micro-kitchen-windowless (W-023) — re-drive, QRATE-UAT-1
 *
 * What a person should be able to do, in my own words:
 *   Two micro kitchens. One has collection windows, one does not. At the one WITHOUT
 *   windows I should be able to order without being made to pick a collection time; at
 *   its sibling WITH windows the same act should make me pick one. The whole point of
 *   this journey is that the two kitchens feel DIFFERENT. If they feel identical, one of
 *   them is wrong.
 *
 * This walk is deliberately kept to what a customer with NO account can see, so its video
 * and trace carry no credential and can be shown to anyone. Whatever lives behind the
 * who-are-you gate is covered by the signup-gate walk, which is withheld.
 *
 * I compare the two kitchens by the set of controls actually on screen at the moment each
 * one stops me — not by searching the page text for the word "window", which would match
 * a dish description just as happily.
 */
import { test } from "@playwright/test";
import { journal, look, roleContext, closeRole, PATRON, DWELL } from "../lib-witness.mjs";
import fs from "node:fs";

const F = JSON.parse(fs.readFileSync("/workspace/uat/runs/wave0/fixtures.json", "utf8"));
const WINDOWED   = F["micro-kitchen"];
const WINDOWLESS = F["micro-kitchen-windowless"];

async function answerDietary(page, ms = 15000) {
  const gate = page.locator('[data-testid="m2-dietary-gate"]');
  try { await gate.first().waitFor({ state: "visible", timeout: ms }); } catch { return false; }
  const no = page.locator('[data-testid="m2-dietary-gate-no"]').first();
  await no.click({ timeout: 10000 }).catch(async () => { await no.evaluate(el => el.click()).catch(() => {}); });
  await gate.first().waitFor({ state: "hidden", timeout: 10000 }).catch(() => {});
  await page.waitForTimeout(1500);
  return true;
}

const tap = async (page, sel) => {
  const l = page.locator(sel).first();
  if (!(await l.count())) return false;
  await l.click({ timeout: 8000 }).catch(async () => { await l.evaluate(el => el.click()); });
  return true;
};

const tids = page => page.evaluate(() =>
  [...new Set([...document.querySelectorAll("[data-testid]")].map(e => e.getAttribute("data-testid")))].sort());

const fulfilmentControls = page => page.evaluate(() =>
  [...document.querySelectorAll("[data-testid]")].map(e => e.getAttribute("data-testid"))
    .filter(t => /pickup|pick-up|delivery|deliver|window|slot|collect|fulfil|schedule|when|time|asap|address/i.test(t)).sort());

/** Browse, cart one thing, read both tabs of the basket, then press order. Report what stopped me. */
async function orderAt(page, jr, role, rid, table, id) {
  await page.goto(`${PATRON}/menu?id=${rid}&table=${table}`, { waitUntil: "domcontentloaded" });
  await page.waitForTimeout(DWELL);
  await answerDietary(page);
  await look(page, jr, role, `${id}a`, "menu");
  const dishes = await page.locator('[data-testid^="m2-tile-"]').count();
  if (!dishes) throw new Error("Nothing on this menu, so I cannot order from it.");

  await page.locator('[data-testid^="m2-tile-"]').first().evaluate(el => el.click());
  await page.waitForTimeout(DWELL);
  await page.locator('[data-testid="composition-add"]').first().click({ timeout: 20000 });
  await page.waitForTimeout(DWELL);

  await tap(page, '[data-testid="m2-dock-trigger"]');
  await page.waitForTimeout(2000);
  await tap(page, '[data-testid="m2-dock-cart"]');
  await page.waitForTimeout(DWELL);
  await answerDietary(page, 3000);

  // read BOTH tabs before judging - a control I never opened is a control I cannot report on
  const tabs = {};
  for (const t of ["m2-cart-tab-way", "m2-cart-tab-table"]) {
    if (!(await page.locator(`[data-testid="${t}"]`).count())) { tabs[t] = "absent"; continue; }
    const label = (await page.locator(`[data-testid="${t}"]`).first().innerText().catch(() => "")).replace(/\s+/g, " ").trim();
    await tap(page, `[data-testid="${t}"]`);
    await page.waitForTimeout(2500);
    await look(page, jr, role, `${id}b-${t}`, `basket tab ${label || t}`);
    tabs[t] = { label, offers: await fulfilmentControls(page) };
  }
  await tap(page, '[data-testid="m2-cart-tab-way"]');
  await page.waitForTimeout(2000);
  const beforeOrder = await tids(page);
  const preOrderFulfilment = await fulfilmentControls(page);

  const btn = page.locator('[data-testid="order-now-btn"]').first();
  if (!(await btn.count())) throw new Error("No Place order button in my basket at all.");
  const label = (await btn.innerText()).replace(/\s+/g, " ").trim();
  await btn.click({ timeout: 20000 });
  await page.waitForTimeout(DWELL);
  await look(page, jr, role, `${id}c`, "what stops me");

  const gated = await page.locator('[data-testid="signup-gate"]').count();
  const gateText = gated
    ? (await page.locator('[data-testid="signup-gate"]').first().innerText()).replace(/\s+/g, " ").trim() : "";
  return {
    dishes, orderButton: label, tabs, preOrderFulfilment,
    stoppedByGate: !!gated, gateText,
    stopFulfilment: await fulfilmentControls(page),
    stopTestids: await tids(page),
    appearedOnPressingOrder: (await tids(page)).filter(t => !beforeOrder.includes(t)),
  };
}

test("micro-kitchen-windowless", async ({ browser }) => {
  const jr = journal("micro-kitchen-windowless");
  jr.target({ app: "patron", url: PATRON,
              windowlessRestaurantId: WINDOWLESS, windowedRestaurantId: WINDOWED,
              tables: { windowless: 10471, windowed: 10472 } });
  jr.note("_A differential. The same act — cart one thing, press Place order — done at the "
        + "kitchen with **no** collection windows and at its sibling **with** them. They are "
        + "supposed to behave differently. I compare the controls actually on screen at each "
        + "stop, not the words on the page._");
  jr.note("> **No account is used in this walk**, so nothing here carries a credential.");

  const cA = await roleContext(browser, jr, "patron-windowless");
  const cB = await roleContext(browser, jr, "patron-windowed");
  const a = await cA.newPage(), b = await cB.newPage();
  let L = null, W = null;

  try {
    await jr.step("PATRON", "At the kitchen with NO collection windows I order, and am not made to pick a time",
      async id => {
        L = await orderAt(a, jr, "patron-windowless", WINDOWLESS, 10471, id);
        jr.note(`> **Windowless kitchen** — basket tabs: \`${JSON.stringify(L.tabs)}\`; `
              + `anything about pickup/delivery/a time before ordering: **${L.preOrderFulfilment.join(", ") || "none"}**.`);
        return L.stoppedByGate
          ? `It did not ask me for a time — it asked me who I am. The panel says: "${L.gateText.slice(0, 150)}". `
            + `Nothing on that screen offers pickup, delivery or a time (${L.stopFulfilment.join(", ") || "no such control"}).`
          : `Nothing stopped me. Controls that appeared when I pressed "${L.orderButton}": ${L.appearedOnPressingOrder.join(", ") || "none at all"}.`;
      });

    await jr.step("PATRON", "At its sibling that DOES have windows, the same act makes me pick a time",
      async id => {
        W = await orderAt(b, jr, "patron-windowed", WINDOWED, 10472, id);
        jr.note(`> **Windowed kitchen** — basket tabs: \`${JSON.stringify(W.tabs)}\`; `
              + `anything about pickup/delivery/a time before ordering: **${W.preOrderFulfilment.join(", ") || "none"}**.`);
        return W.stoppedByGate
          ? `It did not ask me for a time either — it asked me who I am. The panel says: "${W.gateText.slice(0, 150)}". `
            + `Nothing on that screen offers pickup, delivery or a time (${W.stopFulfilment.join(", ") || "no such control"}).`
          : `Nothing stopped me. Controls that appeared when I pressed "${W.orderButton}": ${W.appearedOnPressingOrder.join(", ") || "none at all"}.`;
      });

    await jr.step("PATRON", "The two kitchens behaved differently — which is the entire point", async () => {
      const onlyL = L.stopTestids.filter(t => !W.stopTestids.includes(t));
      const onlyW = W.stopTestids.filter(t => !L.stopTestids.includes(t));
      const meaningful = [...onlyL, ...onlyW].filter(t => !/^(m2-tile|m2-text|m2-add|m2-dec|m2-qty|cart-item|cart-group|cart-line-price|cart-serving-anchor|cart-qty|held-cart-item)/.test(t));
      jr.note(`> **Only at the windowless kitchen:** ${onlyL.join(", ") || "nothing"}`);
      jr.note(`> **Only at the windowed kitchen:** ${onlyW.join(", ") || "nothing"}`);
      jr.note(`> **Ignoring per-dish ids, the difference between the two screens is:** `
            + `${meaningful.join(", ") || "**nothing at all — the two kitchens stop me on an identical screen**"}`);
      if (!meaningful.length)
        throw new Error("Both kitchens stopped me on the same screen with the same controls. "
                      + "Neither offered a collection time, so I cannot tell them apart at all — "
                      + "which is the one thing this journey exists to show.");
      return `They differ: ${meaningful.join(", ")}`;
    });

    jr.finish("WALKED", "Compared both kitchens side by side as a customer with no account.");
  } catch (e) {
    jr.finish("STOPPED", `I could not get further: ${String(e.message || e).split("\n")[0]}`);
    throw e;
  } finally {
    await closeRole(cA, jr, "patron-windowless");
    await closeRole(cB, jr, "patron-windowed");
  }
});
