<script lang="ts">
	import "$lib/theme/tokens.css";
	import "$lib/theme/base.css";
	import { onMount } from "svelte";
	import { goto } from "$app/navigation";
	import { page } from "$app/state";
	import { dev } from "$app/environment";
	import { appBase, withBase } from "$lib/paths";
	import { i18n } from "$lib/i18n/index.svelte";
	import { session } from "$lib/session-store.svelte";
	import { eventStream } from "../api/events.svelte";
	import { loadCore } from "../platform/core/index";
	import { GATEWAY_RESPONSE_PUBLIC_KEY } from "$lib/env";
	import ToastHost from "$lib/toast-host.svelte";

	let { children } = $props();

	// `streamSessionId` records the device session id the event stream
	// is currently bound to. The `$effect` below uses it to detect a
	// re-login (different session id while still authenticated) and
	// restart the stream against the fresh credentials.
	let streamSessionId: string | null = null;

	onMount(() => {
		void session.init();
		// Production-only service-worker registration (auto-register is off
		// in svelte.config.js) so `vite dev` and the dev-server e2e suite
		// run without the worker intercepting requests.
		if (!dev && "serviceWorker" in navigator) {
			void navigator.serviceWorker.register(withBase("/service-worker.js"), {
				scope: withBase("/"),
			});
		}
		return () => {
			eventStream.stop();
			streamSessionId = null;
		};
	});

	$effect(() => {
		if (
			session.status === "authenticated" &&
			session.keypair !== null &&
			session.deviceSessionId !== null &&
			GATEWAY_RESPONSE_PUBLIC_KEY.length > 0
		) {
			const keypair = session.keypair;
			const deviceSessionId = session.deviceSessionId;
			if (streamSessionId !== deviceSessionId) {
				if (streamSessionId !== null) {
					eventStream.stop();
				}
				streamSessionId = deviceSessionId;
				void (async (): Promise<void> => {
					try {
						const core = await loadCore();
						// Bail out if the session flipped away from this id
						// while we were loading core (logout, re-login).
						if (
							session.deviceSessionId !== deviceSessionId ||
							session.status !== "authenticated"
						) {
							return;
						}
						eventStream.start({
							core,
							keypair,
							deviceSessionId,
							gatewayResponsePublicKey: GATEWAY_RESPONSE_PUBLIC_KEY,
						});
					} catch (err) {
						console.info("layout: failed to start event stream", err);
					}
				})();
			}
		} else if (streamSessionId !== null) {
			eventStream.stop();
			streamSessionId = null;
		}

		// page.url.pathname includes the configured base path; strip it so
		// the route comparisons below stay base-agnostic.
		const pathname = page.url.pathname.slice(appBase.length);
		// Debug-only routes under /__debug/* run their own bootstrap
		// path against the storage primitives and must bypass the
		// auth guard so Phase 6's Playwright spec can drive the
		// keystore directly.
		if (pathname.startsWith("/__debug/")) {
			return;
		}
		if (session.status === "anonymous" && pathname !== "/login") {
			void goto(withBase("/login"), { replaceState: true });
		} else if (
			session.status === "authenticated" &&
			(pathname === "/login" || pathname === "/")
		) {
			void goto(withBase("/lobby"), { replaceState: true });
		}
	});
</script>

{#if session.status === "loading"}
	<main class="status">
		<p>{i18n.t("common.loading")}</p>
	</main>
{:else if session.status === "unsupported"}
	<main class="status">
		<h1>{i18n.t("common.browser_not_supported_title")}</h1>
		<p>{i18n.t("common.browser_not_supported_body")}</p>
	</main>
{:else}
	{@render children()}
{/if}

<ToastHost />

<style>
	.status {
		padding: var(--space-6);
		font-family: var(--font-sans);
	}
</style>
