<script lang="ts">
	import { getContext, onMount, onDestroy } from "svelte";
	import { createLogger } from "$lib/utils/logger";
	import {
		Button,
		Modal,
		Avatar,
		ContextMenu,
		Input,
		Textarea,
	} from "$lib/components/ui";
	import { Calendar } from "$lib/components/calendar";
	import {
		getCalendarSubscribeUrl,
		type GoogleCalendarEvent,
	} from "$lib/api/google-calendar";
	import type { CalendarEvent } from "$lib/supabase/types";
	import type { SupabaseClient } from "@supabase/supabase-js";
	import type { Database } from "$lib/supabase/types";
	import * as m from "$lib/paraglide/messages";

	interface Props {
		data: {
			org: { id: string; name: string; slug: string };
			events: CalendarEvent[];
			user: { id: string } | null;
			userRole?: string;
		};
	}

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

	const supabase = getContext<SupabaseClient<Database>>("supabase");
	const log = createLogger("page.calendar");

	// svelte-ignore state_referenced_locally
	let events = $state(data.events);
	$effect(() => {
		events = data.events;
	});
	let googleEvents = $state<CalendarEvent[]>([]);
	let isOrgCalendarConnected = $state(false);
	let isLoadingGoogle = $state(false);
	let orgCalendarId = $state<string | null>(null);
	let orgCalendarName = $state<string | null>(null);
	// Track Google event IDs that are pending deletion to prevent ghost re-appearance
	let deletedGoogleEventIds = $state<Set<string>>(new Set());

	const isAdmin = $derived(
		data.userRole === "owner" || data.userRole === "admin",
	);

	// Deduplicate: exclude Google Calendar events that already exist locally (synced events)
	// Also exclude events that are pending deletion
	const allEvents = $derived.by(() => {
		const localGoogleIds = new Set(
			events
				.filter((e) => e.google_event_id)
				.map((e) => e.google_event_id),
		);
		const filteredGoogle = googleEvents.filter((ge) => {
			const rawId = ge.id.replace("google-", "");
			if (localGoogleIds.has(rawId)) return false;
			if (deletedGoogleEventIds.has(rawId)) return false;
			return true;
		});
		return [...events, ...filteredGoogle];
	});
	let showEventModal = $state(false);
	let showEventFormModal = $state(false);
	let eventFormMode = $state<"create" | "edit">("create");
	let isDeleting = $state(false);
	let isSavingEvent = $state(false);
	let selectedEvent = $state<CalendarEvent | null>(null);

	// Event form state
	let eventTitle = $state("");
	let eventDescription = $state("");
	let eventDate = $state("");
	let eventStartTime = $state("09:00");
	let eventEndTime = $state("10:00");
	let eventAllDay = $state(false);
	let eventColor = $state("#7986cb");
	let syncToGoogleCal = $state(true);

	// Google Calendar official event colors (colorId → hex)
	const GCAL_COLORS: Record<string, string> = {
		"1": "#7986cb", // Lavender
		"2": "#33b679", // Sage
		"3": "#8e24aa", // Grape
		"4": "#e67c73", // Flamingo
		"5": "#f6bf26", // Banana
		"6": "#f4511e", // Tangerine
		"7": "#039be5", // Peacock
		"8": "#616161", // Graphite
		"9": "#3f51b5", // Blueberry
		"10": "#0b8043", // Basil
		"11": "#d50000", // Tomato
	};

	// Reverse map: hex → colorId (for pushing to Google)
	const HEX_TO_COLOR_ID: Record<string, string> = Object.fromEntries(
		Object.entries(GCAL_COLORS).map(([id, hex]) => [hex, id]),
	);

	const EVENT_COLORS = Object.values(GCAL_COLORS);

	function toLocalDateString(date: Date): string {
		const y = date.getFullYear();
		const m = String(date.getMonth() + 1).padStart(2, "0");
		const d = String(date.getDate()).padStart(2, "0");
		return `${y}-${m}-${d}`;
	}

	function handleDateClick(date: Date) {
		eventFormMode = "create";
		eventTitle = "";
		eventDescription = "";
		eventDate = toLocalDateString(date);
		eventStartTime = "09:00";
		eventEndTime = "10:00";
		eventAllDay = false;
		eventColor = "#7986cb";
		syncToGoogleCal = isOrgCalendarConnected;
		showEventFormModal = true;
	}

	function handleEventClick(event: CalendarEvent) {
		selectedEvent = event;
		showEventModal = true;
	}

	function openEditEvent() {
		if (!selectedEvent || selectedEvent.id.startsWith("google-")) return;
		eventFormMode = "edit";
		eventTitle = selectedEvent.title;
		eventDescription = selectedEvent.description ?? "";
		const start = new Date(selectedEvent.start_time);
		const end = new Date(selectedEvent.end_time);
		eventDate = toLocalDateString(start);
		eventStartTime = start.toTimeString().slice(0, 5);
		eventEndTime = end.toTimeString().slice(0, 5);
		eventAllDay = selectedEvent.all_day ?? false;
		eventColor = selectedEvent.color ?? "#7986cb";
		showEventModal = false;
		showEventFormModal = true;
	}

	/**
	 * Push event to Google Calendar in the background.
	 * Does not block the UI — updates google_event_id on success.
	 */
	async function syncToGoogle(
		action: "create" | "update" | "delete",
		eventData: {
			id?: string;
			google_event_id?: string | null;
			title?: string;
			description?: string | null;
			start_time?: string;
			end_time?: string;
			all_day?: boolean;
			color?: string;
		},
	) {
		const colorId = eventData.color
			? (HEX_TO_COLOR_ID[eventData.color] ?? undefined)
			: undefined;

		try {
			if (action === "create") {
				const res = await fetch("/api/google-calendar/push", {
					method: "POST",
					headers: { "Content-Type": "application/json" },
					body: JSON.stringify({
						org_id: data.org.id,
						title: eventData.title,
						description: eventData.description,
						start_time: eventData.start_time,
						end_time: eventData.end_time,
						all_day: eventData.all_day,
						color_id: colorId,
					}),
				});
				if (res.ok) {
					const { google_event_id } = await res.json();
					if (google_event_id && eventData.id) {
						// Store the Google event ID back to Supabase
						await supabase
							.from("calendar_events")
							.update({
								google_event_id,
								synced_at: new Date().toISOString(),
							})
							.eq("id", eventData.id);
						// Update local state
						events = events.map((e) =>
							e.id === eventData.id
								? {
										...e,
										google_event_id,
										synced_at: new Date().toISOString(),
									}
								: e,
						);
					}
				}
			} else if (action === "update" && eventData.google_event_id) {
				await fetch("/api/google-calendar/push", {
					method: "PUT",
					headers: { "Content-Type": "application/json" },
					body: JSON.stringify({
						org_id: data.org.id,
						google_event_id: eventData.google_event_id,
						title: eventData.title,
						description: eventData.description,
						start_time: eventData.start_time,
						end_time: eventData.end_time,
						all_day: eventData.all_day,
						color_id: colorId,
					}),
				});
			} else if (action === "delete" && eventData.google_event_id) {
				await fetch("/api/google-calendar/push", {
					method: "DELETE",
					headers: { "Content-Type": "application/json" },
					body: JSON.stringify({
						org_id: data.org.id,
						google_event_id: eventData.google_event_id,
					}),
				});
			}
		} catch (e) {
			log.error("Google Calendar sync failed", {
				error: e,
				data: { action },
			});
		}
	}

	async function handleSaveEvent() {
		if (!eventTitle.trim() || !eventDate) return;
		isSavingEvent = true;

		const startTime = eventAllDay
			? `${eventDate}T00:00:00`
			: `${eventDate}T${eventStartTime}:00`;
		const endTime = eventAllDay
			? `${eventDate}T23:59:59`
			: `${eventDate}T${eventEndTime}:00`;

		if (eventFormMode === "edit" && selectedEvent) {
			const { error } = await supabase
				.from("calendar_events")
				.update({
					title: eventTitle.trim(),
					description: eventDescription.trim() || null,
					start_time: startTime,
					end_time: endTime,
					all_day: eventAllDay,
					color: eventColor,
				})
				.eq("id", selectedEvent.id);

			if (!error) {
				events = events.map((e) =>
					e.id === selectedEvent!.id
						? {
								...e,
								title: eventTitle.trim(),
								description: eventDescription.trim() || null,
								start_time: startTime,
								end_time: endTime,
								all_day: eventAllDay,
								color: eventColor,
							}
						: e,
				);
				// Push update to Google Calendar in background
				syncToGoogle("update", {
					google_event_id: selectedEvent.google_event_id,
					title: eventTitle.trim(),
					description: eventDescription.trim() || null,
					start_time: startTime,
					end_time: endTime,
					all_day: eventAllDay,
					color: eventColor,
				});
			}
		} else {
			const { data: newEvent, error } = await supabase
				.from("calendar_events")
				.insert({
					org_id: data.org.id,
					title: eventTitle.trim(),
					description: eventDescription.trim() || null,
					start_time: startTime,
					end_time: endTime,
					all_day: eventAllDay,
					color: eventColor,
					created_by: data.user?.id,
				})
				.select()
				.single();

			if (!error && newEvent) {
				events = [...events, newEvent as CalendarEvent];
				// Push new event to Google Calendar if sync is enabled
				if (syncToGoogleCal && isOrgCalendarConnected) {
					syncToGoogle("create", {
						id: newEvent.id,
						title: eventTitle.trim(),
						description: eventDescription.trim() || null,
						start_time: startTime,
						end_time: endTime,
						all_day: eventAllDay,
						color: eventColor,
					});
				}
			}
		}

		showEventFormModal = false;
		selectedEvent = null;
		isSavingEvent = false;
	}

	async function handleDeleteEvent() {
		if (!selectedEvent || selectedEvent.id.startsWith("google-")) return;

		isDeleting = true;
		try {
			const googleEventId = selectedEvent.google_event_id;
			const { error } = await supabase
				.from("calendar_events")
				.delete()
				.eq("id", selectedEvent.id);

			if (!error) {
				events = events.filter((e) => e.id !== selectedEvent?.id);
				if (googleEventId) {
					// Immediately exclude from Google events display
					deletedGoogleEventIds = new Set([
						...deletedGoogleEventIds,
						googleEventId,
					]);
					googleEvents = googleEvents.filter(
						(ge) => ge.id !== `google-${googleEventId}`,
					);
					// Await Google delete so it completes before any refresh
					await syncToGoogle("delete", {
						google_event_id: googleEventId,
					});
				}
				showEventModal = false;
				selectedEvent = null;
			}
		} catch (e) {
			log.error("Failed to delete event", { error: e });
		}
		isDeleting = false;
	}

	function formatEventTime(event: CalendarEvent): string {
		if (event.all_day) return "All day";
		const start = new Date(event.start_time);
		const end = new Date(event.end_time);
		return `${start.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })} - ${end.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}`;
	}

	let pollInterval: ReturnType<typeof setInterval> | null = null;

	function handleWindowFocus() {
		if (isOrgCalendarConnected) {
			loadGoogleCalendarEvents();
		}
	}

	onMount(async () => {
		await loadGoogleCalendarEvents();

		// Re-fetch when user returns to the tab (e.g. after editing in Google Calendar)
		window.addEventListener("focus", handleWindowFocus);

		// Poll every 60s for changes made in Google Calendar
		pollInterval = setInterval(() => {
			if (isOrgCalendarConnected && !document.hidden) {
				loadGoogleCalendarEvents();
			}
		}, 60_000);
	});

	onDestroy(() => {
		if (typeof window !== "undefined") {
			window.removeEventListener("focus", handleWindowFocus);
		}
		if (pollInterval) clearInterval(pollInterval);
	});

	async function loadGoogleCalendarEvents() {
		isLoadingGoogle = true;
		try {
			const res = await fetch(
				`/api/google-calendar/events?org_id=${data.org.id}`,
			);
			const result = await res.json();

			// Check if calendar is connected (even if no events)
			if (res.ok && result.calendar_id) {
				isOrgCalendarConnected = true;
				orgCalendarId = result.calendar_id;
				orgCalendarName = result.calendar_name;

				const fetchedEvents = result.events ?? [];
				googleEvents = fetchedEvents.map((ge: GoogleCalendarEvent) => ({
					id: `google-${ge.id}`,
					org_id: data.org.id,
					title: ge.summary || "(No title)",
					description: ge.description ?? null,
					start_time:
						ge.start.dateTime || `${ge.start.date}T00:00:00`,
					end_time: ge.end.dateTime || `${ge.end.date}T23:59:59`,
					all_day: !ge.start.dateTime,
					color: ge.colorId
						? (GCAL_COLORS[ge.colorId] ?? "#7986cb")
						: "#7986cb",
					recurrence: null,
					created_by: data.user?.id ?? "",
					created_at: new Date().toISOString(),
				})) as CalendarEvent[];
				// Clear deleted IDs that Google has confirmed are gone
				const fetchedIds = new Set(
					fetchedEvents.map((ge: GoogleCalendarEvent) => ge.id),
				);
				deletedGoogleEventIds = new Set(
					[...deletedGoogleEventIds].filter((id) =>
						fetchedIds.has(id),
					),
				);
			} else if (result.error) {
				log.error("Calendar API error", { error: result.error });
			}
		} catch (e) {
			log.error("Failed to load Google events", { error: e });
		}
		isLoadingGoogle = false;
	}

	function subscribeToCalendar() {
		if (!orgCalendarId) return;
		const url = getCalendarSubscribeUrl(orgCalendarId);
		window.open(url, "_blank");
	}
</script>

<svelte:head>
	<title>Calendar - {data.org.name} | Root</title>
</svelte:head>

<div class="flex flex-col h-full">
	<!-- Toolbar -->
	<div class="flex items-center gap-2 px-6 py-3 border-b border-light/5 shrink-0">
		<div class="flex-1"></div>
		<Button size="sm" onclick={() => handleDateClick(new Date())}
			>{m.btn_new()}</Button
		>
		<ContextMenu
			items={[
				...(isOrgCalendarConnected
					? [
							{
								label: m.calendar_subscribe(),
								icon: "add",
								onclick: subscribeToCalendar,
							},
						]
					: []),
				{
					label: m.calendar_refresh(),
					icon: "refresh",
					onclick: () => {
						loadGoogleCalendarEvents();
					},
				},
				...(isAdmin
					? [
							{
								label: "",
								icon: "",
								onclick: () => {},
								divider: true,
							},
							{
								label: m.calendar_settings(),
								icon: "settings",
								onclick: () => {
									window.location.href = `/${data.org.slug}/settings?tab=integrations`;
								},
							},
						]
					: []),
			]}
		/>
	</div>

	<!-- Calendar Grid -->
	<div class="flex-1 overflow-auto p-4">
		<Calendar
			events={allEvents}
			onDateClick={handleDateClick}
			onEventClick={handleEventClick}
		/>
	</div>
</div>

<Modal
	isOpen={showEventModal}
	onClose={() => (showEventModal = false)}
	title={selectedEvent?.title ?? "Event"}
>
	{#if selectedEvent}
		<div class="space-y-4">
			<!-- Date and Time -->
			<div class="flex items-start gap-3">
				<div
					class="w-8 h-8 rounded-lg bg-light/10 flex items-center justify-center flex-shrink-0"
				>
					<svg
						class="w-4 h-4 text-light/70"
						viewBox="0 0 24 24"
						fill="none"
						stroke="currentColor"
						stroke-width="2"
					>
						<rect
							x="3"
							y="4"
							width="18"
							height="18"
							rx="2"
							ry="2"
						/>
						<line x1="16" y1="2" x2="16" y2="6" />
						<line x1="8" y1="2" x2="8" y2="6" />
						<line x1="3" y1="10" x2="21" y2="10" />
					</svg>
				</div>
				<div>
					<p class="text-light font-medium">
						{new Date(selectedEvent.start_time).toLocaleDateString(
							undefined,
							{
								weekday: "long",
								year: "numeric",
								month: "long",
								day: "numeric",
							},
						)}
					</p>
					<p class="text-light/60 text-sm">
						{formatEventTime(selectedEvent)}
					</p>
				</div>
			</div>

			<!-- Description -->
			{#if selectedEvent.description}
				<div class="flex items-start gap-3">
					<div
						class="w-8 h-8 rounded-lg bg-light/10 flex items-center justify-center flex-shrink-0"
					>
						<svg
							class="w-4 h-4 text-light/70"
							viewBox="0 0 24 24"
							fill="none"
							stroke="currentColor"
							stroke-width="2"
						>
							<line x1="17" y1="10" x2="3" y2="10" />
							<line x1="21" y1="6" x2="3" y2="6" />
							<line x1="21" y1="14" x2="3" y2="14" />
							<line x1="17" y1="18" x2="3" y2="18" />
						</svg>
					</div>
					<p class="text-light/80 text-sm whitespace-pre-wrap">
						{selectedEvent.description}
					</p>
				</div>
			{/if}

			<!-- Color indicator -->
			<div class="flex items-center gap-3">
				<div
					class="w-8 h-8 rounded-lg bg-light/10 flex items-center justify-center flex-shrink-0"
				>
					<div
						class="w-4 h-4 rounded-full"
						style="background-color: {selectedEvent.color ??
							'#6366f1'}"
					></div>
				</div>
				<span class="text-light/60 text-sm">
					{selectedEvent.id.startsWith("google-")
						? "Google Calendar Event"
						: selectedEvent.google_event_id
							? "Synced to Google Calendar"
							: "Local Event"}
				</span>
			</div>

			<!-- Google Calendar link -->
			{#if (selectedEvent.id.startsWith("google-") ? selectedEvent.id.replace("google-", "") : selectedEvent.google_event_id) && orgCalendarId}
				{@const googleId = selectedEvent.id.startsWith("google-")
					? selectedEvent.id.replace("google-", "")
					: selectedEvent.google_event_id}
				<div class="pt-3 border-t border-light/10">
					<a
						href="https://calendar.google.com/calendar/u/0/r/eventedit/{googleId}?cid={encodeURIComponent(
							orgCalendarId,
						)}"
						target="_blank"
						rel="noopener noreferrer"
						class="inline-flex items-center gap-2 px-4 py-2 text-sm bg-blue-500/20 text-blue-400 rounded-lg hover:bg-blue-500/30 transition-colors"
					>
						<svg class="w-4 h-4" viewBox="0 0 24 24">
							<path
								fill="currentColor"
								d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
							/>
							<path
								fill="currentColor"
								d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
							/>
							<path
								fill="currentColor"
								d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
							/>
							<path
								fill="currentColor"
								d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
							/>
						</svg>
						Open in Google Calendar
					</a>
				</div>
			{/if}

			<!-- Edit/Delete local event -->
			{#if !selectedEvent.id.startsWith("google-")}
				<div
					class="pt-3 border-t border-light/10 flex items-center justify-between"
				>
					<Button
						variant="danger"
						onclick={handleDeleteEvent}
						loading={isDeleting}
					>
						Delete Event
					</Button>
					<Button onclick={openEditEvent}>Edit Event</Button>
				</div>
			{/if}
		</div>
	{/if}
</Modal>

<!-- Event Create/Edit Form Modal -->
<Modal
	isOpen={showEventFormModal}
	onClose={() => (showEventFormModal = false)}
	title={eventFormMode === "edit"
		? m.calendar_edit_event()
		: m.calendar_create_event()}
>
	<div class="space-y-4">
		<Input
			label={m.calendar_event_title()}
			bind:value={eventTitle}
			placeholder={m.calendar_event_title_placeholder()}
		/>

		<Input
			type="date"
			label={m.calendar_event_date()}
			bind:value={eventDate}
		/>

		<label
			class="flex items-center gap-2 text-sm text-light cursor-pointer"
		>
			<input type="checkbox" bind:checked={eventAllDay} class="rounded" />
			All day event
		</label>

		{#if !eventAllDay}
			<div class="grid grid-cols-2 gap-3">
				<div class="flex flex-col gap-1">
					<span class="px-3 font-bold font-body text-body text-white"
						>Start</span
					>
					<input
						type="time"
						class="w-full p-3 bg-background text-white rounded-[32px] font-medium font-input text-body focus:outline-none focus:ring-2 focus:ring-primary"
						bind:value={eventStartTime}
					/>
				</div>
				<div class="flex flex-col gap-1">
					<span class="px-3 font-bold font-body text-body text-white"
						>End</span
					>
					<input
						type="time"
						class="w-full p-3 bg-background text-white rounded-[32px] font-medium font-input text-body focus:outline-none focus:ring-2 focus:ring-primary"
						bind:value={eventEndTime}
					/>
				</div>
			</div>
		{/if}

		<Textarea
			label={m.calendar_event_desc()}
			bind:value={eventDescription}
			placeholder="Add a description..."
			rows={3}
		/>

		<div>
			<span class="block text-sm font-medium text-light mb-2">Color</span>
			<div class="flex gap-2">
				{#each EVENT_COLORS as color}
					<button
						type="button"
						class="w-7 h-7 rounded-full transition-transform {eventColor ===
						color
							? 'ring-2 ring-white scale-110'
							: ''}"
						style="background-color: {color}"
						onclick={() => (eventColor = color)}
						aria-label="Color {color}"
					></button>
				{/each}
			</div>
		</div>

		{#if isOrgCalendarConnected && eventFormMode === "create"}
			<label
				class="flex items-center gap-3 text-sm text-light cursor-pointer p-3 rounded-lg bg-light/5 border border-light/10"
			>
				<input
					type="checkbox"
					bind:checked={syncToGoogleCal}
					class="rounded"
				/>
				<div class="flex items-center gap-2">
					<svg class="w-4 h-4 text-blue-400" viewBox="0 0 24 24">
						<path
							fill="currentColor"
							d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
						/>
						<path
							fill="currentColor"
							d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
						/>
						<path
							fill="currentColor"
							d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
						/>
						<path
							fill="currentColor"
							d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
						/>
					</svg>
					<span>Sync to Google Calendar</span>
				</div>
			</label>
		{/if}

		<div class="flex justify-end gap-2 pt-2">
			<Button
				variant="tertiary"
				onclick={() => (showEventFormModal = false)}
				>{m.btn_cancel()}</Button
			>
			<Button
				onclick={handleSaveEvent}
				loading={isSavingEvent}
				disabled={!eventTitle.trim() || !eventDate}
				>{eventFormMode === "edit"
					? m.btn_save()
					: m.btn_create()}</Button
			>
		</div>
	</div>
</Modal>
