// Long-lived state for the ship-class calculator. The sidebar unmounts
// the calculator tab when another tab is active, so component-local state
// would be lost on every tab switch (the inspector auto-opens on a planet
// click, for instance). The calculator is a long-lived planning tool, so
// its inputs live here — a page-level singleton that survives tab
// unmount/remount — and the component renders this store rather than its
// own `$state`.
//
// `ensureGame` resets the design when the active game changes so a draft
// from a previous game does not leak across games. `reset` is for tests,
// which share the module instance across cases.

import type { LoadMode, LockableOutputId } from "./calc-model";

interface Blocks {
	drive: number;
	armament: number;
	weapons: number;
	shields: number;
	cargo: number;
}
interface Tech {
	drive: number;
	weapons: number;
	shields: number;
	cargo: number;
}
type Mode = "ship" | "modernization";

function freshBlocks(): Blocks {
	return { drive: 0, armament: 0, weapons: 0, shields: 0, cargo: 0 };
}
function freshTech(): Tech {
	return { drive: 0, weapons: 0, shields: 0, cargo: 0 };
}

class CalculatorState {
	gameId = $state<string | null>(null);
	mode = $state<Mode>("ship");
	name = $state("");
	blocks = $state<Blocks>(freshBlocks());
	techValues = $state<Tech>(freshTech());
	techOverridden = $state<Record<keyof Tech, boolean>>({
		drive: false,
		weapons: false,
		shields: false,
		cargo: false,
	});
	targetTech = $state<Tech>(freshTech());
	targetSeeded = $state(false);
	loadMode = $state<LoadMode>("full");
	customLoad = $state(0);
	lock = $state<LockableOutputId | null>(null);
	lockValue = $state(0);
	matOverridden = $state(false);
	matValue = $state(0);
	loadedExisting = $state<string | null>(null);
	// The last calculatorLoadRequest token this state has applied. Held
	// here (not in the component) so a tab-switch remount does not
	// re-apply the previous load request and clobber the kept design.
	handledLoadToken = $state(0);

	/** Clears the design back to a blank new-class form. */
	resetDesign(): void {
		this.blocks = freshBlocks();
		this.name = "";
		this.loadedExisting = null;
		this.lock = null;
	}

	/** Full reset to defaults; used by tests sharing the singleton. */
	reset(): void {
		this.gameId = null;
		this.mode = "ship";
		this.resetDesign();
		this.techValues = freshTech();
		this.techOverridden = {
			drive: false,
			weapons: false,
			shields: false,
			cargo: false,
		};
		this.targetTech = freshTech();
		this.targetSeeded = false;
		this.loadMode = "full";
		this.customLoad = 0;
		this.lockValue = 0;
		this.matOverridden = false;
		this.matValue = 0;
		this.handledLoadToken = 0;
	}

	/**
	 * Resets the per-game design when the active game changes, so a draft
	 * from one game does not surface in another. A no-op while the game is
	 * unchanged, which is what makes the design survive tab switches.
	 * `handledLoadToken` is intentionally preserved across games.
	 */
	ensureGame(gameId: string): void {
		if (this.gameId === gameId) return;
		this.gameId = gameId;
		this.mode = "ship";
		this.resetDesign();
		this.techValues = freshTech();
		this.techOverridden = {
			drive: false,
			weapons: false,
			shields: false,
			cargo: false,
		};
		this.targetTech = freshTech();
		this.targetSeeded = false;
		this.loadMode = "full";
		this.customLoad = 0;
		this.lockValue = 0;
		this.matOverridden = false;
		this.matValue = 0;
	}
}

export const calculatorState = new CalculatorState();
