<script lang="ts">
	import type { PageProps } from "./$types";
	import { browser } from "$app/environment";
	import { enhance } from "$app/forms";

	import VerseDisplay from "$lib/components/VerseDisplay.svelte";
	import SearchInput from "$lib/components/SearchInput.svelte";
	import GuessesTable from "$lib/components/GuessesTable.svelte";
	import WinScreen from "$lib/components/WinScreen.svelte";
	import Credits from "$lib/components/Credits.svelte";
	import TitleAnimation from "$lib/components/TitleAnimation.svelte";
	import DevButtons from "$lib/components/DevButtons.svelte";
	import AuthModal from "$lib/components/AuthModal.svelte";

	import { evaluateGuess, getGrade } from "$lib/utils/game";
	import {
		generateShareText,
		shareResult,
		copyToClipboard as clipboardCopy,
	} from "$lib/utils/share";
	import {
		submitCompletion,
		fetchExistingStats,
		type StatsData,
	} from "$lib/utils/stats-client";
	import { createGamePersistence } from "$lib/stores/game-persistence.svelte";

	let { data }: PageProps = $props();

	let dailyVerse = $derived(data.dailyVerse);
	let correctBookId = $derived(data.correctBookId);
	let correctBook = $derived(data.correctBook);
	let user = $derived(data.user);
	let session = $derived(data.session);

	let searchQuery = $state("");
	let copied = $state(false);
	let isDev = $state(false);
	let authModalOpen = $state(false);
	let showWinScreen = $state(false);
	let statsData = $state<StatsData | null>(null);

	const persistence = createGamePersistence(
		() => dailyVerse.date,
		() => dailyVerse.reference,
		() => correctBookId,
		() => user?.id,
	);

	let guessedIds = $derived(
		new Set(persistence.guesses.map((g) => g.book.id)),
	);

	const currentDate = $derived(
		new Date().toLocaleDateString("en-US", {
			weekday: "long",
			year: "numeric",
			month: "long",
			day: "numeric",
		}),
	);

	let isWon = $derived(
		persistence.guesses.some((g) => g.book.id === correctBookId),
	);
	let grade = $derived(
		isWon
			? persistence.guesses.length === 1 && persistence.chapterCorrect
				? "S++"
				: getGrade(persistence.guesses.length)
			: "",
	);
	let blurChapter = $derived(
		isWon &&
			persistence.guesses.length === 1 &&
			!persistence.chapterGuessCompleted,
	);

	async function submitGuess(bookId: string) {
		if (persistence.guesses.some((g) => g.book.id === bookId)) return;

		const guess = evaluateGuess(bookId, correctBookId);
		if (!guess) return;

		if (persistence.guesses.length === 0) {
			const key = `bibdle-first-guess-${dailyVerse.date}`;
			if (
				browser &&
				localStorage.getItem(key) !== "true" &&
				(window as any).umami
			) {
				(window as any).umami.track("First guess");
				localStorage.setItem(key, "true");
			}
		}

		persistence.guesses = [guess, ...persistence.guesses];
		searchQuery = "";

		if (
			guess.book.id === correctBookId &&
			browser &&
			persistence.anonymousId
		) {
			statsData = await submitCompletion({
				anonymousId: persistence.anonymousId,
				date: dailyVerse.date,
				guessCount: persistence.guesses.length,
				guesses: persistence.guesses.map((g) => g.book.id),
			});
			if (statsData) {
				persistence.markStatsSubmitted();
			}
		}
	}

	// If server date doesn't match client's local date, fetch timezone-correct verse
	$effect(() => {
		if (!browser) return;

		const localDate = new Date().toLocaleDateString("en-CA");
		if (dailyVerse.date === localDate) return;

		const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;

		fetch("/api/daily-verse", {
			method: "POST",
			headers: { "Content-Type": "application/json" },
			body: JSON.stringify({ date: localDate, timezone }),
		})
			.then((res) => res.json())
			.then((result) => {
				dailyVerse = result.dailyVerse;
				correctBookId = result.correctBookId;
				correctBook = result.correctBook;
			})
			.catch((err) =>
				console.error("Failed to fetch timezone-correct verse:", err),
			);
	});

	// Reload when the user returns to a stale tab on a new calendar day
	$effect(() => {
		if (!browser) return;

		const loadedDate = new Date().toLocaleDateString("en-CA");

		function onVisibilityChange() {
			if (document.hidden) return;
			const now = new Date().toLocaleDateString("en-CA");
			if (now !== loadedDate) {
				window.location.reload();
			}
		}

		document.addEventListener("visibilitychange", onVisibilityChange);
		return () =>
			document.removeEventListener(
				"visibilitychange",
				onVisibilityChange,
			);
	});

	$effect(() => {
		if (!browser) return;
		isDev =
			window.location.host === "localhost:5173" ||
			window.location.host === "test.bibdle.com";
	});

	// Fetch stats on page load if user already won in a previous session (same device)
	$effect(() => {
		if (
			!browser ||
			!isWon ||
			!persistence.anonymousId ||
			statsData ||
			!persistence.statsSubmitted
		)
			return;
		fetchExistingStats({
			anonymousId: persistence.anonymousId,
			date: dailyVerse.date,
		}).then((data) => {
			statsData = data;
		});
	});

	// For logged-in users on a new device: restore today's game state from the server.
	// Runs even when isWon is true so that logging in after completing the game on another
	// device always replaces local localStorage with the authoritative DB record.
	let crossDeviceCheckDate = $state<string | null>(null);
	$effect(() => {
		if (
			!browser ||
			!user ||
			!dailyVerse?.date ||
			crossDeviceCheckDate === dailyVerse.date ||
			!persistence.anonymousId
		)
			return;
		crossDeviceCheckDate = dailyVerse.date;
		fetchExistingStats({
			anonymousId: persistence.anonymousId,
			date: dailyVerse.date,
		}).then((data) => {
			if (data?.guesses?.length) {
				persistence.hydrateFromServer(data.guesses);
				statsData = data;
				persistence.markStatsSubmitted();
			}
		});
	});

	// Delay showing win screen until GuessesTable animation completes
	$effect(() => {
		if (!isWon) {
			showWinScreen = false;
			return;
		}

		if (persistence.isWinAlreadyTracked()) {
			showWinScreen = true;
		} else {
			const animationDelay = 1800;
			const timeoutId = setTimeout(() => {
				showWinScreen = true;
			}, animationDelay);
			return () => clearTimeout(timeoutId);
		}
	});

	// Track win analytics
	$effect(() => {
		if (!browser || !isWon) return;
		const isNew = persistence.markWinTracked();
		if (isNew && (window as any).umami) {
			(window as any).umami.track("Guessed correctly", {
				totalGuesses: persistence.guesses.length,
			});
		}
	});

	function getShareText(): string {
		return generateShareText({
			guesses: persistence.guesses,
			correctBookId,
			dailyVerseDate: dailyVerse.date,
			grade,
			chapterCorrect: persistence.chapterCorrect,
			isLoggedIn: !!user,
			userStreak: user ? (user as any).streak : undefined,
			origin: window.location.origin,
		});
	}

	function handleShare() {
		if (copied || !browser) return;
		const useClipboard = !("share" in navigator);
		if (useClipboard) {
			copied = true;
		}
		shareResult(getShareText())
			.then(() => {
				if (useClipboard) {
					setTimeout(() => {
						copied = false;
					}, 5000);
				}
			})
			.catch(() => {
				if (useClipboard) {
					copied = false;
				}
			});
	}

	async function handleCopyToClipboard() {
		if (!browser) return;
		try {
			await clipboardCopy(getShareText());
			copied = true;
			setTimeout(() => {
				copied = false;
			}, 5000);
		} catch (err) {
			console.error("Copy to clipboard failed:", err);
		}
	}
</script>

<svelte:head>
	<title>A daily bible game{isDev ? " (dev)" : ""}</title>
</svelte:head>

<div class="min-h-dvh md:bg-linear-to-br md:from-blue-50 md:to-indigo-200 py-8">
	<div class="w-full max-w-3xl mx-auto px-4">
		<h1
			class="text-3xl md:text-4xl font-bold text-center uppercase text-gray-600 drop-shadow-2xl tracking-widest p-4 animate-fade-in-up"
		>
			<TitleAnimation />
			<div class="font-normal"></div>
		</h1>
		<div class="text-center mb-8 animate-fade-in-up animate-delay-200">
			<span class="big-text"
				>{isDev ? "Dev Edition  |  " : ""}{currentDate}</span
			>
		</div>

		<div class="flex flex-col gap-6">
			<div class="animate-fade-in-up animate-delay-200">
				<VerseDisplay {data} {isWon} {blurChapter} />
			</div>

			{#if !isWon}
				<div class="animate-fade-in-up animate-delay-400">
					<SearchInput bind:searchQuery {guessedIds} {submitGuess} />
				</div>
			{:else if showWinScreen}
				<div class="animate-fade-in-up animate-delay-400">
					<WinScreen
						{grade}
						{statsData}
						{correctBookId}
						{handleShare}
						copyToClipboard={handleCopyToClipboard}
						bind:copied
						statsSubmitted={persistence.statsSubmitted}
						guessCount={persistence.guesses.length}
						reference={dailyVerse.reference}
						onChapterGuessCompleted={persistence.onChapterGuessCompleted}
					/>
				</div>
			{/if}

			<div class="animate-fade-in-up animate-delay-600">
				<GuessesTable guesses={persistence.guesses} {correctBookId} />
			</div>

			{#if isWon}
				<div class="animate-fade-in-up animate-delay-800">
					<Credits />
				</div>
			{/if}
		</div>
		{#if isDev}
			<div class="mt-8 flex flex-col items-stretch md:items-center gap-3">
				<div class="flex flex-col md:flex-row gap-3">
					<a
						href="/stats?{user
							? `userId=${user.id}`
							: `anonymousId=${persistence.anonymousId}`}&tz={encodeURIComponent(
							Intl.DateTimeFormat().resolvedOptions().timeZone,
						)}"
						class="inline-flex items-center justify-center px-4 py-2 bg-amber-600 text-white rounded-lg hover:bg-amber-700 transition-colors text-sm font-medium shadow-md"
					>
						📊 View Stats
					</a>

					{#if user}
						<form
							method="POST"
							action="/auth/logout"
							use:enhance
							class="w-full md:w-auto"
						>
							<button
								type="submit"
								class="inline-flex items-center justify-center w-full px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors text-sm font-medium shadow-md"
							>
								🚪 Sign Out
							</button>
						</form>
					{:else}
						<button
							onclick={() => (authModalOpen = true)}
							class="inline-flex items-center justify-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm font-medium shadow-md"
						>
							🔐 Sign In
						</button>
					{/if}
				</div>

				<div
					class="text-xs text-gray-600 bg-gray-100 px-3 py-2 rounded border"
				>
					<div><strong>Debug Info:</strong></div>
					<div>
						User: {user
							? `${user.email} (ID: ${user.id})`
							: "Not signed in"}
					</div>
					<div>
						Session: {session
							? `Expires ${session.expiresAt.toLocaleDateString()}`
							: "No session"}
					</div>
					<div>
						Anonymous ID: {persistence.anonymousId || "Not set"}
					</div>
					<div>
						Client Local Time: {new Date().toLocaleString("en-US", {
							timeZone:
								Intl.DateTimeFormat().resolvedOptions()
									.timeZone,
							timeZoneName: "short",
						})}
					</div>
					<div>
						Client Local Date: {new Date().toLocaleDateString(
							"en-CA",
						)}
					</div>
					<div>Daily Verse Date: {dailyVerse.date}</div>
				</div>
				<DevButtons />
			</div>
		{/if}

		{#if user && session}
			<div class="mt-6 pt-4 border-t border-gray-200 text-center text-xs text-gray-400">
				Signed in as {[user.firstName, user.lastName].filter(Boolean).join(" ")}{user.email ? ` (${user.email})` : ""}{user.appleId ? " using Apple" : ""}
				<form method="POST" action="/auth/logout" use:enhance class="inline">
					<button
						type="submit"
						class="ml-2 underline hover:text-gray-600 transition-colors cursor-pointer"
					>Sign out</button>
				</form>
			</div>
		{/if}
	</div>
</div>

<AuthModal bind:isOpen={authModalOpen} anonymousId={persistence.anonymousId} />
