<!--
"Ship groups stationed here" subsection of the planet inspector.
The map deliberately hides on-planet groups (rendering them as
offset points crowds the canvas), so this list is the player's
view of which fleets sit in this orbit. Race attribution is
best-effort:
  - LocalGroup → the player's own race (`localRace` prop).
  - OtherGroup on an `other`-kind planet → the planet's owner.
  - OtherGroup elsewhere → "foreign" placeholder; the engine's
    typed contract does not carry per-group ownership outside
    battle rosters.

Phase 20 made own-ship rows interactive: clicking a row pivots
the inspector to the corresponding ship-group inspector through
the shared `SelectionStore`. The actions panel mounts on top of
the existing ship-group inspector, so the row is the on-planet
entry point for Send / Load / Modernize / etc. Foreign rows stay
non-interactive — there are no actions to drive against another
race's fleet.

F8-05 (issue #48 п.32) moved the race column into a dropdown
above the table: the previous "race | class | count | mass"
layout overflowed horizontally on narrow viewports. The dropdown
seeds with the player's own race when local groups are stationed
here, otherwise with the first race alphabetically; both cases
are after sorting `availableRaces` alphabetically so the picker
is stable across re-mounts. When a single race is in orbit the
dropdown is hidden — there is nothing to choose — and the table
renders straight through. The race column is dropped in both
modes because the dropdown already names the active race.
-->
<script lang="ts">
	import { getContext } from "svelte";

	import type {
		ReportLocalShipGroup,
		ReportOtherShipGroup,
		ReportPlanet,
	} from "../../../api/game-state";
	import { i18n } from "$lib/i18n/index.svelte";
	import {
		SELECTION_CONTEXT_KEY,
		type SelectionStore,
	} from "$lib/selection.svelte";
	import { formatFloat } from "$lib/util/number-format";

	type Props = {
		planet: ReportPlanet;
		localShipGroups: ReportLocalShipGroup[];
		otherShipGroups: ReportOtherShipGroup[];
		localRace: string;
	};
	let { planet, localShipGroups, otherShipGroups, localRace }: Props = $props();

	const selection = getContext<SelectionStore | undefined>(
		SELECTION_CONTEXT_KEY,
	);

	interface StationedRow {
		key: string;
		race: string;
		class: string;
		count: number;
		mass: number;
		selectable: boolean;
		groupId: string | null;
	}

	// F8-05 owner-feedback: the row carries the authoritative `race`
	// field projected by the engine (and by the legacy parser via the
	// `<Race> Groups` header), so every stationed group surfaces its
	// real owner. The planet-owner / "foreign" fallback is gone — when
	// the wire carries no race the row falls back to the i18n
	// `race.unknown` placeholder, matching how the local-race column
	// degrades if `localRace` is missing.
	const unknownRace = $derived(
		i18n.t("game.inspector.planet.ship_groups.race.unknown"),
	);

	const stationedRows: StationedRow[] = $derived.by(() => {
		const rows: StationedRow[] = [];
		for (const g of localShipGroups) {
			if (g.destination !== planet.number) continue;
			if (g.origin !== null || g.range !== null) continue;
			rows.push({
				key: `local:${g.id}`,
				race: g.race || localRace || unknownRace,
				class: g.class,
				count: g.count,
				mass: g.mass,
				selectable: true,
				groupId: g.id,
			});
		}
		for (let i = 0; i < otherShipGroups.length; i++) {
			const g = otherShipGroups[i]!;
			if (g.destination !== planet.number) continue;
			if (g.origin !== null || g.range !== null) continue;
			rows.push({
				key: `other:${i}`,
				race: g.race || unknownRace,
				class: g.class,
				count: g.count,
				mass: g.mass,
				selectable: false,
				groupId: null,
			});
		}
		return rows;
	});

	const ownStationedHere = $derived(
		stationedRows.some((r) => r.selectable),
	);

	const availableRaces = $derived.by(() => {
		const set = new Set<string>();
		for (const row of stationedRows) set.add(row.race);
		return Array.from(set).sort((a, b) => a.localeCompare(b));
	});

	const ownRaceLabel = $derived(
		localRace || i18n.t("game.inspector.planet.ship_groups.race.unknown"),
	);

	function defaultRace(races: ReadonlyArray<string>): string {
		if (races.length === 0) return "";
		if (ownStationedHere && races.includes(ownRaceLabel)) return ownRaceLabel;
		return races[0]!;
	}

	let selectedRace = $state<string>("");

	$effect(() => {
		// Re-seed whenever the inspector switches planets or the
		// stationed roster changes (new arrivals after a turn).
		// Preserve the player's pick if it is still represented;
		// otherwise fall back to the documented default.
		void planet.number;
		const races = availableRaces;
		if (races.length === 0) {
			selectedRace = "";
			return;
		}
		if (selectedRace === "" || !races.includes(selectedRace)) {
			selectedRace = defaultRace(races);
		}
	});

	const showFilter = $derived(availableRaces.length > 1);
	const filteredRows = $derived(
		showFilter
			? stationedRows.filter((r) => r.race === selectedRace)
			: stationedRows,
	);

	function pickRace(event: Event): void {
		selectedRace = (event.target as HTMLSelectElement).value;
	}

	function selectLocalGroup(groupId: string): void {
		if (selection === undefined) return;
		selection.selectShipGroup({ variant: "local", id: groupId });
	}
</script>

{#if stationedRows.length > 0}
	<section class="ship-groups" data-testid="inspector-planet-ship-groups">
		<div class="head">
			<h4>{i18n.t("game.inspector.planet.ship_groups.title")}</h4>
			{#if showFilter}
				<select
					class="race-select"
					data-testid="inspector-planet-ship-groups-race-filter"
					aria-label={i18n.t(
						"game.inspector.planet.ship_groups.race_filter.aria",
					)}
					value={selectedRace}
					onchange={pickRace}
				>
					{#each availableRaces as race (race)}
						<option value={race}>{race}</option>
					{/each}
				</select>
			{/if}
		</div>
		<ul class="rows">
			{#each filteredRows as row (row.key)}
				<li class="row" data-testid="inspector-planet-ship-groups-row">
					{#if row.selectable && row.groupId !== null}
						{@const groupId = row.groupId}
						<button
							type="button"
							class="cells select"
							data-testid="inspector-planet-ship-groups-select"
							onclick={() => selectLocalGroup(groupId)}
						>
							<span class="class">{row.class}</span>
							<span class="count">{row.count} ×</span>
							<span class="mass">{formatFloat(row.mass)}</span>
						</button>
					{:else}
						<div class="cells">
							<span class="class">{row.class}</span>
							<span class="count">{row.count} ×</span>
							<span class="mass">{formatFloat(row.mass)}</span>
						</div>
					{/if}
				</li>
			{/each}
		</ul>
	</section>
{/if}

<style>
	.ship-groups {
		display: flex;
		flex-direction: column;
		gap: 0.4rem;
	}
	.head {
		display: flex;
		align-items: center;
		gap: 0.5rem;
		flex-wrap: wrap;
	}
	h4 {
		margin: 0;
		font-size: 0.85rem;
		text-transform: uppercase;
		letter-spacing: 0.05em;
		color: var(--color-text-muted);
	}
	.race-select {
		flex: 1 1 auto;
		min-width: 0;
		font: inherit;
		font-size: 0.85rem;
		padding: 0.15rem 0.4rem;
		background: var(--color-surface-raised);
		color: var(--color-text);
		border: 1px solid var(--color-border);
		border-radius: 3px;
		cursor: pointer;
	}
	.rows {
		list-style: none;
		margin: 0;
		padding: 0;
		display: flex;
		flex-direction: column;
		gap: 0.2rem;
	}
	.row {
		display: block;
		font-size: 0.85rem;
	}
	.cells {
		display: grid;
		grid-template-columns: 1fr auto auto;
		gap: 0.5rem;
		align-items: baseline;
	}
	.select {
		width: 100%;
		font: inherit;
		text-align: left;
		background: transparent;
		color: inherit;
		border: 1px solid transparent;
		border-radius: 3px;
		padding: 0.15rem 0.3rem;
		cursor: pointer;
	}
	.select:hover {
		border-color: var(--color-border);
		background: var(--color-surface-hover);
	}
	.class {
		color: var(--color-text-muted);
	}
	.count {
		color: var(--color-text-muted);
		text-align: right;
		font-variant-numeric: tabular-nums;
	}
	.mass {
		color: var(--color-text-muted);
		text-align: right;
		font-family: var(--font-mono);
		font-variant-numeric: tabular-nums;
	}
</style>
