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

// The landscape (wide) layout: when the viewport is wider than tall, the game switches to a
// two-column layout — the board fills the right side fitted to the height (no zoom), while the
// rack, status, scores, the always-open history and the controls stack in a left panel. These
// lock the key differences from the portrait layout so a future edit surfaces as a failing
// assertion. The rest of the suite runs portrait (see playwright.config.ts); this spec overrides
// the viewport to a wide, short one.
test.use({ viewport: { width: 1100, height: 640 } });

async function openGame(page: Page): Promise<void> {
  await page.goto('/');
  await page.getByRole('button', { name: /guest/i }).click();
  await page.getByRole('button', { name: /Ann/ }).click(); // the seeded active game vs Ann
  await expect(page.locator('[data-cell]').first()).toBeVisible();
}

test('landscape lays the game in two columns with the history docked open', async ({ page }) => {
  await openGame(page);
  // The two-column landscape wrapper is mounted instead of the portrait stacking.
  await expect(page.locator('.game-land')).toBeVisible();
  // The history is shown without tapping the score bar — it is docked open in the left panel,
  // not a slide-down drawer.
  await expect(page.locator('.history')).toBeVisible();
  // The controls live in the left panel (no bottom tab bar in landscape).
  await expect(page.locator('.leftpane .tabbar')).toBeVisible();
});

test('the docked history shows the newest move', async ({ page }) => {
  // Stretch the cells so the seeded four-move game overflows the docked table's scroller — the
  // condition under which "shows the newest move" is observable at all. Injected at document
  // start: in landscape the table is docked open from the mount, and it is pinned to its last row
  // as soon as the moves arrive. The portrait (drawer) counterpart lives in history.spec.ts.
  await page.addInitScript(() => {
    document.addEventListener('DOMContentLoaded', () => {
      const style = document.createElement('style');
      style.textContent = '.hcell { min-height: 200px !important; }';
      document.head.append(style);
    });
  });
  await openGame(page);

  const m = await page
    .locator('.hgridwrap')
    .evaluate((el) => ({ top: el.scrollTop, scroll: el.scrollHeight, client: el.clientHeight }));
  expect(m.scroll).toBeGreaterThan(m.client); // the table really overflows — no vacuous pass
  expect(m.top).toBeGreaterThanOrEqual(m.scroll - m.client - 1); // pinned to the last row
});

test('landscape zooms the board on a double-tap and the zoomed board overflows the pane', async ({ page }) => {
  await openGame(page);
  // Double-tap an empty cell zooms in, same as portrait. The board is height-driven here, so the
  // zoomed square grows past the wide pane and becomes pannable (scrollWidth exceeds the viewport).
  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();
  await page.waitForTimeout(350); // let the width/height magnify settle
  const overflows = await viewport.evaluate((el) => el.scrollWidth > el.clientWidth + 5);
  expect(overflows).toBe(true);
});

test('landscape still places a tile and commits via the make button', async ({ page }) => {
  await openGame(page);
  // Placement works the same in landscape: tap a rack tile, tap an empty cell adjacent to the
  // seeded word, and the make (✅) control appears next to the rack.
  await page.locator('.rack .tile').first().click();
  await page.locator('[data-cell][data-row="9"][data-col="6"]').click();
  await expect(page.locator('.cell.pending')).toHaveCount(1);
  await expect(page.locator('.make')).toBeVisible();
});

// Placement auto-zoom is portrait-only (Game.svelte gates it on !landscape): landscape fits the
// whole board, so magnifying on every placed tile would only hide the position. The gate also
// requires a coarse pointer, so the block emulates touch and skips on an engine whose emulation
// does not flip `(pointer: coarse)` (desktop WebKit). The portrait counterpart lives in
// zoom.spec.ts.
test.describe('touch placement', () => {
  test.use({ hasTouch: true });

  test('landscape does not auto-zoom when a tile is placed', async ({ page }) => {
    await openGame(page);
    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('.cell.pending')).toHaveCount(1);
    await page.waitForTimeout(400); // the would-be zoom transition window
    await expect(page.locator('.viewport.zoomed')).toHaveCount(0);
  });
});
