import { speakText } from "./audio/speech";
import { companions } from "./companion/characters";
import { getGreeting } from "./companion/companion";
import { renderInlineMarkdown } from "./utils/markdown";
import { initRewardScreen, startPreGeneration } from "./forest/reward";
import { initForestScreen, renderForestScene, SLOTS_PER_PAGE } from "./forest/scene";
import { getForestElements, getProgress, openDB, saveProgress } from "./storage/db";
import type { ScreenName } from "./types";
import { initParentScreen, showParentCodePrompt } from "./ui/parent";
import { initLessonScreen, initWelcomeScreen } from "./ui/screens";

let db: IDBDatabase;
let lessonCleanup: (() => void) | null = null;

export function showScreen(name: ScreenName): void {
	document.querySelectorAll(".screen").forEach((el) => {
		el.classList.remove("screen--active");
	});
	const target = document.getElementById(`screen-${name}`);
	if (target) {
		target.classList.add("screen--active");
	}
}

export function getDB(): IDBDatabase {
	return db;
}

const MAX_LEVEL = 6;

/**
 * Ensure progress object has all fields (migration for older saved data).
 */
function migrateProgress(
	progress: NonNullable<Awaited<ReturnType<typeof getProgress>>>,
): void {
	if (!progress.errorKeyCounts) progress.errorKeyCounts = {};
	if (!progress.lastPlayedLevels) progress.lastPlayedLevels = [];
	if (progress.totalCorrect === undefined) progress.totalCorrect = 0;
	if (progress.totalErrors === undefined) progress.totalErrors = 0;
	if (progress.currentForestPage === undefined) progress.currentForestPage = 0;
}

async function handleLessonComplete(
	completedLevel: number,
	stats: {
		totalCorrect: number;
		totalErrors: number;
		errorKeys: Record<string, number>;
	},
): Promise<void> {
	// Update progress after lesson completion
	const progress = await getProgress(db);
	if (!progress) return;
	migrateProgress(progress);

	// Accumulate exercise stats (D-15, D-16)
	progress.totalCorrect += stats.totalCorrect;
	progress.totalErrors += stats.totalErrors;
	for (const [key, count] of Object.entries(stats.errorKeys)) {
		progress.errorKeyCounts[key] =
			(progress.errorKeyCounts[key] ?? 0) + count;
	}

	// Track last played levels (keep last 3) for repetition detection
	progress.lastPlayedLevels.push(completedLevel);
	if (progress.lastPlayedLevels.length > 3) {
		progress.lastPlayedLevels = progress.lastPlayedLevels.slice(-3);
	}

	// Add level to completedLevels if not already there
	if (!progress.completedLevels.includes(completedLevel)) {
		progress.completedLevels.push(completedLevel);
	}

	// Advance to next level if this was the current level (LEVL-02, LEVL-03)
	// Cap at MAX_LEVEL so we don't go beyond defined levels
	if (
		completedLevel === progress.currentLevel &&
		completedLevel < MAX_LEVEL
	) {
		progress.currentLevel = completedLevel + 1;
	}

	// Increment session count
	progress.totalSessions++;

	// Add today's date if not already recorded
	const today = new Date().toISOString().split("T")[0]!;
	if (!progress.sessionDates.includes(today)) {
		progress.sessionDates.push(today);
	}

	await saveProgress(db, progress);

	// Show REWARD screen instead of going directly to forest
	showScreen("reward");

	// Set companion avatar on reward screen
	const companion = companions.find(
		(c) => c.type === progress.selectedCharacter,
	);
	if (companion) {
		const avatar = document.getElementById(
			"reward-companion-avatar",
		) as HTMLImageElement;
		avatar.src = companion.avatarUrl;
		avatar.alt = companion.name;
	}

	const elementId = await initRewardScreen(
		db,
		completedLevel,
		progress.selectedCharacter,
		() => {
			// "Weiter üben" -- start next lesson
			startLessonFromForest(
				Math.min(progress.currentLevel, MAX_LEVEL),
			);
		},
		async () => {
			// "Zurück zum Wald" -- navigate to page containing the new element
			const elements = await getForestElements(db);
			const newPage = Math.max(0, Math.ceil(elements.length / SLOTS_PER_PAGE) - 1);

			// Update progress with new page before initForestScreen reads it
			const latestProgress = await getProgress(db);
			if (latestProgress) {
				latestProgress.currentForestPage = newPage;
				await saveProgress(db, latestProgress);
			}

			await initForestScreen(db, startLessonFromForest);
			await renderForestScene(db, newPage, elementId);
			showScreen("forest");
		},
	);
}

async function handleLessonCancel(): Promise<void> {
	await initForestScreen(db, startLessonFromForest);
	showScreen("forest");
}

function startLessonFromForest(level: number): void {
	// Clean up previous lesson if any
	if (lessonCleanup) {
		lessonCleanup();
		lessonCleanup = null;
	}

	// Get layout and determine review/encouragement from progress
	getProgress(db).then((progress) => {
		if (!progress) return;
		migrateProgress(progress);

		const layout = progress.selectedLayout ?? "de";

		// Review every 3rd session (D-05)
		const isReview =
			progress.totalSessions > 0 &&
			progress.totalSessions % 3 === 0;

		// Encouragement if last 2 played levels are the same as current (D-06)
		const last2 = progress.lastPlayedLevels.slice(-2);
		const showEncouragement =
			last2.length === 2 &&
			last2[0] === level &&
			last2[1] === level;

		// Start image pre-generation (D-11) -- fire and forget
		startPreGeneration(db);

		showScreen("lesson");

		lessonCleanup = initLessonScreen(
			db,
			level,
			layout,
			handleLessonComplete,
			handleLessonCancel,
			isReview,
			showEncouragement,
		);
	});
}

export async function initApp(): Promise<void> {
	db = await openDB();

	// Wire parent screen back button
	initParentScreen(db, async () => {
		await initForestScreen(db, startLessonFromForest);
		showScreen("forest");
	});

	// Global keyboard shortcut for parent area (Ctrl+Shift+E)
	document.addEventListener("keydown", (e) => {
		if (e.ctrlKey && e.shiftKey && e.key === "E") {
			e.preventDefault();
			showParentCodePrompt();
		}
		// Dev shortcut: Ctrl+Shift+X to wipe all data and restart
		if (e.ctrlKey && e.shiftKey && e.key === "X") {
			e.preventDefault();
			if (confirm("DEV: Alle Daten löschen und neu starten?")) {
				const delReq = indexedDB.deleteDatabase("zauberwald");
				delReq.onsuccess = () => location.reload();
				delReq.onerror = () => location.reload();
			}
		}
	});

	const progress = await getProgress(db);
	if (progress && progress.selectedCharacter) {
		migrateProgress(progress);

		// Returning user -- init forest and go there
		await initForestScreen(db, startLessonFromForest);
		showScreen("forest");

		// Show companion greeting (per COMP-01, D-14)
		const companion = companions.find(
			(c) => c.type === progress.selectedCharacter,
		);
		if (companion) {
			const greetingEl = document.getElementById("forest-greeting")!;
			const avatarEl = document.getElementById(
				"forest-greeting-avatar",
			) as HTMLImageElement;
			const textEl = document.getElementById("forest-greeting-text")!;

			avatarEl.src = companion.avatarUrl;
			avatarEl.alt = companion.name;
			greetingEl.style.display = "flex";

			// Fetch greeting async (shows immediately with avatar, text fills in)
			getGreeting(progress.selectedCharacter, db).then((text) => {
				textEl.innerHTML = renderInlineMarkdown(text);
				speakText(text);
			});
		}
	} else {
		// First time -- show welcome, then forest after setup
		initWelcomeScreen(db, async (screen: ScreenName) => {
			showScreen(screen);
			if (screen === "forest") {
				await initForestScreen(db, startLessonFromForest);
			}
		});
		showScreen("welcome");
	}
}
