/** Contract tests for the authored California transport pack. */

import assert from "node:assert/strict";
import { describe, it } from "node:test";
import CALIFORNIA_TRANSPORT from "../transport/california.ts";
import type { GeographicPoint, TransportRoute } from "../transport/types.ts";

function assertUnique(values: readonly string[], what: string): void {
  assert.equal(new Set(values).size, values.length, `${what} must be unique`);
}

function assertPoint(point: GeographicPoint, what: string): void {
  assert.ok(Number.isFinite(point.lat), `${what} latitude must be finite`);
  assert.ok(Number.isFinite(point.lng), `${what} longitude must be finite`);
  assert.ok(point.lat >= -90 && point.lat <= 90, `${what} latitude is outside the globe`);
  assert.ok(point.lng >= -180 && point.lng <= 180, `${what} longitude is outside the globe`);
}

function assertProvenance(value: string, what: string): void {
  assert.ok(value.trim().length > 20, `${what} needs meaningful provenance`);
}

function routeSegments(route: TransportRoute) {
  const byId = new Map(CALIFORNIA_TRANSPORT.segments.map((segment) => [segment.id, segment]));
  return route.segmentIds.map((id) => {
    const segment = byId.get(id);
    assert.ok(segment, `route ${route.id} references missing segment ${id}`);
    return segment;
  });
}

describe("California transport graph", () => {
  it("has stable, unique identifiers and valid references", () => {
    assertUnique(
      CALIFORNIA_TRANSPORT.nodes.map((node) => node.id),
      "node ids",
    );
    assertUnique(
      CALIFORNIA_TRANSPORT.segments.map((segment) => segment.id),
      "segment ids",
    );
    assertUnique(
      CALIFORNIA_TRANSPORT.routes.map((route) => route.id),
      "route ids",
    );
    assertUnique(
      CALIFORNIA_TRANSPORT.anchors.map((anchor) => anchor.id),
      "anchor ids",
    );

    const nodeIds = new Set(CALIFORNIA_TRANSPORT.nodes.map((node) => node.id));
    for (const segment of CALIFORNIA_TRANSPORT.segments) {
      assert.ok(nodeIds.has(segment.fromNodeId), `${segment.id} has no start node`);
      assert.ok(nodeIds.has(segment.toNodeId), `${segment.id} has no end node`);
    }
    for (const anchor of CALIFORNIA_TRANSPORT.anchors) {
      assert.ok(nodeIds.has(anchor.nodeId), `${anchor.id} has no corridor node`);
    }
  });

  it("keeps every route continuous from its declared start to its declared end", () => {
    for (const route of CALIFORNIA_TRANSPORT.routes) {
      const segments = routeSegments(route);
      assert.ok(segments.length > 0, `${route.id} is empty`);
      assert.equal(segments[0]?.fromNodeId, route.fromNodeId);
      assert.equal(segments.at(-1)?.toNodeId, route.toNodeId);

      for (let index = 1; index < segments.length; index += 1) {
        assert.equal(
          segments[index - 1]?.toNodeId,
          segments[index]?.fromNodeId,
          `${route.id} breaks between segments ${index - 1} and ${index}`,
        );
      }
    }
  });

  it("names I-5's real Bay connectors instead of pretending I-5 reaches San Francisco", () => {
    const route = CALIFORNIA_TRANSPORT.routes.find((candidate) => candidate.id === "la-sf-i-5");
    assert.ok(route);
    const roads = routeSegments(route).map((segment) => segment.roadName);

    assert.deepEqual([...new Set(roads)], ["I-5", "I-580", "I-80 / Bay Bridge", "I-80"]);
    assert.match(route.label, /I-580/);
    assert.match(route.label, /I-80/);
  });

  it("keeps US-101 on US-101 for the complete authored itinerary", () => {
    const route = CALIFORNIA_TRANSPORT.routes.find((candidate) => candidate.id === "la-sf-us-101");
    assert.ok(route);
    assert.ok(routeSegments(route).every((segment) => segment.roadName === "US-101"));
  });

  it("contains finite California coordinates and usable simulation envelopes", () => {
    for (const node of CALIFORNIA_TRANSPORT.nodes) {
      assertPoint(node.position, `node ${node.id}`);
      assert.ok(node.position.lat >= 32 && node.position.lat <= 42, `${node.id} is outside California`);
      assert.ok(node.position.lng >= -125 && node.position.lng <= -114, `${node.id} is outside California`);
    }
    for (const anchor of CALIFORNIA_TRANSPORT.anchors) {
      assertPoint(anchor.position, `anchor ${anchor.id}`);
    }
    for (const segment of CALIFORNIA_TRANSPORT.segments) {
      assert.ok(segment.speedLimitMph > 0 && segment.speedLimitMph <= 70);
      assert.ok(Number.isInteger(segment.lanesPerDirection));
      assert.ok(segment.lanesPerDirection >= 1 && segment.lanesPerDirection <= 8);
    }
  });

  it("records provenance on every authored item", () => {
    for (const note of CALIFORNIA_TRANSPORT.provenance) assertProvenance(note, "pack");
    for (const node of CALIFORNIA_TRANSPORT.nodes) assertProvenance(node.provenance, node.id);
    for (const segment of CALIFORNIA_TRANSPORT.segments) {
      assertProvenance(segment.provenance, segment.id);
    }
    for (const route of CALIFORNIA_TRANSPORT.routes) assertProvenance(route.provenance, route.id);
    for (const anchor of CALIFORNIA_TRANSPORT.anchors) {
      assertProvenance(anchor.provenance, anchor.id);
    }
  });

  it("has scene anchors for both cities and all shipped offices", () => {
    const cityIds = CALIFORNIA_TRANSPORT.anchors
      .filter((anchor) => anchor.kind === "city")
      .map((anchor) => anchor.cityId)
      .sort();
    const officeIds = CALIFORNIA_TRANSPORT.anchors
      .filter((anchor) => anchor.kind === "office")
      .map((anchor) => anchor.officeId)
      .sort();

    assert.deepEqual(cityIds, ["sf", "socal"]);
    assert.deepEqual(officeIds, ["frontier-valley", "lumbridge-hq", "mateo-court"]);
  });

  it("survives a JSON round trip without losing data", () => {
    assert.deepEqual(JSON.parse(JSON.stringify(CALIFORNIA_TRANSPORT)), CALIFORNIA_TRANSPORT);
  });
});
