// SelectionStore unit tests. The store is in-memory only and carries
// no async lifecycle, so the cases focus on the rune transitions and
// the post-`dispose` no-op contract.

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

import { SelectionStore } from "../src/lib/selection.svelte";

describe("SelectionStore", () => {
	test("initial state has no selection", () => {
		const store = new SelectionStore();
		expect(store.selected).toBeNull();
	});

	test("selectPlanet records the planet id", () => {
		const store = new SelectionStore();
		store.selectPlanet(42);
		expect(store.selected).toEqual({ kind: "planet", id: 42 });
	});

	test("selectPlanet replaces the previous selection", () => {
		const store = new SelectionStore();
		store.selectPlanet(1);
		store.selectPlanet(2);
		expect(store.selected).toEqual({ kind: "planet", id: 2 });
	});

	test("clear resets the selection to null", () => {
		const store = new SelectionStore();
		store.selectPlanet(7);
		store.clear();
		expect(store.selected).toBeNull();
	});

	test("dispose blocks subsequent mutations", () => {
		const store = new SelectionStore();
		store.selectPlanet(3);
		store.dispose();
		expect(store.selected).toBeNull();

		store.selectPlanet(4);
		expect(store.selected).toBeNull();

		store.clear();
		expect(store.selected).toBeNull();
	});

	test("focus sets the selection and queues the pending focus", () => {
		const store = new SelectionStore();
		store.focus({ kind: "planet", id: 11 });
		expect(store.selected).toEqual({ kind: "planet", id: 11 });
		expect(store.consumePendingFocus()).toEqual({ kind: "planet", id: 11 });
	});

	test("focus also works for a ship group target", () => {
		const store = new SelectionStore();
		store.focus({ kind: "shipGroup", ref: { variant: "local", id: "abc" } });
		expect(store.selected).toEqual({
			kind: "shipGroup",
			ref: { variant: "local", id: "abc" },
		});
		expect(store.consumePendingFocus()).toEqual({
			kind: "shipGroup",
			ref: { variant: "local", id: "abc" },
		});
	});

	test("consumePendingFocus clears the queued request", () => {
		const store = new SelectionStore();
		store.focus({ kind: "planet", id: 1 });
		expect(store.consumePendingFocus()).not.toBeNull();
		expect(store.consumePendingFocus()).toBeNull();
	});

	test("consumePendingFocus returns null when no focus was queued", () => {
		const store = new SelectionStore();
		store.selectPlanet(5);
		expect(store.consumePendingFocus()).toBeNull();
	});

	test("clear leaves any queued pending focus untouched", () => {
		const store = new SelectionStore();
		store.focus({ kind: "planet", id: 9 });
		store.clear();
		expect(store.selected).toBeNull();
		expect(store.consumePendingFocus()).toEqual({ kind: "planet", id: 9 });
	});

	test("dispose drops a queued pending focus", () => {
		const store = new SelectionStore();
		store.focus({ kind: "planet", id: 2 });
		store.dispose();
		expect(store.consumePendingFocus()).toBeNull();
	});

	test("focus is a no-op after dispose", () => {
		const store = new SelectionStore();
		store.dispose();
		store.focus({ kind: "planet", id: 7 });
		expect(store.selected).toBeNull();
		expect(store.consumePendingFocus()).toBeNull();
	});

	test("focusPoint queues a coord without touching selection", () => {
		const store = new SelectionStore();
		store.selectPlanet(1);
		store.focusPoint(12, 34);
		expect(store.selected).toEqual({ kind: "planet", id: 1 });
		expect(store.consumePendingCenter()).toEqual({ x: 12, y: 34 });
	});

	test("consumePendingCenter clears the queued point", () => {
		const store = new SelectionStore();
		store.focusPoint(5, 7);
		expect(store.consumePendingCenter()).toEqual({ x: 5, y: 7 });
		expect(store.consumePendingCenter()).toBeNull();
	});

	test("dispose drops a queued pending centre", () => {
		const store = new SelectionStore();
		store.focusPoint(1, 2);
		store.dispose();
		expect(store.consumePendingCenter()).toBeNull();
	});

	test("focusPoint is a no-op after dispose", () => {
		const store = new SelectionStore();
		store.dispose();
		store.focusPoint(1, 2);
		expect(store.consumePendingCenter()).toBeNull();
	});
});
