// Coverage for the map's light / dark palette threading. The map
// renderer follows the resolved app theme: `map.svelte` selects
// `DARK_THEME` or `LIGHT_THEME` and threads it through every primitive
// builder so the canvas, planets, ship groups, routes, markers, and
// overlays all switch with the rest of the chrome. These tests pin the
// palette plumbing — that the builders honour the supplied palette and
// that the two palettes actually differ role-for-role — without booting
// Pixi. The per-builder colour tests (battle-markers, cargo-routes,
// selection-ring) cover their own surfaces; this spec covers the
// planet, ship-group, and reach-ring paths plus the palette invariants.

import { describe, expect, test } from "vitest";

import type { GameReport, ReportPlanet } from "../src/api/game-state";
import { computeReachCircles } from "../src/map/reach-circles";
import { reportToWorld } from "../src/map/state-binding";
import { DARK_THEME, LIGHT_THEME, type Theme } from "../src/map/world";
import { EMPTY_SHIP_GROUPS } from "./helpers/empty-ship-groups";

function makeReport(overrides: Partial<GameReport> = {}): GameReport {
	return {
		turn: 1,
		mapWidth: 4000,
		mapHeight: 4000,
		planetCount: 0,
		planets: [],
		race: "",
		localShipClass: [],
		routes: [],
		localPlayerDrive: 0,
		localPlayerWeapons: 0,
		localPlayerShields: 0,
		localPlayerCargo: 0,
		...EMPTY_SHIP_GROUPS,
		...overrides,
	};
}

function makePlanet(overrides: Partial<ReportPlanet>): ReportPlanet {
	return {
		number: 0,
		name: "",
		x: 0,
		y: 0,
		kind: "local",
		owner: null,
		size: null,
		resources: null,
		industryStockpile: null,
		materialsStockpile: null,
		industry: null,
		population: null,
		colonists: null,
		production: null,
		freeIndustry: null,
		...overrides,
	};
}

function planetFill(
	kind: ReportPlanet["kind"],
	theme?: Theme,
): number | undefined {
	const { world } = reportToWorld(
		makeReport({ planets: [makePlanet({ number: 1, kind })] }),
		theme,
	);
	return world.primitives[0]?.style.fillColor;
}

describe("map palette threading", () => {
	test("planet glyphs default to the dark palette", () => {
		expect(planetFill("local")).toBe(DARK_THEME.planetLocal);
	});

	test("planet glyphs follow the supplied palette per kind", () => {
		expect(planetFill("local", LIGHT_THEME)).toBe(LIGHT_THEME.planetLocal);
		expect(planetFill("other", LIGHT_THEME)).toBe(LIGHT_THEME.planetOther);
		expect(planetFill("uninhabited", LIGHT_THEME)).toBe(
			LIGHT_THEME.planetUninhabited,
		);
		expect(planetFill("unidentified", LIGHT_THEME)).toBe(
			LIGHT_THEME.planetUnidentified,
		);
	});

	test("incoming-group accent follows the palette", () => {
		const report = makeReport({
			planets: [
				makePlanet({ number: 1, x: 0, y: 0, kind: "local" }),
				makePlanet({ number: 2, x: 100, y: 0, kind: "local" }),
			],
			incomingShipGroups: [
				{ origin: 1, destination: 2, distance: 10, speed: 5, mass: 1 },
			],
		});
		for (const theme of [DARK_THEME, LIGHT_THEME]) {
			const { world, hitLookup } = reportToWorld(report, theme);
			// Locate the clickable incoming point via the hit-lookup.
			let incomingId: number | null = null;
			for (const [id, target] of hitLookup) {
				if (
					target.kind === "shipGroup" &&
					target.ref.variant === "incoming"
				) {
					incomingId = id;
					break;
				}
			}
			expect(incomingId).not.toBeNull();
			const point = world.primitives.find((p) => p.id === incomingId);
			expect(point?.style.fillColor).toBe(theme.shipIncoming);
		}
	});

	test("reach rings follow the supplied palette", () => {
		const dark = computeReachCircles({ x: 0, y: 0 }, 100, 1000, 1000, "torus");
		expect(dark[0]?.style.strokeColor).toBe(DARK_THEME.reachCircle);
		const light = computeReachCircles(
			{ x: 0, y: 0 },
			100,
			1000,
			1000,
			"torus",
			LIGHT_THEME,
		);
		expect(light[0]?.style.strokeColor).toBe(LIGHT_THEME.reachCircle);
	});
});

describe("palette invariants", () => {
	test("the two palettes define the same fields", () => {
		expect(Object.keys(LIGHT_THEME).sort()).toEqual(
			Object.keys(DARK_THEME).sort(),
		);
	});

	test("the canvas background and accents differ between palettes", () => {
		expect(LIGHT_THEME.background).not.toBe(DARK_THEME.background);
		expect(LIGHT_THEME.shipIncoming).not.toBe(DARK_THEME.shipIncoming);
		expect(LIGHT_THEME.battleMarker).not.toBe(DARK_THEME.battleMarker);
		expect(LIGHT_THEME.bombingWiped).not.toBe(DARK_THEME.bombingWiped);
	});
});
