import { getProgress, saveProgress, getSettings, saveSettings } from "../storage/db";
import { companions } from "../companion/characters";
import type { CompanionType, KeyboardLayout, Settings } from "../types";
import { showScreen, getDB } from "../app";

const ACCESS_CODE = "1234";

/**
 * Show the parent code prompt gate, then reveal content on correct code.
 */
export function showParentCodePrompt(): void {
	showScreen("parent");

	const gate = document.getElementById("parent-gate")!;
	const content = document.getElementById("parent-content")!;
	const codeInput = document.getElementById("parent-code-input") as HTMLInputElement;
	const gateError = document.getElementById("parent-gate-error")!;

	// Reset state
	gate.style.display = "block";
	content.style.display = "none";
	codeInput.value = "";
	gateError.style.display = "none";

	codeInput.focus();

	// Remove previous listener to avoid duplicates
	const handler = () => {
		const value = codeInput.value;
		if (value === ACCESS_CODE) {
			gate.style.display = "none";
			content.style.display = "block";
			loadParentData();
			codeInput.removeEventListener("input", handler);
		} else if (value.length === 4) {
			gateError.style.display = "block";
			setTimeout(() => {
				gateError.style.display = "none";
				codeInput.value = "";
			}, 1500);
			codeInput.removeEventListener("input", handler);
			// Re-attach after clearing
			setTimeout(() => {
				codeInput.addEventListener("input", handler);
			}, 1500);
		}
	};

	codeInput.addEventListener("input", handler);
}

/**
 * Initialize the parent screen: wire back button.
 */
export function initParentScreen(_db: IDBDatabase, onBack: () => void): void {
	const backBtn = document.getElementById("parent-back-btn");
	if (backBtn) {
		backBtn.onclick = () => onBack();
	}
}

/**
 * Load and display all parent data (stats + settings).
 */
async function loadParentData(): Promise<void> {
	const db = getDB();
	const progress = await getProgress(db);
	const settings = await getSettings(db);

	// Stats
	if (progress) {
		document.getElementById("stat-level")!.textContent = String(progress.currentLevel);
		document.getElementById("stat-sessions")!.textContent = String(progress.totalSessions);

		const total = progress.totalCorrect + progress.totalErrors;
		const accuracy = total > 0 ? Math.round((progress.totalCorrect / total) * 100) : 0;
		document.getElementById("stat-accuracy")!.textContent = `${accuracy}%`;

		// Calendar dots (last 30 days)
		renderCalendarDots(progress.sessionDates);

		// Error keys
		renderErrorKeys(progress.errorKeyCounts);
	}

	// Settings
	await loadSettings(db, progress, settings);

	// Wire data action buttons
	document.getElementById("export-btn")!.onclick = () => exportData(db);
	document.getElementById("import-btn")!.onclick = () =>
		(document.getElementById("import-file") as HTMLInputElement).click();
	document.getElementById("import-file")!.addEventListener("change", (e) => {
		const file = (e.target as HTMLInputElement).files?.[0];
		if (file) importData(db, file);
	});
	document.getElementById("reset-btn")!.onclick = () => resetAllData(db);
}

/**
 * Render calendar dots for the last 30 days.
 */
function renderCalendarDots(sessionDates: string[]): void {
	const container = document.getElementById("calendar-dots")!;
	container.innerHTML = "";

	const today = new Date();
	const sessionSet = new Set(sessionDates);

	for (let i = 29; i >= 0; i--) {
		const date = new Date(today);
		date.setDate(today.getDate() - i);
		const dateStr = date.toISOString().split("T")[0]!;

		const dot = document.createElement("div");
		dot.className = sessionSet.has(dateStr)
			? "parent__calendar-dot"
			: "parent__calendar-dot parent__calendar-dot--empty";
		dot.title = dateStr;
		container.appendChild(dot);
	}
}

/**
 * Render error key badges, sorted by frequency, top 5.
 */
function renderErrorKeys(errorKeyCounts: Record<string, number>): void {
	const container = document.getElementById("error-keys-list")!;
	container.innerHTML = "";

	const entries = Object.entries(errorKeyCounts).sort((a, b) => b[1] - a[1]);

	if (entries.length === 0) {
		container.textContent = "Noch keine Fehler erfasst";
		return;
	}

	const top5 = entries.slice(0, 5);
	for (const [key, count] of top5) {
		const badge = document.createElement("span");
		badge.className = "parent__error-key";
		badge.textContent = `${key.toUpperCase()} (${count}x)`;
		container.appendChild(badge);
	}
}

/**
 * Load settings into form elements and wire change handlers.
 */
async function loadSettings(
	db: IDBDatabase,
	progress: Awaited<ReturnType<typeof getProgress>>,
	settings: Settings | null,
): Promise<void> {
	const layoutSelect = document.getElementById("setting-layout") as HTMLSelectElement;
	const audioCheckbox = document.getElementById("setting-audio") as HTMLInputElement;
	const companionSelect = document.getElementById("setting-companion") as HTMLSelectElement;
	const apiKeyInput = document.getElementById("setting-apikey") as HTMLInputElement;
	const saveApiKeyBtn = document.getElementById("save-apikey-btn")!;

	// Populate companion select
	companionSelect.innerHTML = "";
	for (const c of companions) {
		const option = document.createElement("option");
		option.value = c.type;
		option.textContent = `${c.emoji} ${c.name}`;
		companionSelect.appendChild(option);
	}

	// Set current values
	if (progress) {
		layoutSelect.value = progress.selectedLayout;
		companionSelect.value = progress.selectedCharacter;
	}
	if (settings) {
		audioCheckbox.checked = settings.audioEnabled;
		apiKeyInput.value = settings.apiKey || "";
	}

	// Wire change handlers
	layoutSelect.onchange = async () => {
		if (!progress) return;
		progress.selectedLayout = layoutSelect.value as KeyboardLayout;
		await saveProgress(db, progress);
		showSavedFeedback(layoutSelect);
	};

	companionSelect.onchange = async () => {
		if (!progress) return;
		progress.selectedCharacter = companionSelect.value as CompanionType;
		await saveProgress(db, progress);
		showSavedFeedback(companionSelect);
	};

	audioCheckbox.onchange = async () => {
		const currentSettings = settings ?? {
			id: 1 as const,
			audioEnabled: false,
			speechEnabled: false,
			apiKey: "",
			apiCallsToday: { text: 0, image: 0 },
			lastApiCallDate: "",
		};
		currentSettings.audioEnabled = audioCheckbox.checked;
		await saveSettings(db, currentSettings);
		showSavedFeedback(audioCheckbox);
	};

	saveApiKeyBtn.onclick = async () => {
		const currentSettings = settings ?? {
			id: 1 as const,
			audioEnabled: false,
			speechEnabled: false,
			apiKey: "",
			apiCallsToday: { text: 0, image: 0 },
			lastApiCallDate: "",
		};
		currentSettings.apiKey = apiKeyInput.value;
		await saveSettings(db, currentSettings);
		showSavedFeedback(saveApiKeyBtn);
	};
}

const DB_STORES = ["progress", "companionAssets", "styleReference", "forestElements", "settings"];

/**
 * Show feedback message in the data section.
 */
function showDataFeedback(message: string, isError = false): void {
	const el = document.getElementById("data-feedback")!;
	el.textContent = message;
	el.style.display = "block";
	el.style.color = isError ? "#D46A6A" : "";
	setTimeout(() => {
		el.style.display = "none";
	}, 3000);
}

/**
 * Export progress and settings as a JSON file download.
 */
async function exportData(db: IDBDatabase): Promise<void> {
	const progress = await getProgress(db);
	const settings = await getSettings(db);

	const data = {
		version: 1,
		exportedAt: new Date().toISOString(),
		progress,
		settings,
	};

	const blob = new Blob([JSON.stringify(data, null, 2)], { type: "application/json" });
	const url = URL.createObjectURL(blob);
	const a = document.createElement("a");
	a.href = url;
	a.download = "zauberwald-backup.json";
	a.click();
	URL.revokeObjectURL(url);

	showDataFeedback("Exportiert!");
}

/**
 * Import progress and settings from a JSON file.
 */
async function importData(db: IDBDatabase, file: File): Promise<void> {
	try {
		const text = await file.text();
		const parsed = JSON.parse(text);

		// Validate structure
		if (
			!parsed.progress ||
			typeof parsed.progress.currentLevel !== "number" ||
			!Array.isArray(parsed.progress.completedLevels) ||
			typeof parsed.progress.totalSessions !== "number" ||
			typeof parsed.progress.selectedCharacter !== "string" ||
			typeof parsed.progress.selectedLayout !== "string"
		) {
			showDataFeedback("Ungueltige Datei", true);
			return;
		}
		if (!parsed.settings || typeof parsed.settings.audioEnabled !== "boolean") {
			showDataFeedback("Ungueltige Datei", true);
			return;
		}

		if (!confirm("Fortschritt überschreiben? Aktuelle Daten gehen verloren.")) {
			return;
		}

		await saveProgress(db, { ...parsed.progress, id: 1 });
		await saveSettings(db, { ...parsed.settings, id: 1 });

		showDataFeedback("Importiert!");
		setTimeout(() => location.reload(), 1500);
	} catch {
		showDataFeedback("Ungueltige Datei", true);
	}
}

/**
 * Clear a single IndexedDB object store.
 */
function clearStore(db: IDBDatabase, storeName: string): Promise<void> {
	return new Promise((resolve, reject) => {
		const tx = db.transaction(storeName, "readwrite");
		const request = tx.objectStore(storeName).clear();
		request.onsuccess = () => resolve();
		request.onerror = () => reject(request.error);
	});
}

/**
 * Reset all data with double confirmation, then reload.
 */
async function resetAllData(db: IDBDatabase): Promise<void> {
	if (!confirm("Wirklich alles löschen?")) return;
	if (!confirm("Alle Fortschritte und Einstellungen werden gelöscht. Bist du sicher?")) return;

	await Promise.all(DB_STORES.map((store) => clearStore(db, store)));
	location.reload();
}

/**
 * Show brief "Gespeichert!" feedback next to an element.
 */
function showSavedFeedback(element: HTMLElement): void {
	// Remove any existing feedback
	const existing = element.parentElement?.querySelector(".parent__saved-feedback");
	if (existing) existing.remove();

	const feedback = document.createElement("span");
	feedback.className = "parent__saved-feedback";
	feedback.textContent = "Gespeichert!";
	element.parentElement?.appendChild(feedback);

	setTimeout(() => {
		feedback.style.opacity = "0";
		setTimeout(() => feedback.remove(), 300);
	}, 1500);
}
