'use strict';

/*
 * The pairing code has to be readable on the panel it is displayed on.
 *
 * A CSS pixel covers a quarter of the screen area on a 4K panel that it does on 1080p, and a
 * sixteenth on 8K. Every size on the player's pre-playback screens was a hard-coded pixel value,
 * so the 72px pairing code that fills a 1080p screen became a smudge on a 4K wall — reported from
 * the field, on exactly the screens signage gets installed on.
 *
 * The fix is a viewport-proportional root font size with everything on those screens expressed in
 * rem, so the code holds the same ANGULAR size at any panel resolution. These tests pin the two
 * properties that actually matter: nothing on those screens is left in px, and the scaling cannot
 * leak into playback content.
 */
const { test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');

const ROOT = path.join(__dirname, '..', '..');
const read = (p) => fs.readFileSync(path.join(ROOT, p), 'utf8');

const SURFACES = [
  { name: 'web player', file: 'server/player/index.html' },
  { name: 'tizen player', file: 'tizen/css/style.css' },
];

for (const { name, file } of SURFACES) {
  test(`${name}: the root font size is viewport-proportional and clamped at both ends`, () => {
    const src = read(file);
    const m = src.match(/html\s*\{\s*font-size:\s*clamp\(\s*([\d.]+)px\s*,\s*([\d.]+)vmin\s*,\s*([\d.]+)px\s*\)/);
    assert.ok(m, `${file} must set a clamped, vmin-based root font size`);
    const [, min, vmin, max] = m.map(Number);

    // vmin, not vw: a portrait-mounted panel is as common as a landscape one, and vw would render
    // a 1080x1920 screen at half size.
    assert.ok(vmin > 0, 'the middle term must actually scale with the viewport');
    // 1rem should land on 10px at a 1080-tall viewport, so the rem values read as "px at 1080p"
    // and a reviewer can check them against the design at a glance.
    assert.ok(Math.abs(vmin * 1080 / 100 - 10) < 0.1, `1rem must be ~10px at 1080p, got ${vmin * 1080 / 100}px`);
    // The floor keeps a dashboard preview iframe and a laptop window legible rather than
    // microscopic; the ceiling stops an ultrawide from getting silly.
    assert.ok(min >= 6 && min <= 10, `floor should keep small viewports readable, got ${min}px`);
    assert.ok(max >= 32, `ceiling should not cap a genuine 8K panel too early, got ${max}px`);
  });
}

test('web player: the pairing code scales, and is still the biggest thing on the screen', () => {
  const src = read('server/player/index.html');
  const rule = src.slice(src.indexOf('.pairing-code {'), src.indexOf('.pairing-hint'));
  const size = rule.match(/font-size:\s*([\d.]+)rem/);
  assert.ok(size, 'the pairing code must be sized in rem, not px');
  assert.ok(Number(size[1]) >= 7, 'the code is what someone squints at from across a room');
  assert.match(rule, /letter-spacing:\s*[\d.]+rem/, 'letter-spacing must scale with it or the digits collide');

  const h1 = src.match(/#setupScreen h1 \{ font-size: ([\d.]+)rem/);
  assert.ok(h1 && Number(size[1]) > Number(h1[1]), 'the code must outrank the product name');
});

test('tizen player: the pairing code scales too', () => {
  const src = read('tizen/css/style.css');
  const rule = src.slice(src.indexOf('.code {'), src.indexOf('.hint {'));
  assert.match(rule, /font-size:\s*[\d.]+rem/, 'the Tizen pairing code must be sized in rem');
  assert.match(rule, /letter-spacing:\s*[\d.]+rem/);
});

test('no pre-playback screen is left in hard-coded px', () => {
  const src = read('server/player/index.html');
  // Everything from the setup screen through the status overlay. A px value surviving in here is
  // one element that stays put while the rest of the screen grows around it.
  for (const selector of ['#setupScreen h1', '#setupScreen .subtitle', '.pairing-hint', '.status-msg', '#statusOverlay h2', '#statusOverlay p']) {
    const at = src.indexOf(selector + ' {');
    assert.ok(at > 0, `${selector} not found`);
    const rule = src.slice(at, src.indexOf('}', at));
    const px = rule.match(/font-size:\s*[\d.]+px/);
    assert.equal(px, null, `${selector} still has a hard-coded font-size — it will not scale`);
  }
});

test('the scaling cannot reach playback content', () => {
  const src = read('server/player/index.html');
  // The whole safety argument for moving the root font size is that only the pre-playback chrome
  // uses rem. If a stage/zone/PiP rule starts using rem, resizing a panel would start resizing
  // CONTENT, which is a different and much worse bug than the one being fixed here.
  for (const selector of ['#stage', '.zone', '#pip']) {
    const at = src.indexOf(selector + ' {');
    if (at < 0) continue;
    const rule = src.slice(at, src.indexOf('}', at));
    assert.ok(!/[\d.]rem/.test(rule), `${selector} must not use rem — content sizing must stay independent`);
  }
});
