/* WITNESS · owner-cocktail-bartender  (owner half of W-002 bar-tender, STR-1191)
 *
 * WHY THIS WALK EXISTS
 * --------------------
 * W-002 `bar-tender` is green on the board while soft-skipping 2 of its 6 steps, because no
 * dev fixture carries cocktails (STR-1191). That is a coverage question. This walk asks the
 * OTHER half of it: if an owner goes looking for the bartender screen, what do they get?
 *
 * THE ORACLE IS THE PAGE'S OWN CONTENT, NOT THE ABSENCE OF AN ERROR.
 * A crashed page and an empty page look the same to a naive "no error text" check. So I
 * assert positively, in this order:
 *   1. the route answers and the app shell paints (otherwise it is a routing problem, not a crash)
 *   2. what the main region actually contains, verbatim
 *   3. whether ANY control a bartender could use is present
 * If the page turns out to render a working queue, the walk says so and passes.
 *
 * NO MUTATION. Nothing is created, saved or toggled.
 */
import { test } from "@playwright/test";
import { journal, look, signInOwner, account, closeRole, deskContext, OWNER, DWELL }
  from "../lib-witness.mjs";
import fs from "node:fs";

const FIX = JSON.parse(fs.readFileSync("/workspace/uat/runs/wave0/fixtures.json", "utf8"));
const RID = FIX["canary-mosaic"];

test("owner-cocktail-bartender", async ({ browser }) => {
  const jr = journal("owner-cocktail-bartender");
  jr.target({ app: "owner", url: OWNER, restaurantId: RID, fixture: "canary-mosaic",
              route: "/owner/cocktail-bartender/" });
  jr.note("_The bar-tender journey is green on the canary board. This walk asks what an owner "
        + "sees when they open the bartender screen itself._");
  jr.note("**No mutation:** nothing created, saved or toggled.");

  const ctx  = await deskContext(browser, jr, "owner");
  const page = await ctx.newPage();

  /* Console errors are context, not the finding - a page can log and still work. */
  const consoleErrors = [];
  page.on("pageerror", e => consoleErrors.push(String(e.message || e).split("\n")[0].slice(0, 160)));

  let verdict = "INCOMPLETE", why = "";
  try {
    await jr.step("OWNER", "I sign in as the owner of this restaurant", async id => {
      const a = account("canaryOwner");
      await signInOwner(page, a.email, a.password, RID);
      const t = await look(page, jr, "owner", id, "dashboard");
      if (/sign in|incorrect/i.test(t.slice(0, 300)))
        throw new Error(`I did not get in. Screen: ${t.slice(0, 200)}`);
      return `I am in. ${t.slice(0, 160)}`;
    });

    await jr.step("OWNER", "I open the bartender screen", async id => {
      const res = await page.goto(`${OWNER}/owner/cocktail-bartender/?restaurantId=${RID}`,
                                  { waitUntil: "domcontentloaded" });
      await page.waitForTimeout(DWELL * 2);
      const status = res ? res.status() : null;
      await look(page, jr, "owner", id, "bartender screen");
      const nav = await page.locator('[data-testid^="nav-"]').count();
      if (status !== 200)
        throw new Error(`The route itself did not answer: HTTP ${status}. That is a routing `
                      + `problem, not a page problem.`);
      if (!nav)
        throw new Error(`The app shell did not paint at all (no nav), so I cannot tell a crash `
                      + `from a redirect.`);
      return `HTTP ${status} and the app shell painted — ${nav} nav item(s) down the side. `
           + `So the app believes this is a real page.`;
    });

    await jr.step("OWNER", "I read what is actually on the page", async id => {
      const t = await look(page, jr, "owner", id, "what the page says");
      /* Strip the persistent shell so I am reading the PAGE, not the sidebar. */
      const main = await page.evaluate(() => {
        const el = document.querySelector("main") || document.body;
        return el.innerText.replace(/\s+/g, " ").trim();
      });
      const ids = await page.evaluate(() =>
        [...document.querySelectorAll("[data-testid]")]
          .map(e => e.getAttribute("data-testid"))
          .filter(x => !/^nav-|^edge-banner|mobile-nav|restaurant-switcher|user-menu/.test(x))
          .sort());
      jr.note(`> **The page's own words, verbatim:** \`${main.slice(0, 300)}\``);
      jr.note(`> **Everything the page offers:** ${ids.length ? "`" + ids.join("`, `") + "`" : "_nothing_"}`);
      if (consoleErrors.length)
        jr.note(`> **The browser also reported:** ${consoleErrors.slice(0, 3)
                  .map(e => "`" + e + "`").join(", ")}`);
      const looksBroken = /is not a function|undefined is not|cannot read/i.test(main);
      if (looksBroken)
        return `The whole page is the words "${main.slice(0, 120)}" — that is a JavaScript `
             + `failure shown to the owner as page content. There is no queue, no drink, no `
             + `control of any kind.`;
      return `The page reads: ${main.slice(0, 240)}`;
    });

    await jr.step("OWNER", "I look for anything a bartender could actually use", async id => {
      const t = await look(page, jr, "owner", id, "looking for a control");
      const usable = await page.evaluate(() =>
        [...document.querySelectorAll("main button, main a[href], main input, main select")]
          .map(e => (e.innerText || e.getAttribute("aria-label") || e.tagName).replace(/\s+/g, " ").trim())
          .filter(Boolean).slice(0, 25));
      if (!usable.length)
        throw new Error(`There is not one button, link or field on this page. A bartender `
                      + `opening it can do nothing at all. Page reads: ${t.slice(0, 160)}`);
      return `Controls offered: ${usable.join(" | ")}`;
    });

    verdict = "WALKED"; why = "Read the bartender screen end to end.";
  } catch (e) {
    verdict = "STOPPED"; why = String(e.message || e).split("\n")[0].slice(0, 300);
    throw e;
  } finally {
    jr.finish(verdict, why);
    await closeRole(ctx, jr, "owner");
  }
});
