// apps/client/test/e2e/cli-08-camera.e2e.test.ts
// [int->REQ-CLI-08]
//
// Plan 06.1-07 Task 1 — GREEN refinement of the 06.1-03 RED skeleton. Camera
// follow / scroll assertion against the Wave 3 wire-up (GameScene D6.1-14/15/16
// applyCameraFollow + Plan 06.1-02 RUN_SPEED_PX_PER_TICK=5 + Pitfall 4
// accumulator-subtract).
//
// Pattern: mirrors `camera-follow.e2e.test.ts` lines 16-89 — login fixture,
// waitForGameReady, __rebno deterministic hook, keyboard.down/up +
// waitForTimeout, before/after delta assertion. NO canvas pixel sampling.
//
// Threshold derivation (Plan 06.1-07 refinement — 300 ms hold for CI margin):
//   RUN_SPEED_PX_PER_TICK = 5 (D6.1-05, Phase 06.1)
//   Sim-tick rate = 30 Hz (CLAUDE.md "Extracted Constants" — speed: 30)
//   At 30 Hz a 300 ms hold spans ~9 sim ticks → ~45 px of intended motion.
//   Threshold 15 px keeps a 3× margin to absorb start-up latency,
//   camera-deadzone delay (D6.1-14 = 32×32 from BNCentral hBorder=304),
//   and jitter under client prediction. The original 06.1-03 skeleton used
//   200 ms; we widen to 300 ms here for CI flakiness reduction on slow runners.

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

test('CLI-08 camera follow — pressing KeyD for 300ms pans camera scrollX (Wave 4 GREEN gate)', async ({
  page,
  accountA,
  inviteSuffix,
}) => {
  // 1. Login and wait for game-ready (mirrors fixtures S-09 pattern).
  await loginAs(page, accountA, inviteSuffix);
  await waitForGameReady(page);

  // 2. Focus the canvas so key events reach the Phaser input layer.
  await page.locator('canvas[data-game-ready="true"]').click();

  // 3. Baseline camera scroll via __rebno deterministic hook (S-08; D6.1-15
  //    cameraScrollX is published every render frame by GameScene.update).
  const before = await page.evaluate(
    () =>
      (
        window as unknown as {
          __rebno?: { cameraScrollX?: number; cameraScrollY?: number };
        }
      ).__rebno?.cameraScrollX ?? null,
  );
  expect(
    before,
    '__rebno.cameraScrollX must be populated by GameScene update hook (Plan 06.1-06 S-08)',
  ).not.toBeNull();

  // 4. Hold KeyD for 300 ms. Math: RUN_SPEED=5 px/tick x (300 ms / 33.33 ms/tick)
  //    ~= 45 px of intended motion; deadzone is 32 px so >=13 px of camera scroll
  //    is expected. Threshold 15 px keeps a 3x margin against the expected
  //    45 px and absorbs deadzone latency + prediction jitter.
  await page.keyboard.down('KeyD');
  await page.waitForTimeout(300);
  await page.keyboard.up('KeyD');

  // 5. Brief settle for prediction/reconciliation.
  await page.waitForTimeout(150);

  // 6. Post-hold camera scroll (read from the same __rebno.cameraScrollX hook
  //    that Plan 06.1-06 publishes per render frame — preferred over Phaser
  //    private state per CONTEXT line "use the rebno-hook field directly").
  const after = await page.evaluate(
    () =>
      (
        window as unknown as {
          __rebno?: { cameraScrollX?: number; cameraScrollY?: number };
        }
      ).__rebno?.cameraScrollX ?? null,
  );

  // 7. Assert camera panned at least 15 px on the x axis (3x margin below
  //    expected 45 px to absorb 32-px deadzone crossing + prediction jitter).
  expect(after).not.toBeNull();
  expect(
    (after as number) - (before as number),
    `Camera scrollX did not advance: before=${before} after=${after}`,
  ).toBeGreaterThan(15);
});
