<!--
Phase 23 Report View table of contents.

Responsibilities:
- "Back to map" button at the top — visible on both desktop sidebar
  and mobile sticky toolbar. Navigates via `$app/navigation.goto` so
  active-view-host scroll restoration plays through SvelteKit's
  history machinery and the layout's `mobileTool` resets naturally.
- Desktop / tablet sidebar: a vertical list of anchor links, one per
  section. The active link gets `aria-current="location"` and a
  `.active` style. Click scrolls the active-view-host (not the
  window) by calling `scrollIntoView` on the matching section.
- Mobile (`max-width: 767.98px`): the sidebar collapses to a sticky
  `<select>` at the top of the body — a minimal contract that does
  not stack with the layout's bottom-tab bar. The same option list
  drives both surfaces.

The active section is computed by the orchestrator
(`report.svelte`) via `IntersectionObserver` and passed in via the
`activeSlug` prop. The TOC itself owns no observers.
-->
<script lang="ts">
	import { goto } from "$app/navigation";

	import { i18n, type TranslationKey } from "$lib/i18n/index.svelte";

	export interface TocEntry {
		slug: string;
		titleKey: TranslationKey;
	}

	type Props = {
		entries: readonly TocEntry[];
		activeSlug: string;
		gameId: string;
	};

	let { entries, activeSlug, gameId }: Props = $props();

	function scrollToSlug(slug: string): void {
		const target = document.getElementById(`report-${slug}`);
		if (target === null) return;
		const reduced = window.matchMedia(
			"(prefers-reduced-motion: reduce)",
		).matches;
		target.scrollIntoView({
			behavior: reduced ? "auto" : "smooth",
			block: "start",
		});
	}

	function onAnchorClick(event: MouseEvent, slug: string): void {
		event.preventDefault();
		scrollToSlug(slug);
	}

	function onSelectChange(event: Event): void {
		const select = event.currentTarget as HTMLSelectElement;
		const slug = select.value;
		if (slug === "") return;
		scrollToSlug(slug);
	}

	async function backToMap(): Promise<void> {
		await goto(`/games/${gameId}/map`);
	}
</script>

<aside
	class="report-toc"
	data-testid="report-toc"
	aria-label={i18n.t("game.report.toc.title")}
>
	<button
		type="button"
		class="back-to-map"
		data-testid="report-back-to-map"
		onclick={() => void backToMap()}
	>
		← {i18n.t("game.report.back_to_map")}
	</button>

	<nav class="desktop" aria-label={i18n.t("game.report.toc.title")}>
		<ul>
			{#each entries as entry (entry.slug)}
				<li>
					<a
						href={`#report-${entry.slug}`}
						class:active={activeSlug === entry.slug}
						aria-current={activeSlug === entry.slug
							? "location"
							: undefined}
						data-testid="report-toc-{entry.slug}"
						onclick={(e) => onAnchorClick(e, entry.slug)}
					>
						{i18n.t(entry.titleKey)}
					</a>
				</li>
			{/each}
		</ul>
	</nav>

	<label class="mobile">
		<span class="visually-hidden">
			{i18n.t("game.report.toc.mobile_label")}
		</span>
		<select
			data-testid="report-toc-mobile"
			value={activeSlug}
			onchange={onSelectChange}
		>
			{#each entries as entry (entry.slug)}
				<option value={entry.slug}>{i18n.t(entry.titleKey)}</option>
			{/each}
		</select>
	</label>
</aside>

<style>
	.report-toc {
		display: flex;
		flex-direction: column;
		gap: 0.75rem;
		font-family: system-ui, sans-serif;
	}
	.back-to-map {
		font: inherit;
		font-size: 0.85rem;
		text-align: left;
		padding: 0.4rem 0.6rem;
		background: #11172a;
		color: #cfd7ff;
		border: 1px solid #2a3150;
		border-radius: 3px;
		cursor: pointer;
	}
	.back-to-map:hover {
		background: #1a2240;
		color: #e8eaf6;
	}
	.desktop {
		display: block;
	}
	.desktop ul {
		list-style: none;
		padding: 0;
		margin: 0;
		display: flex;
		flex-direction: column;
		gap: 0.15rem;
	}
	.desktop a {
		display: block;
		padding: 0.3rem 0.6rem;
		color: #aab;
		text-decoration: none;
		font-size: 0.85rem;
		line-height: 1.3;
		border-left: 2px solid transparent;
		border-radius: 0 3px 3px 0;
	}
	.desktop a:hover {
		color: #e8eaf6;
		background: #11172a;
	}
	.desktop a.active {
		color: #e8eaf6;
		background: #11172a;
		border-left-color: #4a6cf7;
	}
	.mobile {
		display: none;
	}
	.mobile select {
		width: 100%;
		font: inherit;
		padding: 0.4rem 0.5rem;
		background: #0a0e1a;
		color: #e8eaf6;
		border: 1px solid #2a3150;
		border-radius: 3px;
	}
	.visually-hidden {
		position: absolute;
		width: 1px;
		height: 1px;
		padding: 0;
		margin: -1px;
		overflow: hidden;
		clip: rect(0, 0, 0, 0);
		white-space: nowrap;
		border: 0;
	}
	@media (max-width: 767.98px) {
		.desktop {
			display: none;
		}
		.mobile {
			display: block;
		}
	}
</style>
