"use client";

import {
	CalendarDays,
	MoreHorizontal,
	Settings,
	Wifi,
	WifiOff,
} from "lucide-react";
import { nanoid } from "nanoid";
import { useEffect, useState } from "react";
import { toast } from "sonner";
import { AIToolbar } from "@/components/ai-toolbar";
import { DragDropContainer } from "@/components/drag-drop-container";
import { EventDialog } from "@/components/event-dialog";
import { EventsList } from "@/components/events-list";
import { IcsFilePicker } from "@/components/ics-file-picker";
import { SettingsPanel } from "@/components/settings-panel";
import SignIn from "@/components/sign-in";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
	DropdownMenu,
	DropdownMenuContent,
	DropdownMenuItem,
	DropdownMenuSeparator,
	DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { useIsMobile } from "@/hooks/use-mobile";
import { getAiCreateOutcome } from "@/lib/ai-create-flow";
import {
	getAiDisabledMessage,
	isClientAiEnabled,
} from "@/lib/ai-feature-flags";
import { useSession } from "@/lib/auth-client";
import { MAX_IMAGE_SIZE_BYTES } from "@/lib/constants";
import {
	type EventFormValues,
	getDefaultEventFormValues,
	getEventFormValuesFromEvent,
} from "@/lib/event-form";
import {
	saveEvent as addEvent,
	clearEvents,
	deleteEvent,
	getEvents as getAllEvents,
	updateEvent,
} from "@/lib/events-db";
import { generateICS, parseICS } from "@/lib/ical";
import { appendImagesDeduped } from "@/lib/multi-image";
import type { CalendarEvent } from "@/lib/types";
import {
	APP_ACTION_BAR_CLASSES,
	getAppHeaderSurfaceClasses,
	getAppNavSurfaceClasses,
	getAppSectionSurfaceClasses,
	getConnectionBadgeClasses,
} from "@/lib/ui-shell-contract";
import { useUserSettings } from "@/lib/user-settings";
import { cn } from "@/lib/utils";

const NAV_BUTTON_CLASSES = "flex-1 gap-2";

const getNavButtonClasses = (isActive: boolean) =>
	cn(NAV_BUTTON_CLASSES, isActive ? "text-primary" : "text-muted-foreground");

const fileToBase64 = (file: File): Promise<string> =>
	new Promise((resolve, reject) => {
		const reader = new FileReader();
		reader.onload = () => resolve(reader.result as string);
		reader.onerror = () => reject(new Error("Failed to read file"));
		reader.readAsDataURL(file);
	});

const validateImageFile = (file: File): string | null => {
	if (file.size > MAX_IMAGE_SIZE_BYTES) {
		return `"${file.name}" must be less than 10MB.`;
	}
	return null;
};

export default function HomePage() {
	const isMobile = useIsMobile();
	const [activeView, setActiveView] = useState<"list" | "settings">("list");
	const [events, setEvents] = useState<CalendarEvent[]>([]);
	const [dialogOpen, setDialogOpen] = useState(false);
	const [editingId, setEditingId] = useState<string | null>(null);
	const [dialogSource, setDialogSource] = useState<"manual" | "ai">("manual");
	const [isDragOver, setIsDragOver] = useState(false);
	const [isOnline, setIsOnline] = useState(true);

	const [dialogInitialValues, setDialogInitialValues] =
		useState<EventFormValues>(getDefaultEventFormValues());

	// AI
	const [aiPrompt, setAiPrompt] = useState("");
	const [aiLoading, setAiLoading] = useState(false);
	const [summary, setSummary] = useState<string | null>(null);
	const [summaryUpdated, setSummaryUpdated] = useState<string | null>(null);

	// Multi-image state: parallel arrays keyed by index
	// imageFiles[i]   — the File object (used for dedup key)
	// imageBase64s[i] — data URL sent to API
	// imagePreviews[i]— object URL shown in thumbnail
	const [imageFiles, setImageFiles] = useState<File[]>([]);
	const [imageBase64s, setImageBase64s] = useState<string[]>([]);
	const [imagePreviews, setImagePreviews] = useState<string[]>([]);
	const { hasLoadedSettings, settings, updateSettings } = useUserSettings();
	const adminAiEnabled = isClientAiEnabled();
	const canUseAi = adminAiEnabled && settings.aiEnabled;

	useEffect(() => {
		(async () => {
			const stored = await getAllEvents();
			setEvents(stored);
		})();
	}, []);

	useEffect(() => {
		setIsOnline(window.navigator.onLine);

		const handleOnline = () => setIsOnline(true);
		const handleOffline = () => setIsOnline(false);

		window.addEventListener("online", handleOnline);
		window.addEventListener("offline", handleOffline);

		return () => {
			window.removeEventListener("online", handleOnline);
			window.removeEventListener("offline", handleOffline);
		};
	}, []);

	const { data: session, isPending } = useSession();

	const resetForm = () => {
		setDialogInitialValues(getDefaultEventFormValues());
		setEditingId(null);
		setDialogSource("manual");
	};

	/**
	 * Adds one or more image files to the attached-images list.
	 * Validates each file, deduplicates, and updates all three parallel arrays.
	 */
	const handleImagesSelect = async (files: File[]) => {
		const validFiles: File[] = [];
		for (const file of files) {
			const error = validateImageFile(file);
			if (error) {
				toast.error(error);
			} else {
				validFiles.push(file);
			}
		}
		if (validFiles.length === 0) return;

		// Dedup against existing files
		const merged = appendImagesDeduped(imageFiles, validFiles);
		const newFiles = merged.slice(imageFiles.length); // only the newly added ones
		if (newFiles.length === 0) return; // all were duplicates

		const newBase64s = await Promise.all(newFiles.map(fileToBase64));
		const newPreviews = newFiles.map((f) => URL.createObjectURL(f));

		setImageFiles(merged);
		setImageBase64s((prev) => [...prev, ...newBase64s]);
		setImagePreviews((prev) => [...prev, ...newPreviews]);
	};

	/** Remove the image at the given index. */
	const handleImageRemove = (index: number) => {
		// Revoke the object URL before dropping it
		URL.revokeObjectURL(imagePreviews[index]);

		setImageFiles((prev) => prev.filter((_, i) => i !== index));
		setImageBase64s((prev) => prev.filter((_, i) => i !== index));
		setImagePreviews((prev) => prev.filter((_, i) => i !== index));
	};

	/** Clear all attached images. */
	const handleImagesClear = () => {
		for (const url of imagePreviews) {
			URL.revokeObjectURL(url);
		}
		setImageFiles([]);
		setImageBase64s([]);
		setImagePreviews([]);
	};

	const handleSave = async (values: EventFormValues) => {
		const eventData: CalendarEvent = {
			id: editingId || nanoid(),
			title: values.title,
			description: values.description,
			location: values.location,
			url: values.url,
			recurrenceRule: values.recurrenceRule,
			start: values.start,
			end: values.end || undefined,
			allDay: values.allDay,
			createdAt: editingId
				? events.find((e) => e.id === editingId)?.createdAt
				: new Date().toISOString(),
			lastModified: new Date().toISOString(),
		};
		if (editingId) {
			await updateEvent(eventData);
			setEvents((prev) =>
				prev.map((e) => (e.id === editingId ? eventData : e)),
			);
		} else {
			await addEvent(eventData);
			setEvents((prev) => [...prev, eventData]);
		}
		resetForm();
		setDialogOpen(false);
	};

	const handleDelete = async (id: string) => {
		await deleteEvent(id);
		setEvents((prev) => prev.filter((e) => e.id !== id));
	};

	const handleClearAll = async () => {
		await clearEvents();
		setEvents([]);
	};

	const handleImport = async (file: File) => {
		const text = await file.text();
		const parsed = parseICS(text);
		for (const ev of parsed) {
			await addEvent(ev);
		}
		const stored = await getAllEvents();
		setEvents(stored);
	};

	const handleExport = () => {
		const icsData = generateICS(events);
		const blob = new Blob([icsData], { type: "text/calendar" });
		const url = URL.createObjectURL(blob);
		const a = document.createElement("a");
		a.href = url;
		a.download = `icallocal-export-${new Date().toLocaleTimeString()}.ics`;
		document.body.appendChild(a);
		a.click();
		document.body.removeChild(a);
		URL.revokeObjectURL(url);
	};

	const populateEventForm = (ev: CalendarEvent) => {
		setDialogInitialValues(getEventFormValuesFromEvent(ev));
		setEditingId(null);
	};

	const persistAiEvents = async (data: CalendarEvent[]) => {
		for (const ev of data) {
			const newEvent: CalendarEvent = {
				...ev,
				id: nanoid(),
				createdAt: new Date().toISOString(),
				lastModified: new Date().toISOString(),
			};
			await addEvent(newEvent);
		}
		const stored = await getAllEvents();
		setEvents(stored);
	};

	const runAiCreate = async (promptOverride?: string) => {
		const nextPrompt = promptOverride?.trim() ?? aiPrompt.trim();
		if (!nextPrompt && imageBase64s.length === 0) return;
		if (!canUseAi) {
			toast.error(
				adminAiEnabled
					? "AI is turned off in Settings."
					: getAiDisabledMessage(),
			);
			return;
		}

		if (promptOverride) {
			setAiPrompt(nextPrompt);
		}

		setAiLoading(true);

		const promise = async (): Promise<{ message: string }> => {
			const originalPrompt = aiPrompt;
			if (promptOverride) {
				setAiPrompt(nextPrompt);
			}

			const res = await fetch("/api/ai-event", {
				method: "POST",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify({
					prompt: nextPrompt || undefined,
					images: imageBase64s.length > 0 ? imageBase64s : undefined,
				}),
			});

			if (res.status === 401) {
				throw new Error("Please sign in to use AI features.");
			}

			if (res.status === 403) {
				const errorBody = (await res.json()) as { error?: string };
				throw new Error(errorBody.error ?? getAiDisabledMessage());
			}

			const data = await res.json();

			if (!Array.isArray(data) || data.length === 0) {
				throw new Error("AI did not return event data.");
			}

			if (
				getAiCreateOutcome(data.length, settings.skipAiReview) ===
				"review-single"
			) {
				populateEventForm(data[0]);
				setDialogSource("ai");
				setAiPrompt("");
				setDialogOpen(true);
				handleImagesClear();
				return { message: "Draft event is ready for review." };
			}

			await persistAiEvents(data);
			setAiPrompt("");
			setSummary(
				data.length === 1
					? "Added 1 AI-generated event."
					: `Added ${data.length} AI-generated events.`,
			);
			setSummaryUpdated(new Date().toLocaleString());
			handleImagesClear();
			if (promptOverride) {
				setAiPrompt("");
			} else {
				setAiPrompt(originalPrompt);
			}
			return { message: "Events have been created!" };
		};

		toast.promise(promise, {
			loading: "Generating event...",
			success: ({ message }) => message,
			error: ({ message }) => message,
			finally: () => setAiLoading(false),
		});
	};

	const handleAiCreate = async () => {
		await runAiCreate();
	};

	// AI Summarize Events
	const handleAiSummarize = async () => {
		if (!canUseAi) {
			setSummary(
				adminAiEnabled
					? "AI is turned off in Settings."
					: getAiDisabledMessage(),
			);
			setSummaryUpdated(new Date().toLocaleString());
			return;
		}

		if (!events.length) {
			setSummary("No events to summarize.");
			setSummaryUpdated(new Date().toLocaleString());
			return;
		}
		setAiLoading(true);
		try {
			const res = await fetch("/api/ai-summary", {
				method: "POST",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify({ events }),
			});

			if (res.status === 401) {
				setSummary("Please sign in to use AI features.");
				setSummaryUpdated(new Date().toLocaleString());
				return;
			}

			if (res.status === 403) {
				const errorBody = (await res.json()) as { error?: string };
				setSummary(errorBody.error ?? getAiDisabledMessage());
				setSummaryUpdated(new Date().toLocaleString());
				return;
			}

			const data = await res.json();
			if (data.summary) {
				setSummary(data.summary);
				setSummaryUpdated(new Date().toLocaleString());
			} else {
				setSummary("No summary generated.");
				setSummaryUpdated(new Date().toLocaleString());
			}
		} catch {
			setSummary("Error summarizing events");
			setSummaryUpdated(new Date().toLocaleString());
		} finally {
			setAiLoading(false);
		}
	};

	const handleEdit = (eventData: CalendarEvent) => {
		setDialogInitialValues(getEventFormValuesFromEvent(eventData));
		setEditingId(eventData.id);
		setDialogSource("manual");
		setDialogOpen(true);
	};

	const openManualEventDialog = () => {
		resetForm();
		setDialogSource("manual");
		setActiveView("list");
		setDialogOpen(true);
	};

	const appFrameClasses = cn(
		"mx-auto flex min-h-screen w-full max-w-6xl flex-col",
		isMobile ? "px-4 pb-24 pt-4" : "px-8 py-4",
	);
	const appHeaderSurfaceClasses = getAppHeaderSurfaceClasses(isMobile);
	const headerLayoutClasses = cn(
		isMobile ? "flex-col items-start" : "items-center justify-between",
	);
	const appSectionSurfaceClasses = getAppSectionSurfaceClasses(isMobile);
	const appNavSurfaceClasses = getAppNavSurfaceClasses(isMobile);
	const mainContentClasses = "space-y-4";
	const timelineContentClasses = "space-y-4";
	const headerActionsClasses = isMobile
		? "flex w-full items-center justify-between gap-2"
		: "flex flex-wrap items-center justify-end gap-2";
	const mobileUtilityActionsClasses = "flex items-center gap-2";
	const desktopUtilityActionsClasses = "flex items-center gap-2";
	const moreTriggerLabel = isMobile ? null : "More";

	return (
		<DragDropContainer
			isDragOver={isDragOver}
			setIsDragOver={setIsDragOver}
			onImport={handleImport}
			onImageDrop={(file) => handleImagesSelect([file])}
		>
			<div className={appFrameClasses}>
				<header className={cn(appHeaderSurfaceClasses, headerLayoutClasses)}>
					<div
						className={cn(
							"flex min-w-0 flex-col",
							isMobile ? "w-full" : undefined,
						)}
					>
						<p className="font-mono text-[11px] uppercase text-muted-foreground">
							Local Calendar
						</p>
						<h1 className="truncate text-[28px] font-semibold tracking-[-0.06em]">
							Event timeline
						</h1>
					</div>
					<div className={headerActionsClasses}>
						<Badge
							variant="outline"
							className={getConnectionBadgeClasses(isOnline)}
						>
							{isOnline ? (
								<Wifi className="h-3 w-3" />
							) : (
								<WifiOff className="h-3 w-3" />
							)}
							<span>{isOnline ? "Online ready" : "Offline mode"}</span>
						</Badge>
						<div
							className={
								isMobile
									? mobileUtilityActionsClasses
									: desktopUtilityActionsClasses
							}
						>
							<SignIn />
							{!isMobile && (
								<Button
									type="button"
									variant="outline"
									size="sm"
									onClick={handleExport}
									disabled={events.length === 0}
								>
									Export
								</Button>
							)}
							<DropdownMenu>
								<DropdownMenuTrigger asChild>
									<Button
										type="button"
										variant="outline"
										size={isMobile ? "icon" : "sm"}
										aria-label="More actions"
									>
										<MoreHorizontal className="h-4 w-4" />
										{moreTriggerLabel}
									</Button>
								</DropdownMenuTrigger>
								<DropdownMenuContent align="end" className="w-48">
									{isMobile && (
										<DropdownMenuItem
											onClick={handleExport}
											disabled={events.length === 0}
										>
											Export
										</DropdownMenuItem>
									)}
									<DropdownMenuItem onClick={openManualEventDialog}>
										Manual create
									</DropdownMenuItem>
									<DropdownMenuItem onClick={() => setActiveView("settings")}>
										Settings
									</DropdownMenuItem>
									<DropdownMenuSeparator />
									<DropdownMenuItem
										variant="destructive"
										onClick={handleClearAll}
										disabled={events.length === 0}
									>
										Clear all events
									</DropdownMenuItem>
								</DropdownMenuContent>
							</DropdownMenu>
						</div>
					</div>
				</header>

				<main className="flex-1 space-y-4">
					{activeView === "settings" ? (
						<SettingsPanel
							adminAiEnabled={adminAiEnabled}
							className={appSectionSurfaceClasses}
							hasLoadedSettings={hasLoadedSettings}
							onSettingsChange={updateSettings}
							settings={settings}
						/>
					) : (
						<section className={mainContentClasses}>
							<section className={appSectionSurfaceClasses}>
								<div className="mb-4 space-y-1">
									<p className="text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground">
										AI capture
									</p>
									<h2 className="text-xl font-semibold tracking-[-0.04em]">
										Capture from text or files.
									</h2>
									<p className="text-sm leading-6 text-muted-foreground">
										Start with a prompt, screenshots, or both. Review happens in
										the timeline rather than a separate flow.
									</p>
								</div>

								<AIToolbar
									adminAiEnabled={adminAiEnabled}
									aiEnabled={settings.aiEnabled}
									isAuthenticated={!!session?.user}
									isPending={isPending}
									aiPrompt={aiPrompt}
									setAiPrompt={setAiPrompt}
									aiLoading={aiLoading}
									imagePreviews={imagePreviews}
									onImagesSelect={handleImagesSelect}
									onImageRemove={handleImageRemove}
									onAiCreate={handleAiCreate}
									onAiTemplateSelect={runAiCreate}
									onAiSummarize={handleAiSummarize}
									onSummaryDismiss={() => setSummary(null)}
									summary={summary}
									summaryUpdated={summaryUpdated}
									events={events}
								/>
							</section>

							<section className={timelineContentClasses}>
								<section className={appSectionSurfaceClasses}>
									<div className="mb-4 flex items-center justify-between gap-3">
										<div className="space-y-1">
											<p className="text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground">
												Event timeline
											</p>
											<h2 className="text-xl font-semibold tracking-[-0.04em]">
												Review the calendar by scanning the stream.
											</h2>
										</div>
										<div className="rounded-full bg-muted px-3 py-1 text-xs font-medium text-muted-foreground">
											{events.length} item{events.length === 1 ? "" : "s"}
										</div>
									</div>

									<div className={APP_ACTION_BAR_CLASSES}>
										<div className="flex flex-wrap items-center gap-2">
											<IcsFilePicker
												onFileSelect={handleImport}
												variant="outline"
												size="sm"
											>
												Import
											</IcsFilePicker>
											{events.length > 0 && (
												<Button
													type="button"
													variant="ghost"
													size="sm"
													onClick={handleClearAll}
													className="text-muted-foreground hover:text-destructive"
												>
													Clear
												</Button>
											)}
										</div>
									</div>

									<EventsList
										events={events}
										onEdit={handleEdit}
										onDelete={handleDelete}
									/>
								</section>
							</section>
						</section>
					)}
				</main>

				<nav className={appNavSurfaceClasses}>
					<Button
						type="button"
						variant="ghost"
						className={getNavButtonClasses(activeView === "list")}
						aria-pressed={activeView === "list"}
						onClick={() => setActiveView("list")}
					>
						<CalendarDays className="h-4 w-4" />
						Timeline
					</Button>
					<Button
						type="button"
						variant="ghost"
						className={getNavButtonClasses(activeView === "settings")}
						aria-pressed={activeView === "settings"}
						onClick={() => setActiveView("settings")}
					>
						<Settings className="h-4 w-4" />
						Settings
					</Button>
				</nav>
			</div>

			<EventDialog
				open={dialogOpen}
				onOpenChange={setDialogOpen}
				editingId={editingId}
				dialogSource={dialogSource}
				initialValues={dialogInitialValues}
				onSave={handleSave}
				onReset={resetForm}
			/>
		</DragDropContainer>
	);
}
