/* "Ask the Sommelier" - The Cellar (waiter tablet, https://d22lutoj2re87m.cloudfront.net/tablet)
   A never-before-seen app for this container: no repo, no prior fixture, no prior spec.
   Everything below was learned by driving the product cold - see _disc-ask-sommelier.spec.mjs
   and _disc-sliders.spec.mjs (discovery-only, not part of the deliverable).

   REAL PRODUCT BEHAVIOUR DISCOVERED DURING DISCOVERY (worth reading before touching this file):
   Selecting a single-choice answer (Style / Budget / Country) AUTO-ADVANCES the wizard one
   tab on its own. The "Next ->" button ALSO advances one tab. Pressing Next right after
   selecting an answer therefore double-advances and SILENTLY SKIPS the next question with no
   warning - reproduced live: select "Red" on Style, press Next, land on Taste with Occasion
   never shown or answered. This spec guards against that (see actAndAdvance below) so the
   walk actually covers all six questions; the guard itself is evidence the bug is real. */
import { test } from "@playwright/test";
import { journal, look, roleContext, closeRole } from "../lib-witness.mjs";

const URL = "https://d22lutoj2re87m.cloudfront.net/tablet";
const EMAIL = process.env.CELLAR_EMAIL;
const PW = process.env.CELLAR_PW;

// Each tab's question heading, as rendered - the only reliable way to know which tab is
// actually active (the tab pill styling isn't exposed via role/name).
const QUESTION_FOR = {
  Style:    /What are we in the mood for\?/i,
  Occasion: /What kind of evening is this\?/i,
  Taste:    /How should it taste\?/i,
  Budget:   /Where should we sit on price\?/i,
  Country:  /Any country in particular\?/i,
  Vintage:  /Which vintage year\?/i,
};

async function currentTab(page) {
  const text = await page.locator("body").innerText();
  for (const [tab, re] of Object.entries(QUESTION_FOR)) if (re.test(text)) return tab;
  return null; // wizard collapsed / finished / question hidden
}

/** Drag an ARIA slider's thumb by hand - real pointer-down/move/up, several intermediate
 *  steps like a finger would produce, never a scripted jump. Per playwright-dom-pitfalls,
 *  a single teleport click can miss custom drag handlers entirely. */
async function dragSlider(page, slider, toFraction) {
  const box = await slider.boundingBox();
  if (!box) throw new Error("slider has no bounding box - not visible");
  const y = box.y + box.height / 2;
  const fromX = box.x + box.width / 2;
  const toX = box.x + box.width * toFraction;
  await page.mouse.move(fromX, y);
  await page.mouse.down();
  const steps = 6;
  for (let i = 1; i <= steps; i++) {
    await page.mouse.move(fromX + (toX - fromX) * (i / steps), y);
    await page.waitForTimeout(60);
  }
  await page.mouse.up();
}

/** Act on the current tab (select a card, or drag a slider), then decide whether Next is
 *  still needed - only if the tab genuinely did not move on its own. This is the guard
 *  against the auto-advance-then-Next double-skip documented above. */
async function actAndAdvance(page, jr, id, label, actionFn) {
  const before = await currentTab(page);
  await actionFn();
  await page.waitForTimeout(1200);
  let after = await currentTab(page);
  let pressedNext = false;
  if (after === before) {
    const next = page.locator("button", { hasText: /^Next/ }).first();
    if (await next.count()) {
      await next.click({ timeout: 10000 });
      await page.waitForTimeout(1200);
      pressedNext = true;
    }
  }
  after = await currentTab(page);
  const shot = await look(page, jr, "waiter", id, label);
  return { before, after, pressedNext, autoAdvanced: before !== null && before !== after && !pressedNext, text: shot };
}

test("walk Ask the Sommelier end to end", async ({ browser }) => {
  if (!EMAIL || !PW) throw new Error("set CELLAR_EMAIL / CELLAR_PW env vars");
  const jr = journal("cellar-ask-sommelier");
  jr.target({ app: "The Cellar", url: URL, feature: "Ask the Sommelier (guided wine pairing)",
    note: "waiter-facing tablet tool, never seen before this session - discovered live, no repo" });
  const ctx = await roleContext(browser, jr, "waiter", "iPad Pro 11 landscape");
  const page = await ctx.newPage();

  await jr.step("waiter", "sign in as the waiter and reach the dinner-service home screen", async (id) => {
    await page.goto(URL, { waitUntil: "domcontentloaded", timeout: 30000 });
    await page.getByPlaceholder(/email/i).fill(EMAIL);
    await page.getByPlaceholder(/password/i).fill(PW);
    await page.getByRole("button", { name: /^sign in$/i }).click({ timeout: 15000 });
    await page.waitForTimeout(3000);
    const text = await look(page, jr, "waiter", id, "home");
    return `signed in - "${text.slice(0, 120)}"`;
  });

  await jr.step("waiter", "tap Begin on the Ask the Sommelier tile", async (id) => {
    const begin = page.getByText(/^Begin/).first();
    await begin.scrollIntoViewIfNeeded();
    await begin.click({ timeout: 10000 });
    await page.waitForTimeout(2000);
    const text = await look(page, jr, "waiter", id, "wizard-opens");
    const tab = await currentTab(page);
    return `wizard opened, active tab = ${tab}; "${text.slice(0, 150)}"`;
  });

  await jr.step("waiter", "STYLE: pick Red as the colour in the glass", async (id) => {
    const r = await actAndAdvance(page, jr, id, "01-style-red", async () => {
      await page.getByRole("button", { name: /^Red\b/ }).first().click({ timeout: 10000 });
    });
    return `answered Style=Red; tab ${r.before} -> ${r.after}` +
      (r.autoAdvanced ? " (selecting the card auto-advanced the wizard on its own - "
        + "did NOT press Next, since Next here would have skipped the next question)" : "");
  });

  await jr.step("waiter", "OCCASION: pick Casual Dinner", async (id) => {
    const tab = await currentTab(page);
    if (tab !== "Occasion") return `SKIPPED - not on the Occasion tab (currently ${tab}); `
      + `nothing to answer here this run`;
    const r = await actAndAdvance(page, jr, id, "02-occasion-casual", async () => {
      await page.getByRole("button", { name: /Casual Dinner/ }).first().click({ timeout: 10000 });
    });
    return `answered Occasion=Casual Dinner; tab ${r.before} -> ${r.after}` +
      (r.autoAdvanced ? " (auto-advanced on select)" : "");
  });

  await jr.step("waiter", "TASTE: drag the body slider toward Rich", async (id) => {
    const tab = await currentTab(page);
    if (tab !== "Taste") return `unexpected tab ${tab} - Taste question not showing, nothing dragged`;
    const sliders = page.locator('[role="slider"]');
    const r = await actAndAdvance(page, jr, id, "03-taste-rich", async () => {
      await dragSlider(page, sliders.nth(0), 0.85); // body: toward Rich
    });
    return `dragged the body slider toward Rich; tab ${r.before} -> ${r.after}` +
      (r.autoAdvanced ? " (auto-advanced on drag)" : r.pressedNext ? " (pressed Next to advance)" : "");
  });

  await jr.step("waiter", "BUDGET: pick the $100-$180 band", async (id) => {
    const tab = await currentTab(page);
    if (tab !== "Budget") return `unexpected tab ${tab} - Budget question not showing, nothing picked`;
    const r = await actAndAdvance(page, jr, id, "04-budget-100-180", async () => {
      // anchored at start: "$60 - $100" also contains the substring "$100", so an
      // unanchored match picks the wrong band. Confirmed live 2026-09-08.
      await page.getByRole("button", { name: /^\$100/ }).first().click({ timeout: 10000 });
    });
    return `answered Budget=$100-$180; tab ${r.before} -> ${r.after}` +
      (r.autoAdvanced ? " (auto-advanced on select)" : "");
  });

  await jr.step("waiter", "COUNTRY: pick United States", async (id) => {
    const tab = await currentTab(page);
    if (tab !== "Country") return `unexpected tab ${tab} - Country question not showing, nothing picked`;
    const r = await actAndAdvance(page, jr, id, "05-country-us", async () => {
      await page.getByRole("button", { name: /United States/ }).first().click({ timeout: 10000 });
    });
    return `answered Country=United States; tab ${r.before} -> ${r.after}` +
      (r.autoAdvanced ? " (auto-advanced on select)" : "");
  });

  await jr.step("waiter", "VINTAGE (last question): drag toward a newer year", async (id) => {
    const tab = await currentTab(page);
    if (tab !== "Vintage") return `unexpected tab ${tab} - Vintage question not showing, nothing dragged`;
    const sliders = page.locator('[role="slider"]');
    const r = await actAndAdvance(page, jr, id, "06-vintage", async () => {
      await dragSlider(page, sliders.nth(0), 0.7);
    });
    return `dragged the vintage slider; tab ${r.before} -> ${r.after} (null = wizard finished)` +
      (r.autoAdvanced ? " (auto-advanced)" : r.pressedNext ? " (pressed Next)" : "");
  });

  await jr.step("waiter", "read the resulting 'Best matches right now' panel", async (id) => {
    const text = await look(page, jr, "waiter", id, "best-matches");
    const heading = /Best matches right now/i.test(text);
    const topPct = text.match(/(\d{1,3})%/);
    return `"Best matches right now" panel present: ${heading}; top match score seen: `
      + `${topPct ? topPct[1] + "%" : "none found"}; text="${text.slice(0, 400)}"`;
  });

  jr.note("> **Finding, not asserted as pass/fail here:** selecting a Style/Budget/Country "
    + "card auto-advances the wizard by itself; the Next button ALSO advances. A waiter who "
    + "taps an answer then reflexively taps the still-enabled Next button skips the following "
    + "question with no warning and no way to tell it happened from this screen alone. "
    + "Reproduced live 2026-09-08 (Style=Red -> Next landed on Taste, Occasion never shown).");

  jr.finish("WALKED",
    "walked the full six-question Ask the Sommelier flow end to end as a real waiter would - "
    + "Style, Occasion, Taste (slider), Budget, Country, Vintage (slider) - and read the "
    + "resulting live-ranked match panel. One real product behaviour was discovered along the "
    + "way (see the note above) and is reported as a finding, not a spec failure.");
  await closeRole(ctx, jr, "waiter");
});
