// Vitest coverage for the pending-Send overlay. The overlay
// renders a green dashed line from the source group's orbit
// planet to the chosen destination for every wire-valid
// `sendShipGroup` command in the order draft.

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

import type {
	GameReport,
	ReportLocalShipGroup,
	ReportPlanet,
} from "../src/api/game-state";
import type { OrderCommand } from "../src/sync/order-types";
import { buildPendingSendLines } from "../src/map/pending-send-routes";

function planet(overrides: Partial<ReportPlanet> & Pick<ReportPlanet, "number" | "x" | "y">): ReportPlanet {
	return {
		name: `P${overrides.number}`,
		kind: "uninhabited",
		owner: null,
		size: 1,
		resources: 1,
		industryStockpile: 0,
		materialsStockpile: 0,
		industry: 0,
		population: 0,
		colonists: 0,
		production: null,
		freeIndustry: 0,
		...overrides,
	};
}

function localGroup(overrides: Partial<ReportLocalShipGroup> & Pick<ReportLocalShipGroup, "id" | "destination">): ReportLocalShipGroup {
	return {
		count: 1,
		class: "Cruiser",
		tech: { drive: 1, weapons: 0, shields: 0, cargo: 0 },
		cargo: "NONE",
		load: 0,
		origin: null,
		range: null,
		speed: 0,
		mass: 1,
		state: "In_Orbit",
		fleet: null,
		...overrides,
	};
}

function makeReport(
	overrides: Partial<GameReport> & Pick<GameReport, "planets" | "localShipGroups">,
): GameReport {
	return {
		turn: 1,
		mapWidth: 200,
		mapHeight: 200,
		planetCount: overrides.planets.length,
		race: "Earthlings",
		localShipClass: [],
		localScience: [],
		routes: [],
		localPlayerDrive: 0,
		localPlayerWeapons: 0,
		localPlayerShields: 0,
		localPlayerCargo: 0,
		otherShipGroups: [],
		incomingShipGroups: [],
		unidentifiedShipGroups: [],
		localFleets: [],
		otherRaces: [],
		races: [],
		myVotes: 0,
		myVoteFor: "",
		players: [],
		otherScience: [],
		otherShipClass: [],
		battles: [],
		battleIds: [],
		bombings: [],
		shipProductions: [],
		...overrides,
	};
}

const SOURCE_PLANET = planet({ number: 1, x: 100, y: 100, kind: "local" });
const DEST_PLANET = planet({ number: 2, x: 110, y: 100, kind: "uninhabited" });
const GROUP_ID = "11111111-1111-1111-1111-111111111111";

describe("buildPendingSendLines", () => {
	test("emits a dashed line from the orbit planet to the destination", () => {
		const report = makeReport({
			planets: [SOURCE_PLANET, DEST_PLANET],
			localShipGroups: [localGroup({ id: GROUP_ID, destination: 1 })],
		});
		const cmd: OrderCommand = {
			kind: "sendShipGroup",
			id: "cmd-1",
			groupId: GROUP_ID,
			destinationPlanetNumber: 2,
		};
		const lines = buildPendingSendLines(report, [cmd], { "cmd-1": "valid" });
		expect(lines).toHaveLength(1);
		const line = lines[0]!;
		expect(line.kind).toBe("line");
		expect(line.x1).toBe(100);
		expect(line.y1).toBe(100);
		expect(line.x2).toBe(110);
		expect(line.y2).toBe(100);
		expect(line.style.strokeDashPx).toBeGreaterThan(0);
		expect(line.style.strokeColor).toBe(0x66bb6a);
	});

	test("uses the torus-shortest path across the seam", () => {
		const report = makeReport({
			mapWidth: 100,
			mapHeight: 100,
			planets: [
				planet({ number: 1, x: 95, y: 50, kind: "local" }),
				planet({ number: 2, x: 5, y: 50 }),
			],
			localShipGroups: [localGroup({ id: GROUP_ID, destination: 1 })],
		});
		const cmd: OrderCommand = {
			kind: "sendShipGroup",
			id: "cmd-1",
			groupId: GROUP_ID,
			destinationPlanetNumber: 2,
		};
		const lines = buildPendingSendLines(report, [cmd], { "cmd-1": "valid" });
		expect(lines).toHaveLength(1);
		expect(lines[0]!.x1).toBe(95);
		expect(lines[0]!.x2).toBe(105); // 95 + (+10) wrap delta
	});

	test("ignores commands targeting groups missing from the report", () => {
		const report = makeReport({
			planets: [SOURCE_PLANET, DEST_PLANET],
			localShipGroups: [],
		});
		const cmd: OrderCommand = {
			kind: "sendShipGroup",
			id: "cmd-1",
			groupId: GROUP_ID,
			destinationPlanetNumber: 2,
		};
		expect(buildPendingSendLines(report, [cmd], { "cmd-1": "valid" })).toEqual(
			[],
		);
	});

	test("ignores commands when the source group is in hyperspace", () => {
		const report = makeReport({
			planets: [SOURCE_PLANET, DEST_PLANET],
			localShipGroups: [
				localGroup({
					id: GROUP_ID,
					destination: 1,
					origin: 2,
					range: 5,
					state: "In_Space",
				}),
			],
		});
		const cmd: OrderCommand = {
			kind: "sendShipGroup",
			id: "cmd-1",
			groupId: GROUP_ID,
			destinationPlanetNumber: 2,
		};
		expect(buildPendingSendLines(report, [cmd], { "cmd-1": "valid" })).toEqual(
			[],
		);
	});

	test("skips rejected and invalid commands", () => {
		const report = makeReport({
			planets: [SOURCE_PLANET, DEST_PLANET],
			localShipGroups: [localGroup({ id: GROUP_ID, destination: 1 })],
		});
		const cmd: OrderCommand = {
			kind: "sendShipGroup",
			id: "cmd-1",
			groupId: GROUP_ID,
			destinationPlanetNumber: 2,
		};
		expect(
			buildPendingSendLines(report, [cmd], { "cmd-1": "rejected" }),
		).toEqual([]);
		expect(
			buildPendingSendLines(report, [cmd], { "cmd-1": "invalid" }),
		).toEqual([]);
	});

	test("ignores non-sendShipGroup commands", () => {
		const report = makeReport({
			planets: [SOURCE_PLANET, DEST_PLANET],
			localShipGroups: [localGroup({ id: GROUP_ID, destination: 1 })],
		});
		const cmd: OrderCommand = {
			kind: "dismantleShipGroup",
			id: "cmd-1",
			groupId: GROUP_ID,
		};
		expect(buildPendingSendLines(report, [cmd], { "cmd-1": "valid" })).toEqual(
			[],
		);
	});
});
