/**
 * The state board is the whole state, and the cell that paid for it.
 *
 * This board used to stop at 38.05 N. The minimap beside it draws the whole of
 * California from the same pack, so a single frame contained a picture of the
 * state and a picture of two thirds of the state, disagreeing about the shape of
 * the one silhouette in this product that everybody already knows. That is the
 * defect this file guards, and the reason it is a pack test and not a picture
 * is that a picture is what it took to notice.
 *
 * ## The three claims, and why each one needs an assertion
 *
 *   1. **The bounds reach the corners.** Easy to state, easy to half-do: an
 *      extension that moved `maxLat` and forgot `minLng` gives a state with an
 *      Oregon border and no Cape Mendocino, which reads as a different place.
 *   2. **The land was authored, not merely permitted.** Growing `bounds` costs
 *      nothing and draws nothing — the polygon decides where the ground is, and
 *      a board whose bounds reach 42 N over a coastline that stops at 38.13 is a
 *      board with two hundred kilometres of open ocean where the North Coast is.
 *      Twenty vertices north of 40 N is the cheapest arithmetic statement of
 *      "somebody traced this".
 *   3. **The cell was coarsened to pay for it.** This is the load-bearing one.
 *      At the old 0.022 x 0.027 the extended board takes the lattice from 84,924
 *      points to 168,813 — 2.02x — and the terrain with it, against a mobile
 *      budget with 70,000 triangles spare and two more layers landing on the same
 *      board in the same round. The 1.42x coarsening is the entire reason the
 *      extension fits, and it is one edit away from being silently reverted by
 *      somebody who thinks a finer lattice is always better.
 */

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

import CALIFORNIA, { CORRIDOR_LAND } from "../../cities/california.ts";
import { World, computeField } from "../../engine/world.ts";

/** Metres in a degree of latitude. The same constant `World` uses. */
const M_PER_DEGREE = 111_320;

describe("the board reaches the whole state", () => {
  it("contains the corners the old bounds cut off", () => {
    const { bounds } = CALIFORNIA;
    // Crescent City is at 41.75 N; the Oregon line is at 42.00. A board that
    // stops short of 41.9 has cut off Del Norte County and the redwoods.
    assert.ok(bounds.maxLat > 41.9, `maxLat is ${bounds.maxLat}`);
    // Cape Mendocino is the westernmost ground in California at -124.41, and it
    // is the corner that makes the northern silhouette read as this state.
    assert.ok(bounds.minLng < -124.3, `minLng is ${bounds.minLng}`);
    // And the three edges that were already right stayed right.
    assert.ok(bounds.minLat <= 32.55, `minLat is ${bounds.minLat}`);
    assert.ok(bounds.maxLng >= -114.0, `maxLng is ${bounds.maxLng}`);
  });

  it("centres scene space on the middle of the bounds", () => {
    // Everything sized from the origin — the satellite dome, the shadow box, the
    // star field — is centred with it, so a centre left where it was when the
    // board was smaller makes all three too small on the far side by the offset.
    const { bounds, center } = CALIFORNIA;
    const midLat = (bounds.minLat + bounds.maxLat) / 2;
    const midLng = (bounds.minLng + bounds.maxLng) / 2;
    assert.ok(Math.abs(center.lat - midLat) < 0.2, `centre is ${center.lat}, middle is ${midLat}`);
    assert.ok(Math.abs(center.lng - midLng) < 0.4, `centre is ${center.lng}, middle is ${midLng}`);
  });

  it("has a traced North Coast rather than a wider empty ocean", () => {
    const north = CORRIDOR_LAND.filter(([lat]) => lat > 40.0);
    assert.ok(
      north.length >= 20,
      `only ${north.length} vertices north of 40 N — the added land is a shelf, not a coast`,
    );
    // The cape itself, because it is the one vertex whose absence changes the
    // silhouette rather than the detail: without it the North Coast is a
    // straight line from Trinidad to Shelter Cove.
    assert.ok(
      CORRIDOR_LAND.some(([lat, lng]) => lat > 40.3 && lat < 40.6 && lng < -124.35),
      "Cape Mendocino is not in the trace",
    );
  });

  it("puts real ground under the new land, north and north-east", () => {
    const world = new World(CALIFORNIA);
    for (const [name, lat, lng] of [
      ["Crescent City", 41.75, -124.18],
      ["Eureka", 40.8, -124.16],
      ["Redding", 40.58, -122.39],
      ["Sacramento", 38.58, -121.49],
      ["Mount Shasta", 41.41, -122.19],
      ["Alturas, in Modoc", 41.49, -120.54],
    ] as [string, number, number][]) {
      assert.equal(world.isLand(lat, lng), true, `${name} is not on the board`);
    }
    // And the two edges that are new: Oregon is not California, and neither is
    // the Great Basin east of the 120th meridian.
    assert.equal(world.isLand(42.3, -122.5), false, "Oregon is on the board");
    assert.equal(world.isLand(41.0, -119.5), false, "Nevada is on the board");
  });

  it("stands Shasta and Lassen up as the two things that make the north the north", () => {
    const world = new World(CALIFORNIA);
    world.lattice();
    assert.ok(
      world.elevationAt(41.409, -122.194) > 3_800,
      `Shasta is only ${Math.round(world.elevationAt(41.409, -122.194))} m`,
    );
    assert.ok(
      world.elevationAt(40.488, -121.505) > 2_600,
      `Lassen is only ${Math.round(world.elevationAt(40.488, -121.505))} m`,
    );
    // The gap between them is as much of the picture as the peaks. Hat Creek
    // country sits around 1,000 m and must not be filled in by either skirt.
    assert.ok(world.elevationAt(40.95, -121.5) < 2_200, "the Cascade gap has been filled in");
    // And the Sacramento Valley is a floor, not a range: farmland at tens of
    // metres, which is what makes the ranges either side of it read as ranges.
    for (const [lat, lng] of [[39.5, -121.95], [39.0, -121.75], [40.2, -122.1]] as const) {
      const floor = world.elevationAt(lat, lng);
      assert.ok(floor < 300, `the Sacramento Valley at ${lat}N is ${Math.round(floor)} m`);
      assert.ok(floor > 3, `the Sacramento Valley at ${lat}N is at the beach colour`);
    }
  });
});

describe("the cell is what paid for the extension", () => {
  it("holds the ground cell between 3.3 and 3.7 kilometres", () => {
    const metres = CALIFORNIA.cellLat * M_PER_DEGREE;
    assert.ok(
      metres > 3_300 && metres < 3_700,
      `the cell is ${Math.round(metres)} m. Below 3,300 the lattice doubles and the ` +
        "terrain goes through the mobile budget; above 3,700 the Sierra stops " +
        "reading as a range.",
    );
    // Longitude is squashed by cos(centre latitude), so an equal-area cell has to
    // be 1/cos as wide as it is tall. Both axes were multiplied by the same 1.42.
    const squash = Math.cos((CALIFORNIA.center.lat * Math.PI) / 180);
    const ratio = CALIFORNIA.cellLng / CALIFORNIA.cellLat;
    assert.ok(
      Math.abs(ratio - 1 / squash) < 0.06,
      `the cell is ${ratio.toFixed(3)} as wide as it is tall; 1/cos(${CALIFORNIA.center.lat}) ` +
        `is ${(1 / squash).toFixed(3)}, so the ground cell is not square`,
    );
  });

  it("holds the lattice where it was on a board a third bigger", () => {
    const field = computeField(new World(CALIFORNIA));
    const points = (field.latSteps + 1) * (field.lngSteps + 1);
    // 84,924 was the measured figure on the board that stopped at 38.05, and the
    // whole argument of the coarsening is that this number does not move. A 5%
    // band, because it is a rounding of two axis lengths and not a target.
    assert.ok(
      points > 80_000 && points < 89_200,
      `the lattice is ${points} points against 84,924 on the smaller board`,
    );
  });

  it("keeps the cell finer in the frame than the board two revisions ago", () => {
    /**
     * The claim the coarsening rests on, asserted rather than argued.
     *
     * What the eye sees is not the cell in metres — it is the cell as a fraction
     * of the board, because the camera retreats to frame whatever it is given.
     * The corridor board before it grew east was 0.020° on 284 units, which is
     * 0.0041 of a span; the board that stopped at 38.05 was 0.022° on 428, or
     * 0.0030. This board must land between them, which means the cell got 42%
     * coarser on the earth and *finer* in the frame than the board two revisions
     * ago.
     */
    const world = new World(CALIFORNIA);
    const [westX, northZ] = world.project(CALIFORNIA.bounds.maxLat, CALIFORNIA.bounds.minLng);
    const [eastX, southZ] = world.project(CALIFORNIA.bounds.minLat, CALIFORNIA.bounds.maxLng);
    const span = Math.max(Math.abs(eastX - westX), Math.abs(southZ - northZ));
    const cellUnits = CALIFORNIA.cellLat * CALIFORNIA.latScale;
    const fraction = cellUnits / span;
    assert.ok(
      fraction < 0.0041,
      `the cell is ${fraction.toFixed(4)} of the board span, coarser in frame than ` +
        "the 0.0041 of the board before the state's eastern edge arrived",
    );
    assert.ok(
      fraction > 0.0025,
      `the cell is ${fraction.toFixed(4)} of the board span, which is finer than the ` +
        "board has ever needed and is being paid for in terrain triangles",
    );
  });
});
