// Vitest component coverage for the Phase 15 production-controls
// subsection of the planet inspector. Drives the component against a
// real `OrderDraftStore` (with `fake-indexeddb` standing in for the
// browser's IDB factory) so the collapse-by-`planetNumber` rule and
// the per-row status side-effects are exercised end-to-end.
//
// The active-segment derivation is covered by direct render-and-
// query assertions: the parser is small enough that a table-driven
// pass over the canonical engine display strings catches every
// branch.

import "@testing-library/jest-dom/vitest";
import "fake-indexeddb/auto";
import { fireEvent, render, waitFor } from "@testing-library/svelte";
import { afterEach, beforeEach, describe, expect, test } from "vitest";

import { i18n } from "../src/lib/i18n/index.svelte";
import type {
	ReportPlanet,
	ScienceSummary,
	ShipClassSummary,
} from "../src/api/game-state";
import Production from "../src/lib/inspectors/planet/production.svelte";
import {
	ORDER_DRAFT_CONTEXT_KEY,
	OrderDraftStore,
} from "../src/sync/order-draft.svelte";
import { IDBCache } from "../src/platform/store/idb-cache";
import { openGalaxyDB, type GalaxyDB } from "../src/platform/store/idb";
import type { Cache } from "../src/platform/store/index";
import type { IDBPDatabase } from "idb";

const GAME_ID = "11111111-2222-3333-4444-555555555555";

let db: IDBPDatabase<GalaxyDB>;
let dbName: string;
let cache: Cache;
let draft: OrderDraftStore;

beforeEach(async () => {
	dbName = `galaxy-production-${crypto.randomUUID()}`;
	db = await openGalaxyDB(dbName);
	cache = new IDBCache(db);
	draft = new OrderDraftStore();
	await draft.init({ cache, gameId: GAME_ID });
	i18n.resetForTests("en");
});

afterEach(async () => {
	draft.dispose();
	db.close();
	await new Promise<void>((resolve) => {
		const req = indexedDB.deleteDatabase(dbName);
		req.onsuccess = () => resolve();
		req.onerror = () => resolve();
		req.onblocked = () => resolve();
	});
});

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

function shipClass(
	overrides: Partial<ShipClassSummary> & Pick<ShipClassSummary, "name">,
): ShipClassSummary {
	return {
		drive: 0,
		armament: 0,
		weapons: 0,
		shields: 0,
		cargo: 0,
		...overrides,
	};
}

function mountProduction(
	planet: ReportPlanet,
	localShipClass: ShipClassSummary[] = [],
	localScience: ScienceSummary[] = [],
) {
	const context = new Map<unknown, unknown>([
		[ORDER_DRAFT_CONTEXT_KEY, draft],
	]);
	return render(Production, {
		props: { planet, localShipClass, localScience },
		context,
	});
}

describe("planet inspector — production controls", () => {
	test("renders the four main segments with localised labels", () => {
		const ui = mountProduction(localPlanet({ number: 1 }));
		expect(
			ui.getByTestId("inspector-planet-production-segment-industry"),
		).toHaveTextContent("industry");
		expect(
			ui.getByTestId("inspector-planet-production-segment-materials"),
		).toHaveTextContent("materials");
		expect(
			ui.getByTestId("inspector-planet-production-segment-research"),
		).toHaveTextContent("research");
		expect(
			ui.getByTestId("inspector-planet-production-segment-ship"),
		).toHaveTextContent("build ship");
	});

	test("Industry click emits a CAP setProductionType command", async () => {
		const ui = mountProduction(localPlanet({ number: 7 }));
		await fireEvent.click(
			ui.getByTestId("inspector-planet-production-segment-industry"),
		);
		await waitFor(() => expect(draft.commands).toHaveLength(1));
		const cmd = draft.commands[0]!;
		expect(cmd.kind).toBe("setProductionType");
		if (cmd.kind !== "setProductionType") return;
		expect(cmd.planetNumber).toBe(7);
		expect(cmd.productionType).toBe("CAP");
		expect(cmd.subject).toBe("");
	});

	test("Materials click emits a MAT setProductionType command", async () => {
		const ui = mountProduction(localPlanet({ number: 7 }));
		await fireEvent.click(
			ui.getByTestId("inspector-planet-production-segment-materials"),
		);
		await waitFor(() => expect(draft.commands).toHaveLength(1));
		const cmd = draft.commands[0]!;
		if (cmd.kind !== "setProductionType") throw new Error("wrong kind");
		expect(cmd.productionType).toBe("MAT");
	});

	test("Research click reveals the four tech sub-buttons without emitting", async () => {
		const ui = mountProduction(localPlanet({ number: 7 }));
		expect(
			ui.queryByTestId("inspector-planet-production-research-row"),
		).toBeNull();
		await fireEvent.click(
			ui.getByTestId("inspector-planet-production-segment-research"),
		);
		expect(
			ui.getByTestId("inspector-planet-production-research-row"),
		).toBeInTheDocument();
		expect(draft.commands).toHaveLength(0);
		await fireEvent.click(
			ui.getByTestId("inspector-planet-production-research-drive"),
		);
		await waitFor(() => expect(draft.commands).toHaveLength(1));
		const cmd = draft.commands[0]!;
		if (cmd.kind !== "setProductionType") throw new Error("wrong kind");
		expect(cmd.productionType).toBe("DRIVE");
		expect(cmd.subject).toBe("");
	});

	test("Build-Ship segment shows the empty placeholder when no classes designed", async () => {
		const ui = mountProduction(localPlanet({ number: 7 }), []);
		await fireEvent.click(
			ui.getByTestId("inspector-planet-production-segment-ship"),
		);
		expect(
			ui.getByTestId("inspector-planet-production-ship-empty"),
		).toBeInTheDocument();
	});

	test("Build-Ship click on a class emits a SHIP setProductionType command", async () => {
		const ui = mountProduction(localPlanet({ number: 7 }), [
			shipClass({ name: "Scout" }),
			shipClass({ name: "Destroyer" }),
		]);
		await fireEvent.click(
			ui.getByTestId("inspector-planet-production-segment-ship"),
		);
		await fireEvent.click(
			ui.getByTestId("inspector-planet-production-ship-Scout"),
		);
		await waitFor(() => expect(draft.commands).toHaveLength(1));
		const cmd = draft.commands[0]!;
		if (cmd.kind !== "setProductionType") throw new Error("wrong kind");
		expect(cmd.productionType).toBe("SHIP");
		expect(cmd.subject).toBe("Scout");
	});

	test("re-clicks on the same planet collapse to the latest entry via the store", async () => {
		const ui = mountProduction(localPlanet({ number: 7 }), [
			shipClass({ name: "Scout" }),
		]);
		await fireEvent.click(
			ui.getByTestId("inspector-planet-production-segment-industry"),
		);
		await fireEvent.click(
			ui.getByTestId("inspector-planet-production-segment-materials"),
		);
		await fireEvent.click(
			ui.getByTestId("inspector-planet-production-segment-research"),
		);
		await fireEvent.click(
			ui.getByTestId("inspector-planet-production-research-cargo"),
		);
		await waitFor(() => expect(draft.commands).toHaveLength(1));
		const cmd = draft.commands[0]!;
		if (cmd.kind !== "setProductionType") throw new Error("wrong kind");
		expect(cmd.productionType).toBe("CARGO");
	});

	test("active main segment derives from planet.production display string", () => {
		const cases: ReadonlyArray<{
			production: string | null;
			expected: "industry" | "materials" | "research" | "ship" | "none";
		}> = [
			{ production: "Capital", expected: "industry" },
			{ production: "Material", expected: "materials" },
			{ production: "Drive", expected: "research" },
			{ production: "Weapons", expected: "research" },
			{ production: "Shields", expected: "research" },
			{ production: "Cargo", expected: "research" },
			{ production: "Scout", expected: "ship" },
			{ production: "-", expected: "none" },
			{ production: null, expected: "none" },
			{ production: "UnknownThing", expected: "none" },
		];
		for (const tc of cases) {
			const ui = mountProduction(
				localPlanet({ number: 1, production: tc.production }),
				[shipClass({ name: "Scout" })],
			);
			const ids: ReadonlyArray<
				"industry" | "materials" | "research" | "ship"
			> = ["industry", "materials", "research", "ship"];
			for (const id of ids) {
				const el = ui.getByTestId(
					`inspector-planet-production-segment-${id}`,
				);
				if (tc.expected === id) {
					expect(el.classList.contains("active")).toBe(true);
				} else {
					expect(el.classList.contains("active")).toBe(false);
				}
			}
			ui.unmount();
		}
	});

	test("active research sub-button highlights for known display strings", () => {
		const cases: ReadonlyArray<{
			production: string;
			slug: "drive" | "weapons" | "shields" | "cargo";
		}> = [
			{ production: "Drive", slug: "drive" },
			{ production: "Weapons", slug: "weapons" },
			{ production: "Shields", slug: "shields" },
			{ production: "Cargo", slug: "cargo" },
		];
		for (const tc of cases) {
			const ui = mountProduction(
				localPlanet({ number: 1, production: tc.production }),
			);
			const el = ui.getByTestId(
				`inspector-planet-production-research-${tc.slug}`,
			);
			expect(el.classList.contains("active")).toBe(true);
			ui.unmount();
		}
	});

	test("ship class sub-row matches when production equals a class name", async () => {
		const ui = mountProduction(
			localPlanet({ number: 1, production: "Scout" }),
			[shipClass({ name: "Scout" }), shipClass({ name: "Destroyer" })],
		);
		expect(
			ui.getByTestId("inspector-planet-production-ship-Scout").classList
				.contains("active"),
		).toBe(true);
		expect(
			ui
				.getByTestId("inspector-planet-production-ship-Destroyer")
				.classList.contains("active"),
		).toBe(false);
	});
});
