// Vitest coverage for the Phase 20 modernize cost preview. The
// preview line in the inspector calls `core.blockUpgradeCost` once
// per ship block and multiplies the per-ship total by the number of
// targeted ships. The preview hides when `Core` is unavailable; when
// `tech === "ALL"` the targets are the player's race tech levels;
// otherwise only the picked block contributes to the cost.

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

import { i18n } from "../src/lib/i18n/index.svelte";
import type {
	ReportLocalShipGroup,
	ReportPlanet,
	ShipClassSummary,
} from "../src/api/game-state";
import ShipGroup, {
	type ShipGroupSelection,
} from "../src/lib/inspectors/ship-group.svelte";
import {
	ORDER_DRAFT_CONTEXT_KEY,
	OrderDraftStore,
} from "../src/sync/order-draft.svelte";
import { CORE_CONTEXT_KEY, CoreHolder } from "../src/lib/core-context.svelte";
import type { Core } from "../src/platform/core/index";
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;

const PLANETS: ReportPlanet[] = [
	{
		number: 17,
		name: "Castle",
		x: 100,
		y: 100,
		kind: "local",
		owner: null,
		size: 1000,
		resources: 5,
		industryStockpile: 0,
		materialsStockpile: 0,
		industry: 1000,
		population: 1000,
		colonists: 0,
		production: "Capital",
		freeIndustry: 1000,
	},
];

const SHIP_CLASS_CRUISER: ShipClassSummary = {
	name: "Cruiser",
	drive: 5,
	armament: 0,
	weapons: 0,
	shields: 5,
	cargo: 5,
};

beforeEach(async () => {
	dbName = `galaxy-ship-group-modernize-${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 group(
	overrides: Partial<ReportLocalShipGroup> = {},
): ReportLocalShipGroup {
	return {
		id: "cccccccc-cccc-cccc-cccc-cccccccccccc",
		count: 4,
		class: "Cruiser",
		tech: { drive: 1, weapons: 0, shields: 1, cargo: 1 },
		cargo: "NONE",
		load: 0,
		destination: 17,
		origin: null,
		range: null,
		speed: 0,
		mass: 25,
		state: "In_Orbit",
		fleet: null,
		...overrides,
	};
}

// stubCore mirrors `pkg/calc/ship.go.BlockUpgradeCost` exactly so the
// preview line shows the same number the WASM bridge would produce.
// The other Core methods are no-ops because the modernize preview
// only consults `weaponsBlockMass` (returns null when armament is
// zero) and `blockUpgradeCost`.
function stubCore(): Core {
	return {
		signRequest: () => new Uint8Array(),
		verifyResponse: () => true,
		verifyEvent: () => true,
		verifyPayloadHash: () => true,
		driveEffective: ({ drive, driveTech }) => drive * driveTech,
		emptyMass: () => 0,
		weaponsBlockMass: ({ weapons, armament }) => {
			if ((armament === 0 && weapons !== 0) || (armament !== 0 && weapons === 0)) {
				return null;
			}
			return (armament + 1) * (weapons / 2);
		},
		fullMass: ({ emptyMass, carryingMass }) => emptyMass + carryingMass,
		speed: () => 0,
		cargoCapacity: () => 0,
		carryingMass: () => 0,
		blockUpgradeCost: ({ blockMass, currentTech, targetTech }) => {
			if (blockMass === 0 || targetTech <= currentTech) return 0;
			return (1 - currentTech / targetTech) * 10 * blockMass;
		},
	};
}

function mount(
	g: ReportLocalShipGroup,
	options: { core?: Core | null } = {},
) {
	const selection: ShipGroupSelection = { variant: "local", group: g };
	const holder = new CoreHolder();
	if (options.core !== undefined) holder.set(options.core);
	const context = new Map<unknown, unknown>([
		[ORDER_DRAFT_CONTEXT_KEY, draft],
		[CORE_CONTEXT_KEY, holder],
	]);
	return render(ShipGroup, {
		props: {
			selection,
			planets: PLANETS,
			localShipClass: [SHIP_CLASS_CRUISER],
			localFleets: [],
			otherRaces: [],
			mapWidth: 1000,
			mapHeight: 1000,
			localPlayerDrive: 2,
			localPlayerWeapons: 2,
			localPlayerShields: 2,
			localPlayerCargo: 2,
		},
		context,
	});
}

describe("ship-group inspector — modernize cost preview", () => {
	test("ALL upgrade preview matches the BlockUpgradeCost formula × ship count", async () => {
		// drive: mass=5 current=1 target=2 → (1 - 0.5) * 10 * 5 = 25
		// shields: mass=5 current=1 target=2 → 25
		// cargo: mass=5 current=1 target=2 → 25
		// weapons: armament=0 weapons=0 → block mass 0 → 0
		// per-ship = 75; group of 4 → 300
		const ui = mount(group(), { core: stubCore() });
		await fireEvent.click(ui.getByTestId("inspector-ship-group-action-modernize"));
		const preview = ui.getByTestId("inspector-ship-group-form-modernize-cost");
		expect(preview).toHaveTextContent("300");
	});

	test("per-block tech with custom level uses only that block", async () => {
		// DRIVE only, target=2: 25 per ship × 4 = 100.
		const ui = mount(group(), { core: stubCore() });
		await fireEvent.click(ui.getByTestId("inspector-ship-group-action-modernize"));
		await fireEvent.change(
			ui.getByTestId("inspector-ship-group-form-modernize-tech"),
			{ target: { value: "DRIVE" } },
		);
		await fireEvent.input(
			ui.getByTestId("inspector-ship-group-form-modernize-level"),
			{ target: { value: "2" } },
		);
		const preview = ui.getByTestId("inspector-ship-group-form-modernize-cost");
		expect(preview).toHaveTextContent("100");
	});

	test("preview is unavailable when Core is not loaded", async () => {
		const ui = mount(group(), { core: null });
		await fireEvent.click(ui.getByTestId("inspector-ship-group-action-modernize"));
		const preview = ui.getByTestId("inspector-ship-group-form-modernize-cost");
		expect(preview).toHaveTextContent(/preview unavailable/i);
	});
});
