/**
 * The one inequality that makes the arrival guard necessary.
 *
 * `main.ts`'s `maybeHandover` refuses to run while `handle.arriving()` is true.
 * That line looks like belt-and-braces and is not: without it, landing on any
 * board with the free-camera handover on threw the visitor straight back to the
 * coarser tier they came from, with no input at all. It was measured on the
 * deployed bundle twice — `?city=sf` alone stays on the Bay Area, `?city=sf` with
 * the handover on reported "San Francisco Bay Area" and then "California".
 *
 * The cause is arithmetic rather than tuning, which is why it is asserted here
 * rather than left to a screenshot. `arrivalStart` opens every board's
 * unrequested move at `ARRIVAL_STANDOFF` times the resting stand-off, and
 * `handover` demotes a board once the camera passes `DEMOTE` times that board's
 * handover ceiling. A board's ceiling is its own widest authored pose, so the
 * opening frame sits outside its own retention band for as long as
 * `ARRIVAL_STANDOFF > DEMOTE` — and it does, for every board there will ever be,
 * because both are single global constants.
 *
 * So this file exists to fail the day somebody "simplifies" one of three things:
 * the guard, `ARRIVAL_STANDOFF`, or `DEMOTE`.
 */

import assert from "node:assert/strict";
import { describe, it } from "node:test";

import { ARRIVAL_STANDOFF } from "../engine/scene.ts";
import { DEMOTE, HANDOVER_STANDOFF_M, PROMOTE, handover } from "../engine/ladder.ts";
import SAN_FRANCISCO from "../cities/sf.ts";
import SOCAL from "../cities/socal.ts";
import CALIFORNIA from "../cities/california.ts";

const BOARDS = [CALIFORNIA, SAN_FRANCISCO, SOCAL].map((city) => ({
  id: city.id,
  bounds: city.bounds,
  metresPerUnit: 111_320 / city.latScale,
}));

describe("the arrival guard", () => {
  it("is required, because the opening move starts outside every board's retention band", () => {
    assert.ok(
      ARRIVAL_STANDOFF > DEMOTE,
      `arrival opens at ${ARRIVAL_STANDOFF}x resting and a board is demoted above ` +
        `${DEMOTE}x its ceiling — if this ever stops being true the guard in ` +
        "maybeHandover may be reconsidered, and until then it may not",
    );
  });

  it("would demote a board on its own opening frame, for each board that has a ceiling", () => {
    /*
     * The failure the guard prevents, reproduced through the real rule: put the
     * camera where `arrivalStart` puts it — 1.5x the resting stand-off, which for
     * a board at rest on its own widest pose is 1.5x its ceiling — and ask the
     * ladder what board that is. It answers "a coarser one", every time.
     */
    for (const [id, ceiling] of Object.entries(HANDOVER_STANDOFF_M)) {
      const board = BOARDS.find((candidate) => candidate.id === id);
      assert.ok(board, `no pack for ${id}`);
      const centre = { lat: (board.bounds.minLat + board.bounds.maxLat) / 2,
                       lng: (board.bounds.minLng + board.bounds.maxLng) / 2 };
      const opening = handover({
        boards: BOARDS,
        current: id,
        lat: centre.lat,
        lng: centre.lng,
        standoffM: ceiling * ARRIVAL_STANDOFF,
        dragging: false,
      });
      assert.equal(
        opening,
        "california",
        `${id}'s opening frame does not demote, so this test is asserting nothing`,
      );

      // And once the move has landed, the same board is stable: no promotion out
      // of it and no demotion off it. That is the state the guard hands over to.
      const settled = handover({
        boards: BOARDS,
        current: id,
        lat: centre.lat,
        lng: centre.lng,
        standoffM: ceiling,
        dragging: false,
      });
      assert.equal(settled, null, `${id} is not stable at its own resting stand-off`);
    }
  });

  const SF_CEILING = HANDOVER_STANDOFF_M.sf ?? 0;

  it("still promotes on the way in, which is the behaviour being protected", () => {
    // Below the ceiling by more than the hysteresis band: the Bay Area is the
    // right board for a camera this close to San Francisco.
    const promoted = handover({
      boards: BOARDS,
      current: "california",
      lat: 37.77,
      lng: -122.42,
      standoffM: SF_CEILING * PROMOTE * 0.9,
      dragging: false,
    });
    assert.equal(promoted, "sf");
  });

  it("never swaps a board out from under a finger", () => {
    const held = handover({
      boards: BOARDS,
      current: "california",
      lat: 37.77,
      lng: -122.42,
      standoffM: SF_CEILING * PROMOTE * 0.9,
      dragging: true,
    });
    assert.equal(held, null);
  });
});
