import { describe, test, expect } from "bun:test";
import { generateShareText, getVerseSnippet } from "$lib/utils/share";
import { getBookById } from "$lib/utils/game";
import type { Guess } from "$lib/utils/game";

// Helpers to build Guess objects without calling evaluateGuess
function makeGuess(bookId: string, overrides: Partial<Omit<Guess, "book">> = {}): Guess {
	const book = getBookById(bookId)!;
	return {
		book,
		testamentMatch: false,
		sectionMatch: false,
		adjacent: false,
		firstLetterMatch: false,
		...overrides,
	};
}

const CORRECT_BOOK_ID = "GEN";

const exactGuess = makeGuess("GEN", {
	testamentMatch: true,
	sectionMatch: true,
});

const adjacentGuess = makeGuess("EXO", {
	testamentMatch: true,
	sectionMatch: true,
	adjacent: true,
});

const sectionGuess = makeGuess("LEV", {
	testamentMatch: true,
	sectionMatch: true,
});

const testamentGuess = makeGuess("JOS", {
	testamentMatch: true,
	sectionMatch: false,
});

const noMatchGuess = makeGuess("MAT", {
	testamentMatch: false,
	sectionMatch: false,
});

describe("generateShareText — emoji mapping", () => {
	test("exact match → ✅", () => {
		const text = generateShareText({
			guesses: [exactGuess],
			correctBookId: CORRECT_BOOK_ID,
			dailyVerseDate: "2025-01-15",
			chapterCorrect: false,
			isLoggedIn: false,
			origin: "https://bibdle.com",
			verseText: "In the beginning...",
		});
		expect(text).toContain("✅");
	});

	test("adjacent book → ‼️", () => {
		const text = generateShareText({
			guesses: [adjacentGuess],
			correctBookId: CORRECT_BOOK_ID,
			dailyVerseDate: "2025-01-15",
			chapterCorrect: false,
			isLoggedIn: false,
			origin: "https://bibdle.com",
			verseText: "In the beginning...",
		});
		expect(text).toContain("‼️");
	});

	test("section match → 🟩", () => {
		// LEV matches section (Law) but is not adjacent to GEN (order 1 vs 3)
		const text = generateShareText({
			guesses: [sectionGuess],
			correctBookId: CORRECT_BOOK_ID,
			dailyVerseDate: "2025-01-15",
			chapterCorrect: false,
			isLoggedIn: false,
			origin: "https://bibdle.com",
			verseText: "In the beginning...",
		});
		expect(text).toContain("🟩");
	});

	test("testament match only → 🟧", () => {
		const text = generateShareText({
			guesses: [testamentGuess],
			correctBookId: CORRECT_BOOK_ID,
			dailyVerseDate: "2025-01-15",
			chapterCorrect: false,
			isLoggedIn: false,
			origin: "https://bibdle.com",
			verseText: "In the beginning...",
		});
		expect(text).toContain("🟧");
	});

	test("no match → 🟥", () => {
		const text = generateShareText({
			guesses: [noMatchGuess],
			correctBookId: CORRECT_BOOK_ID,
			dailyVerseDate: "2025-01-15",
			chapterCorrect: false,
			isLoggedIn: false,
			origin: "https://bibdle.com",
			verseText: "In the beginning...",
		});
		expect(text).toContain("🟥");
	});
});

describe("generateShareText — guess count wording", () => {
	test("1 guess uses singular 'guess'", () => {
		const text = generateShareText({
			guesses: [exactGuess],
			correctBookId: CORRECT_BOOK_ID,
			dailyVerseDate: "2025-01-15",
			chapterCorrect: false,
			isLoggedIn: false,
			origin: "https://bibdle.com",
			verseText: "...",
		});
		expect(text).toContain("1 guess,");
	});

	test("multiple guesses uses plural 'guesses'", () => {
		const text = generateShareText({
			guesses: [noMatchGuess, testamentGuess, exactGuess],
			correctBookId: CORRECT_BOOK_ID,
			dailyVerseDate: "2025-01-15",
			chapterCorrect: false,
			isLoggedIn: false,
			origin: "https://bibdle.com",
			verseText: "...",
		});
		expect(text).toContain("3 guesses,");
	});
});

describe("generateShareText — streak display", () => {
	test("streak > 1 is shown with fire emoji", () => {
		const text = generateShareText({
			guesses: [exactGuess],
			correctBookId: CORRECT_BOOK_ID,
			dailyVerseDate: "2025-01-15",
			chapterCorrect: false,
			isLoggedIn: false,
			streak: 5,
			origin: "https://bibdle.com",
			verseText: "...",
		});
		expect(text).toContain("5 days 🔥");
	});

	test("streak of 1 is not shown", () => {
		const text = generateShareText({
			guesses: [exactGuess],
			correctBookId: CORRECT_BOOK_ID,
			dailyVerseDate: "2025-01-15",
			chapterCorrect: false,
			isLoggedIn: false,
			streak: 1,
			origin: "https://bibdle.com",
			verseText: "...",
		});
		expect(text).not.toContain("🔥");
	});

	test("undefined streak is not shown", () => {
		const text = generateShareText({
			guesses: [exactGuess],
			correctBookId: CORRECT_BOOK_ID,
			dailyVerseDate: "2025-01-15",
			chapterCorrect: false,
			isLoggedIn: false,
			origin: "https://bibdle.com",
			verseText: "...",
		});
		expect(text).not.toContain("🔥");
	});
});

describe("generateShareText — chapter star", () => {
	test("1 guess + chapterCorrect → ⭐ appended to emoji line", () => {
		const text = generateShareText({
			guesses: [exactGuess],
			correctBookId: CORRECT_BOOK_ID,
			dailyVerseDate: "2025-01-15",
			chapterCorrect: true,
			isLoggedIn: false,
			origin: "https://bibdle.com",
			verseText: "...",
		});
		expect(text).toContain("✅ ⭐");
	});

	test("multiple guesses + chapterCorrect → no star (only awarded for hole-in-one)", () => {
		const text = generateShareText({
			guesses: [noMatchGuess, exactGuess],
			correctBookId: CORRECT_BOOK_ID,
			dailyVerseDate: "2025-01-15",
			chapterCorrect: true,
			isLoggedIn: false,
			origin: "https://bibdle.com",
			verseText: "...",
		});
		expect(text).not.toContain("⭐");
	});

	test("1 guess + chapterCorrect false → no star", () => {
		const text = generateShareText({
			guesses: [exactGuess],
			correctBookId: CORRECT_BOOK_ID,
			dailyVerseDate: "2025-01-15",
			chapterCorrect: false,
			isLoggedIn: false,
			origin: "https://bibdle.com",
			verseText: "...",
		});
		expect(text).not.toContain("⭐");
	});
});

describe("generateShareText — login book emoji", () => {
	test("logged in uses 📜", () => {
		const text = generateShareText({
			guesses: [exactGuess],
			correctBookId: CORRECT_BOOK_ID,
			dailyVerseDate: "2025-01-15",
			chapterCorrect: false,
			isLoggedIn: true,
			origin: "https://bibdle.com",
			verseText: "...",
		});
		expect(text).toContain("📜");
		expect(text).not.toContain("📖");
	});

	test("not logged in uses 📖", () => {
		const text = generateShareText({
			guesses: [exactGuess],
			correctBookId: CORRECT_BOOK_ID,
			dailyVerseDate: "2025-01-15",
			chapterCorrect: false,
			isLoggedIn: false,
			origin: "https://bibdle.com",
			verseText: "...",
		});
		expect(text).toContain("📖");
		expect(text).not.toContain("📜");
	});
});

describe("generateShareText — date formatting", () => {
	test("date is formatted as 'Mon DD, YYYY'", () => {
		const text = generateShareText({
			guesses: [exactGuess],
			correctBookId: CORRECT_BOOK_ID,
			dailyVerseDate: "2025-01-15",
			chapterCorrect: false,
			isLoggedIn: false,
			origin: "https://bibdle.com",
			verseText: "...",
		});
		expect(text).toContain("Jan 15, 2025");
	});
});

describe("generateShareText — guess order", () => {
	test("guesses are reversed in the emoji line (first guess last)", () => {
		// noMatchGuess first, then exactGuess — reversed output: ✅🟥
		const text = generateShareText({
			guesses: [noMatchGuess, exactGuess],
			correctBookId: CORRECT_BOOK_ID,
			dailyVerseDate: "2025-01-15",
			chapterCorrect: false,
			isLoggedIn: false,
			origin: "https://bibdle.com",
			verseText: "...",
		});
		const lines = text.split("\n");
		expect(lines[2]).toBe("✅🟥");
	});
});

describe("getVerseSnippet", () => {
	test("wraps output in curly double quotes", () => {
		const result = getVerseSnippet("Hello world");
		expect(result.startsWith("\u201C")).toBe(true);
		expect(result.endsWith("\u201D")).toBe(true);
	});

	test("short verse (fewer than 10 words) returns full text", () => {
		const result = getVerseSnippet("For God so loved");
		// No punctuation search happens, returns all words
		expect(result).toContain("For God so loved");
		expect(result).toContain("...");
	});

	test("verse with no punctuation in range returns first 25 words", () => {
		const words = Array.from({ length: 30 }, (_, i) => `word${i + 1}`);
		const verse = words.join(" ");
		const result = getVerseSnippet(verse);
		// Should contain up to 25 words
		expect(result).toContain("word25");
		expect(result).not.toContain("word26");
	});

	test("truncates at punctuation between words 10 and 25", () => {
		// 12 words before comma, rest after
		const verse =
			"one two three four five six seven eight nine ten eleven twelve, thirteen fourteen fifteen twenty";
		const result = getVerseSnippet(verse);
		// The comma is after word 12, which is between word 10 and 25
		expect(result).toContain("twelve");
		expect(result).not.toContain("thirteen");
	});

	test("punctuation before word 10 does not trigger truncation", () => {
		// Comma is after word 5 — before the search window starts at word 10
		const verse =
			"one two three four five, six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen";
		const result = getVerseSnippet(verse);
		// The comma at word 5 is before start of search range, so we continue
		// The snippet should contain word 10 at minimum
		expect(result).toContain("ten");
	});

	test("does not include trailing whitespace before ellipsis", () => {
		const verse =
			"one two three four five six seven eight nine ten eleven twelve, rest of verse here";
		const result = getVerseSnippet(verse);
		// trimEnd is applied before adding ..., so no space before ...
		expect(result).not.toMatch(/\s\.\.\./);
	});
});
