// v1.49.x: zoom goes below the base fit, the editor does not shift the plan.
// - the stage height follows the MEASURED header, not a hard-coded 118px, so
//   entering an editor keeps the plan inside the viewport;
// - zoom < 1 centres the content instead of pinning it to a corner;
// - the content frame (default zoom) includes devices standing outside rooms.
import { launch, checkAll, finish } from './serve.mjs';
const { page, browser } = await launch();
const out = {};

// -- editor entry keeps the stage inside the viewport --------------------
const stageBox = () => page.evaluate(() => {
  const sr = window.__card.shadowRoot || window.__card.renderRoot;
  const b = sr.querySelector('.stage').getBoundingClientRect();
  return { top: Math.round(b.top), bottom: Math.round(b.bottom) };
});
const vh = await page.evaluate(() => window.innerHeight);
const inView = await stageBox();
await page.evaluate(() => window.__card._setMode('plan'));
await page.waitForTimeout(400);
const inPlan = await stageBox();
out.viewFitsViewport = inView.bottom <= vh + 2;
out.editorFitsViewport = inPlan.bottom <= vh + 2; // used to overflow by ~90px
out.editorStageShrinks = inPlan.top > inView.top && inPlan.bottom <= inView.bottom + 2;
await page.evaluate(() => window.__card._setMode('view'));
await page.waitForTimeout(300);

// -- zoom out below the base fit -----------------------------------------
out.zoomOut = await page.evaluate(() => {
  const c = window.__card;
  c._resetZoom();
  const fit = { ...c._viewOr(c._baseVb()) };
  const stage = (c.shadowRoot || c.renderRoot).querySelector('.stage');
  c._zoomAt(stage.clientWidth / 2, stage.clientHeight / 2, 0.5);
  const v = { ...c._view };
  const base = c._baseVb();
  const cx = v.x + v.w / 2, cy = v.y + v.h / 2;
  return {
    zoom: c._zoom,
    wider: v.w > fit.w * 1.9,                                   // actually zoomed out
    centredX: Math.abs(cx - (base[0] + base[2] / 2)) < 1,       // not pinned to a corner
    centredY: Math.abs(cy - (base[1] + base[3] / 2)) < 1,
  };
});
out.zoomOutWorks = out.zoomOut.zoom === 0.5 && out.zoomOut.wider
  && out.zoomOut.centredX && out.zoomOut.centredY;
delete out.zoomOut;
out.floorIsHalf = await page.evaluate(() => { window.__card._resetZoom(); const c = window.__card;
  c._applyView(0.1); return c._zoom; }) === 0.4; // clamped at the floor
await page.evaluate(() => window.__card._resetZoom());

// -- devices outside rooms stretch the default frame ---------------------
out.devicesStretchFrame = await page.evaluate(() => {
  const c = window.__card;
  const cfg = JSON.parse(JSON.stringify(c._serverCfg));
  cfg.spaces[0].plan_url = null; cfg.spaces[0].plan_aspect = null;
  c._serverCfg = cfg; c._model = null;
  const before = c._baseVb();
  // walk one lamp far outside every room
  c._layout = { ...c._layout, d_lamp: { s: 'f1', x: 0.99, y: 0.5 } };
  const after = c._baseVb();
  return after[0] + after[2] > before[0] + before[2] + 20; // right edge follows the lamp
});

// -- a card BELOW other dashboard content still gets a stage (HP-1500-02) --
out.stageSurvivesContentAbove = await page.evaluate(async () => {
  const spacer = document.createElement('div');
  spacer.style.height = '900px';
  document.body.insertBefore(spacer, document.body.firstChild);
  window.dispatchEvent(new Event('resize'));
  await new Promise((r) => setTimeout(r, 120));
  const c = window.__card;
  const sr = c.shadowRoot || c.renderRoot;
  const h = sr.querySelector('.stage').getBoundingClientRect().height;
  spacer.remove();
  window.dispatchEvent(new Event('resize'));
  await new Promise((r) => setTimeout(r, 120));
  // the old code billed the 900px spacer as "header" and left a 0px stage
  return h > 300;
});

await finish(browser, checkAll(out));
