// Vitest coverage for the Phase 20 ship-group command shapes —
// `validateCommand` for each of the eight new variants. The
// validator is invoked through the public `OrderDraftStore.add`
// path so a regression in either layer surfaces here.

import "fake-indexeddb/auto";
import { afterEach, beforeEach, describe, expect, test } from "vitest";

import { OrderDraftStore } from "../src/sync/order-draft.svelte";
import type { OrderCommand } from "../src/sync/order-types";
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";
const GROUP_ID = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa";
const NEW_GROUP_ID = "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb";

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

beforeEach(async () => {
	dbName = `galaxy-validate-ship-group-${crypto.randomUUID()}`;
	db = await openGalaxyDB(dbName);
	cache = new IDBCache(db);
	draft = new OrderDraftStore();
	await draft.init({ cache, gameId: GAME_ID });
});

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();
	});
});

async function statusOf(cmd: OrderCommand): Promise<string> {
	await draft.add(cmd);
	return draft.statuses[cmd.id]!;
}

describe("validateCommand — ship-group variants", () => {
	test("breakShipGroup with positive quantity is valid", async () => {
		expect(
			await statusOf({
				kind: "breakShipGroup",
				id: crypto.randomUUID(),
				groupId: GROUP_ID,
				newGroupId: NEW_GROUP_ID,
				quantity: 2,
			}),
		).toBe("valid");
	});

	test("breakShipGroup with quantity 0 is invalid", async () => {
		expect(
			await statusOf({
				kind: "breakShipGroup",
				id: crypto.randomUUID(),
				groupId: GROUP_ID,
				newGroupId: NEW_GROUP_ID,
				quantity: 0,
			}),
		).toBe("invalid");
	});

	test("breakShipGroup with same source and new id is invalid", async () => {
		expect(
			await statusOf({
				kind: "breakShipGroup",
				id: crypto.randomUUID(),
				groupId: GROUP_ID,
				newGroupId: GROUP_ID,
				quantity: 1,
			}),
		).toBe("invalid");
	});

	test("sendShipGroup with positive destination is valid", async () => {
		expect(
			await statusOf({
				kind: "sendShipGroup",
				id: crypto.randomUUID(),
				groupId: GROUP_ID,
				destinationPlanetNumber: 7,
			}),
		).toBe("valid");
	});

	test("sendShipGroup to planet 0 is invalid", async () => {
		expect(
			await statusOf({
				kind: "sendShipGroup",
				id: crypto.randomUUID(),
				groupId: GROUP_ID,
				destinationPlanetNumber: 0,
			}),
		).toBe("invalid");
	});

	test("loadShipGroup with valid cargo and quantity is valid", async () => {
		expect(
			await statusOf({
				kind: "loadShipGroup",
				id: crypto.randomUUID(),
				groupId: GROUP_ID,
				cargo: "COL",
				quantity: 1.5,
			}),
		).toBe("valid");
	});

	test("loadShipGroup with zero quantity is invalid", async () => {
		expect(
			await statusOf({
				kind: "loadShipGroup",
				id: crypto.randomUUID(),
				groupId: GROUP_ID,
				cargo: "COL",
				quantity: 0,
			}),
		).toBe("invalid");
	});

	test("unloadShipGroup with positive quantity is valid", async () => {
		expect(
			await statusOf({
				kind: "unloadShipGroup",
				id: crypto.randomUUID(),
				groupId: GROUP_ID,
				quantity: 0.5,
			}),
		).toBe("valid");
	});

	test("upgradeShipGroup ALL with level 0 is valid", async () => {
		expect(
			await statusOf({
				kind: "upgradeShipGroup",
				id: crypto.randomUUID(),
				groupId: GROUP_ID,
				tech: "ALL",
				level: 0,
			}),
		).toBe("valid");
	});

	test("upgradeShipGroup ALL with non-zero level is invalid", async () => {
		expect(
			await statusOf({
				kind: "upgradeShipGroup",
				id: crypto.randomUUID(),
				groupId: GROUP_ID,
				tech: "ALL",
				level: 2,
			}),
		).toBe("invalid");
	});

	test("upgradeShipGroup DRIVE with positive level is valid", async () => {
		expect(
			await statusOf({
				kind: "upgradeShipGroup",
				id: crypto.randomUUID(),
				groupId: GROUP_ID,
				tech: "DRIVE",
				level: 1.5,
			}),
		).toBe("valid");
	});

	test("upgradeShipGroup DRIVE with level 0 is invalid", async () => {
		expect(
			await statusOf({
				kind: "upgradeShipGroup",
				id: crypto.randomUUID(),
				groupId: GROUP_ID,
				tech: "DRIVE",
				level: 0,
			}),
		).toBe("invalid");
	});

	test("dismantleShipGroup with valid uuid is valid", async () => {
		expect(
			await statusOf({
				kind: "dismantleShipGroup",
				id: crypto.randomUUID(),
				groupId: GROUP_ID,
			}),
		).toBe("valid");
	});

	test("transferShipGroup with valid acceptor name is valid", async () => {
		expect(
			await statusOf({
				kind: "transferShipGroup",
				id: crypto.randomUUID(),
				groupId: GROUP_ID,
				acceptor: "Aliens",
			}),
		).toBe("valid");
	});

	test("transferShipGroup with empty acceptor is invalid", async () => {
		expect(
			await statusOf({
				kind: "transferShipGroup",
				id: crypto.randomUUID(),
				groupId: GROUP_ID,
				acceptor: "",
			}),
		).toBe("invalid");
	});

	test("joinFleetShipGroup with valid name is valid", async () => {
		expect(
			await statusOf({
				kind: "joinFleetShipGroup",
				id: crypto.randomUUID(),
				groupId: GROUP_ID,
				name: "Vanguard",
			}),
		).toBe("valid");
	});

	test("joinFleetShipGroup with empty name is invalid", async () => {
		expect(
			await statusOf({
				kind: "joinFleetShipGroup",
				id: crypto.randomUUID(),
				groupId: GROUP_ID,
				name: "",
			}),
		).toBe("invalid");
	});
});
