<script lang="ts">
	import { bibleBooks, type BibleBook } from "$lib/types/bible";

	import type { PageProps } from "./$types";
	import { browser } from "$app/environment";

	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 { getGrade } from "$lib/utils/game";

	interface Guess {
		book: BibleBook;
		testamentMatch: boolean;
		sectionMatch: boolean;
		adjacent: boolean;
		firstLetterMatch: boolean;
	}

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

	let dailyVerse = $derived(data.dailyVerse);
	let correctBookId = $derived(data.correctBookId);

	let guesses = $state<Guess[]>([]);

	let searchQuery = $state("");

	let copied = $state(false);
	let isDev = $state(false);
	let chapterGuessCompleted = $state(false);
	let chapterCorrect = $state(false);

	let anonymousId = $state("");
	let statsSubmitted = $state(false);
	let statsData = $state<{
		solveRank: number;
		guessRank: number;
		totalSolves: number;
		averageGuesses: number;
		tiedCount: number;
		percentile: number;
	} | null>(null);

	let guessedIds = $derived(new Set(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(guesses.some((g) => g.book.id === correctBookId));
	let grade = $derived(
		isWon
			? guesses.length === 1 && chapterCorrect
				? "S++"
				: getGrade(
						guesses.length,
						getBookById(correctBookId)?.popularity ?? 0,
					)
			: "",
	);
	let blurChapter = $derived(
		isWon && guesses.length === 1 && !chapterGuessCompleted,
	);

	function getBookById(id: string): BibleBook | undefined {
		return bibleBooks.find((b) => b.id === id);
	}

	function isAdjacent(id1: string, id2: string): boolean {
		const b1 = getBookById(id1);
		const b2 = getBookById(id2);
		return !!(b1 && b2 && Math.abs(b1.order - b2.order) === 1);
	}

	function getFirstLetter(bookName: string): string {
		const match = bookName.match(/[a-zA-Z]/);
		return match ? match[0] : bookName[0];
	}

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

		const book = getBookById(bookId);
		if (!book) return;

		const correctBook = getBookById(correctBookId);
		if (!correctBook) return;

		const testamentMatch = book.testament === correctBook.testament;
		const sectionMatch = book.section === correctBook.section;
		const adjacent = isAdjacent(bookId, correctBookId);

		// Special case: if correct book is in the Epistles + starts with "1",
		// any guess starting with "1" counts as first letter match
		const correctIsEpistlesWithNumber =
			(correctBook.section === "Pauline Epistles" ||
				correctBook.section === "General Epistles") &&
			correctBook.name[0] === "1";
		const guessIsEpistlesWithNumber =
			(book.section === "Pauline Epistles" ||
				book.section === "General Epistles") &&
			book.name[0] === "1";

		const firstLetterMatch =
			correctIsEpistlesWithNumber && guessIsEpistlesWithNumber
				? true
				: getFirstLetter(book.name).toUpperCase() ===
					getFirstLetter(correctBook.name).toUpperCase();

		console.log(
			`Guess: ${book.name} (order ${book.order}), Correct: ${correctBook.name} (order ${correctBook.order}), Adjacent: ${adjacent}`,
		);

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

		guesses = [
			{
				book,
				testamentMatch,
				sectionMatch,
				adjacent,
				firstLetterMatch,
			},
			...guesses,
		];

		searchQuery = "";
	}

	function generateUUID(): string {
		// Try native randomUUID if available
		if (typeof window.crypto.randomUUID === "function") {
			return window.crypto.randomUUID();
		}

		// Fallback UUID v4 generator for older browsers
		return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
			const r =
				window.crypto.getRandomValues(new Uint8Array(1))[0] % 16 | 0;
			const v = c === "x" ? r : (r & 0x3) | 0x8;
			return v.toString(16);
		});
	}

	function getOrCreateAnonymousId(): string {
		if (!browser) return "";
		const key = "bibdle-anonymous-id";
		let id = localStorage.getItem(key);
		if (!id) {
			id = generateUUID();
			localStorage.setItem(key, id);
		}
		return id;
	}

	// Initialize anonymous ID
	$effect(() => {
		if (!browser) return;
		anonymousId = getOrCreateAnonymousId();
		const statsKey = `bibdle-stats-submitted-${dailyVerse.date}`;
		statsSubmitted = localStorage.getItem(statsKey) === "true";
		const chapterGuessKey = `bibdle-chapter-guess-${dailyVerse.reference}`;
		chapterGuessCompleted = localStorage.getItem(chapterGuessKey) !== null;
		if (chapterGuessCompleted) {
			const saved = localStorage.getItem(chapterGuessKey);
			if (saved) {
				const data = JSON.parse(saved);
				const match = dailyVerse.reference.match(/\s(\d+):/);
				const correctChapter = match ? parseInt(match[1], 10) : 1;
				chapterCorrect = data.selectedChapter === correctChapter;
			}
		}
	});

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

	// Load saved guesses
	$effect(() => {
		if (!browser) return;

		const key = `bibdle-guesses-${dailyVerse.date}`;
		const saved = localStorage.getItem(key);
		if (saved) {
			let savedIds: string[] = JSON.parse(saved);
			savedIds = Array.from(new Set(savedIds));
			guesses = savedIds.map((bookId: string) => {
				const book = getBookById(bookId)!;
				const correctBook = getBookById(correctBookId)!;
				const testamentMatch = book.testament === correctBook.testament;
				const sectionMatch = book.section === correctBook.section;
				const adjacent = isAdjacent(bookId, correctBookId);

				// Apply same first letter logic as in submitGuess
				const correctIsEpistlesWithNumber =
					(correctBook.section === "Pauline Epistles" ||
						correctBook.section === "General Epistles") &&
					correctBook.name[0] === "1";
				const guessIsEpistlesWithNumber =
					(book.section === "Pauline Epistles" ||
						book.section === "General Epistles") &&
					book.name[0] === "1";

				const firstLetterMatch =
					correctIsEpistlesWithNumber && guessIsEpistlesWithNumber
						? true
						: getFirstLetter(book.name).toUpperCase() ===
							getFirstLetter(correctBook.name).toUpperCase();

				return {
					book,
					testamentMatch,
					sectionMatch,
					adjacent,
					firstLetterMatch,
				};
			});
		}
	});

	$effect(() => {
		if (!browser) return;
		localStorage.setItem(
			`bibdle-guesses-${dailyVerse.date}`,
			JSON.stringify(guesses.map((g) => g.book.id)),
		);
	});

	// Auto-submit stats when user wins
	$effect(() => {
		console.log("Stats effect triggered:", {
			browser,
			isWon,
			anonymousId,
			statsSubmitted,
			statsData,
		});

		if (!browser || !isWon || !anonymousId) {
			console.log("Basic conditions not met");
			return;
		}

		if (statsSubmitted && !statsData) {
			console.log("Fetching existing stats...");

			(async () => {
				try {
					const response = await fetch(
						`/api/submit-completion?anonymousId=${anonymousId}&date=${dailyVerse.date}`,
					);
					const result = await response.json();
					console.log("Stats response:", result);

					if (result.success && result.stats) {
						console.log("Setting stats data:", result.stats);
						statsData = result.stats;
						localStorage.setItem(
							`bibdle-stats-submitted-${dailyVerse.date}`,
							"true",
						);
					} else if (result.error) {
						console.error("Server error:", result.error);
					} else {
						console.error("Unexpected response format:", result);
					}
				} catch (err) {
					console.error("Stats fetch failed:", err);
				}
			})();

			return;
		}

		console.log("Submitting stats...");

		async function submitStats() {
			try {
				const payload = {
					anonymousId,
					date: dailyVerse.date,
					guessCount: guesses.length,
				};

				console.log("Sending POST request with:", payload);

				const response = await fetch("/api/submit-completion", {
					method: "POST",
					headers: {
						"Content-Type": "application/json",
					},
					body: JSON.stringify(payload),
				});

				const result = await response.json();
				console.log("Stats response:", result);

				if (result.success && result.stats) {
					console.log("Setting stats data:", result.stats);
					statsData = result.stats;
					statsSubmitted = true;
					localStorage.setItem(
						`bibdle-stats-submitted-${dailyVerse.date}`,
						"true",
					);
				} else if (result.error) {
					console.error("Server error:", result.error);
				} else {
					console.error("Unexpected response format:", result);
				}
			} catch (err) {
				console.error("Stats submission failed:", err);
			}
		}

		submitStats();
	});

	$effect(() => {
		if (!browser || !isWon) return;
		const key = `bibdle-win-tracked-${dailyVerse.date}`;
		if (localStorage.getItem(key) === "true") return;
		if ((window as any).umami) {
			(window as any).umami.track("Guessed correctly", {
				totalGuesses: guesses.length,
			});
		}
		localStorage.setItem(key, "true");
	});

	function generateShareText(): string {
		const emojis = guesses
			.slice()
			.reverse()
			.map((guess) => {
				if (guess.book.id === correctBookId) return "✅";
				if (guess.adjacent) return "‼️";
				if (guess.sectionMatch) return "🟩";
				if (guess.testamentMatch) return "🟧";
				return "🟥";
			})
			.join("");

		const dateFormatter = new Intl.DateTimeFormat("en-US", {
			month: "short",
			day: "numeric",
			year: "numeric",
		});
		const formattedDate = dateFormatter.format(
			new Date(`${dailyVerse.date}T00:00:00`),
		);
		const siteUrl = window.location.origin;
		return [
			`📖 Bibdle | ${formattedDate} 📖`,
			`${grade} (${guesses.length} ${guesses.length === 1 ? "guess" : "guesses"})`,
			`${emojis}${guesses.length === 1 && chapterCorrect ? " ⭐" : ""}`,
			siteUrl,
		].join("\n");
	}

	async function share() {
		if (!browser) return;

		const shareText = generateShareText();

		try {
			if ("share" in navigator) {
				await (navigator as any).share({ text: shareText });
			} else {
				await (navigator as any).clipboard.writeText(shareText);
			}
		} catch (err) {
			console.error("Share failed:", err);
			throw err;
		}
	}

	async function copyToClipboard() {
		if (!browser) return;

		const shareText = generateShareText();

		try {
			await (navigator as any).clipboard.writeText(shareText);
			copied = true;
			setTimeout(() => {
				copied = false;
			}, 5000);
		} catch (err) {
			console.error("Copy to clipboard failed:", err);
			throw err;
		}
	}

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

<svelte:head>
	<title>A daily bible game{isDev ? " (dev)" : ""}</title>
	<!-- <meta
    name="description"
    content="Guess which book of the Bible a verse comes from."
  /> -->
</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"
		>
			<TitleAnimation />
			<div class="font-normal"></div>
		</h1>
		<div class="text-center mb-8">
			<span class="big-text"
				>{isDev ? "Dev Edition  |  " : ""}{currentDate}</span
			>
		</div>

		<div class="flex flex-col gap-6">
			<VerseDisplay {data} {isWon} {blurChapter} />

			{#if !isWon}
				<SearchInput bind:searchQuery {guessedIds} {submitGuess} />
			{:else}
				<WinScreen
					{grade}
					{statsData}
					{correctBookId}
					{handleShare}
					{copyToClipboard}
					bind:copied
					{statsSubmitted}
					guessCount={guesses.length}
					reference={dailyVerse.reference}
					onChapterGuessCompleted={() => {
						chapterGuessCompleted = true;
						const key = `bibdle-chapter-guess-${dailyVerse.reference}`;
						const saved = localStorage.getItem(key);
						if (saved) {
							const data = JSON.parse(saved);
							const match =
								dailyVerse.reference.match(/\s(\d+):/);
							const correctChapter = match
								? parseInt(match[1], 10)
								: 1;
							chapterCorrect =
								data.selectedChapter === correctChapter;
						}
					}}
				/>
			{/if}

			<GuessesTable {guesses} {correctBookId} />

			{#if isWon}
				<Credits />
			{/if}
		</div>
		{#if isDev}
			<DevButtons />
		{/if}
	</div>
</div>
