import { expect, test } from './fixtures';

// Item 5: zooming the board must enlarge the labels too (a magnifying-glass zoom).
// cqw is sized against the zoom-scaled board, so the font grows with the cells.
test('zoom enlarges the board labels with the board', async ({ page }) => {
  await page.goto('/');
  await page.getByRole('button', { name: /guest/i }).click();
  await page.getByRole('button', { name: /Ann/ }).click();

  const letter = page.locator('[data-cell] .letter').first();
  await expect(letter).toBeVisible();
  const base = await letter.evaluate((el) => parseFloat(getComputedStyle(el).fontSize));

  // Double-tap an empty cell to zoom in (two synchronous clicks = a double-tap).
  await page
    .locator('[data-cell]:not(.filled)')
    .nth(20)
    .evaluate((el: HTMLElement) => {
      el.click();
      el.click();
    });
  await page.waitForTimeout(400); // let the width transition settle

  const zoomed = await letter.evaluate((el) => parseFloat(getComputedStyle(el).fontSize));
  expect(zoomed).toBeGreaterThan(base * 1.4);
});

// Item 4 (UX): the zoomed board clamps at its edge — no native rubber-band/overscroll past
// the content. We assert the CSS contract on the zoomed scroll container, which is
// deterministic across engines (the bounce gesture itself is a native compositor behaviour
// Playwright cannot reliably synthesize).
test('zoomed board clamps overscroll at the edge', async ({ page }) => {
  await page.goto('/');
  await page.getByRole('button', { name: /guest/i }).click();
  await page.getByRole('button', { name: /Ann/ }).click();

  // Double-tap an empty cell to zoom in.
  await page
    .locator('[data-cell]:not(.filled)')
    .nth(20)
    .evaluate((el: HTMLElement) => {
      el.click();
      el.click();
    });

  const viewport = page.locator('.viewport.zoomed');
  await expect(viewport).toBeVisible();
  const ob = await viewport.evaluate((el) => {
    const s = getComputedStyle(el);
    return { x: s.overscrollBehaviorX, y: s.overscrollBehaviorY };
  });
  expect(ob.x).toBe('none');
  expect(ob.y).toBe('none');
});

// Placement auto-zoom (touch): in portrait, placing a tile magnifies into it. This is the
// counterpart of landscape.spec.ts's no-auto-zoom guard — together they lock the gate to
// orientation only. Skips on an engine whose touch emulation does not flip `(pointer: coarse)`.
test.describe('touch placement', () => {
  test.use({ hasTouch: true });

  test('placing a tile auto-zooms the board in portrait', async ({ page }) => {
    await page.goto('/');
    await page.getByRole('button', { name: /guest/i }).click();
    await page.getByRole('button', { name: /Ann/ }).click();
    await expect(page.locator('[data-cell]').first()).toBeVisible();
    test.skip(
      !(await page.evaluate(() => matchMedia('(pointer: coarse)').matches)),
      'touch emulation does not report a coarse pointer in this engine',
    );
    await page.locator('.rack .tile').first().click();
    await page.locator('[data-cell][data-row="9"][data-col="6"]').click();
    await expect(page.locator('.viewport.zoomed')).toBeVisible();
  });
});

// A hint taken while the board is ALREADY zoomed in now zooms OUT to the whole board, so the played
// word — highlighted while composing — is guaranteed visible rather than parked off-screen under the
// old zoom (the owner changed this from the former recentre-on-the-word behaviour, so the word can
// never be lost off-screen). The mock hint plays at the centre star (7,7).
test('a hint zooms out an already-zoomed board so the played word is visible', async ({ page }) => {
  await page.goto('/');
  await page.getByRole('button', { name: /guest/i }).click();
  await page.getByRole('button', { name: /Ann/ }).click();

  // Zoom into the top-left cell (far from the centre where the hint lands).
  await page
    .locator('[data-cell]:not(.filled)')
    .first()
    .evaluate((el: HTMLElement) => {
      el.click();
      el.click();
    });
  await expect(page.locator('.viewport.zoomed')).toBeVisible();

  // Take a hint (the control confirms on a second tap), which plays at the centre.
  const hint = page.getByRole('button', { name: 'Hint' });
  await hint.click();
  await hint.click();

  // The board zoomed out — no zoomed viewport — with the hint's play staged (the confirm control
  // shows). The mock hint plays on the centre star, which the seeded game already occupies, so the
  // staged tile hides under the committed one; the confirm control is the reliable "a play is
  // staged" signal.
  await expect(page.locator('.viewport.zoomed')).toHaveCount(0);
  await expect(page.locator('.make')).toBeVisible();
});
