<script lang="ts">
	import { goto } from '$app/navigation';
	import { resolve } from '$app/paths';
	import { authStore } from '$lib/stores/auth.svelte';
	import { apiFetch } from '$lib/utils/api';
	import { ensureBusinessInfo, getBusinessInfo } from '$lib/stores/businessInfo.svelte';
	import { browser } from '$app/environment';
	import { toast } from 'svelte-sonner';
	import { SvelteDate } from 'svelte/reactivity';
	import { fly } from 'svelte/transition';
	import UserBookingModal from '$lib/components/account/UserBookingModal.svelte';
	import type { Booking, BookingService } from '$lib/types/booking';
	import { Button } from '$lib/components/ui/button';

	let pageState = $state<'loading' | 'authorized' | 'unauthorized'>('loading');
	let bookings = $state<Booking[]>([]);
	let loading = $state(false);
	let selectedBookingId = $state<string | null>(null);
	let showBookingModal = $state(false);
	const businessSettings = $derived(getBusinessInfo());

	$effect(() => {
		if (!browser) return;
		if (authStore.isLoading) {
			pageState = 'loading';
			return;
		}
		if (!authStore.isAuthenticated) {
			pageState = 'unauthorized';
			// eslint-disable-next-line svelte/no-navigation-without-resolve
			goto('/login', { replaceState: true });
			return;
		}
		pageState = 'authorized';
		ensureBusinessInfo();
		fetchBookings();
	});

	async function fetchBookings() {
		loading = true;
		try {
			const today = new Date().toLocaleDateString('en-CA', { timeZone: 'Europe/London' });
			const response = await apiFetch(`/api/bookings?start_date=${today}&per_page=50&page=1`, {
				headers: { 'Content-Type': 'application/json' }
			});
			if (!response.ok) {
				toast.error('Failed to load bookings');
				return;
			}
			const data = await response.json();
			const now = new SvelteDate();
			bookings = (data.bookings || [])
				.filter((b: Booking) => {
					const startTime = new SvelteDate(b.start_time);
					const endTime = new SvelteDate(startTime.getTime() + (b.duration_minutes || 0) * 60000);
					return endTime > now;
				})
				.sort(
					(a: Booking, b: Booking) =>
						new SvelteDate(a.start_time).getTime() - new SvelteDate(b.start_time).getTime()
				);
		} catch (err) {
			console.error('Error fetching bookings:', err);
			toast.error('Network error');
		} finally {
			loading = false;
		}
	}

	function openBooking(id: string) {
		selectedBookingId = id;
		showBookingModal = true;
	}

	type BookingGroup = {
		label: string;
		key: string;
		bookings: Booking[];
	};

	const bookingGroups = $derived.by(() => {
		const groups: BookingGroup[] = [];
		let currentMonth = '';
		let currentGroup: BookingGroup | null = null;
		for (const booking of bookings) {
			const monthKey = booking.start_time.slice(0, 7);
			if (monthKey !== currentMonth) {
				currentMonth = monthKey;
				const d = new SvelteDate(booking.start_time);
				const label = d.toLocaleDateString('en-GB', {
					month: 'long',
					year: 'numeric'
				});
				currentGroup = { label, key: monthKey, bookings: [] };
				groups.push(currentGroup);
			}
			currentGroup!.bookings.push(booking);
		}
		return groups;
	});

	function formatTime(iso: string): string {
		return new SvelteDate(iso).toLocaleTimeString('en-GB', {
			hour: 'numeric',
			minute: '2-digit'
		});
	}

	function formatCardDate(iso: string): string {
		return new SvelteDate(iso).toLocaleDateString('en-GB', {
			weekday: 'short',
			day: 'numeric',
			month: 'short'
		});
	}

	function formatEndTime(iso: string, durationMinutes: number): string {
		const start = new SvelteDate(iso);
		const end = new SvelteDate(start.getTime() + durationMinutes * 60000);
		return end.toLocaleTimeString('en-GB', { hour: 'numeric', minute: '2-digit' });
	}

	const totalAppointments = $derived(bookings.length);

	type StatusStyle = {
		bar: string;
		badge: string;
		dot: string;
		label: string;
	};
	const statusConfig: Record<string, StatusStyle> = {
		pending: {
			bar: 'bg-amber-500',
			badge: 'bg-amber-50 text-amber-700 border-amber-200',
			dot: 'bg-amber-500',
			label: 'Pending'
		},
		confirmed: {
			bar: 'bg-emerald-500',
			badge: 'bg-emerald-50 text-emerald-700 border-emerald-200',
			dot: 'bg-emerald-500',
			label: 'Confirmed'
		},
		in_progress: {
			bar: 'bg-blue-500',
			badge: 'bg-blue-50 text-blue-700 border-blue-200',
			dot: 'bg-blue-500',
			label: 'In Progress'
		},
		completed: {
			bar: 'bg-gray-400',
			badge: 'bg-gray-50 text-gray-600 border-gray-200',
			dot: 'bg-gray-400',
			label: 'Completed'
		},
		client_cancelled: {
			bar: 'bg-red-400',
			badge: 'bg-red-50 text-red-700 border-red-200',
			dot: 'bg-red-500',
			label: 'Cancelled'
		},
		we_cancelled: {
			bar: 'bg-red-400',
			badge: 'bg-red-50 text-red-700 border-red-200',
			dot: 'bg-red-500',
			label: 'Cancelled'
		},
		no_show: {
			bar: 'bg-gray-400',
			badge: 'bg-gray-50 text-gray-600 border-gray-200',
			dot: 'bg-gray-400',
			label: 'No Show'
		}
	};

	function getConfig(status: string): StatusStyle {
		return statusConfig[status] || statusConfig.completed;
	}
</script>

<svelte:head>
	<script>
		(function () {
			// Pre-hydration auth guard: reads localStorage directly because the Svelte
			// authStore hasn't initialized yet at this point (async+$state). This runs
			// synchronously before any rendering, preventing a flash of protected content.
			// The authStore handles post-hydration auth.
			try {
				var token = localStorage.getItem('authToken');
				if (!token) {
					window.location.replace('/login');
					return;
				}
				var payload = JSON.parse(atob(token.split('.')[1]));
				if (payload.exp * 1000 <= Date.now()) {
					window.location.replace('/login');
				}
			} catch (e) {
				window.location.replace('/login');
			}
		})();
	</script>
</svelte:head>

{#if pageState === 'loading'}
	<div class="mx-auto max-w-4xl px-4 py-8 md:px-8 md:py-12">
		<div class="animate-pulse space-y-6">
			<div class="h-8 w-44 rounded-lg bg-gray-200"></div>
			<div class="h-4 w-64 rounded bg-gray-200"></div>
			<div class="space-y-4 pt-2">
				{#each Array(3) as _, i (i)}
					<div class="rounded-xl border bg-white p-5 shadow-sm">
						<div class="mb-3 flex items-center gap-3">
							<div class="h-4 w-24 rounded bg-gray-200"></div>
							<div class="h-6 w-20 rounded-full bg-gray-100"></div>
						</div>
						<div class="mb-3 h-4 w-48 rounded bg-gray-200"></div>
						<div class="flex items-center justify-between">
							<div class="h-5 w-16 rounded bg-gray-200"></div>
							<div class="h-4 w-16 rounded bg-gray-100"></div>
						</div>
					</div>
				{/each}
			</div>
		</div>
	</div>
{:else if pageState === 'unauthorized'}
	<div class="mx-auto max-w-4xl px-4 py-16 text-center md:px-8">
		<p class="text-gray-500">Please log in to view your schedule.</p>
	</div>
{:else}
	<div class="mx-auto max-w-4xl px-4 py-8 md:px-8 md:py-12">
		<div class="mb-10 text-center">
			<h1 class="font-['Playfair_Display'] text-4xl font-bold text-gray-900">My Schedule</h1>
			<p class="mt-2 text-sm text-gray-500 md:text-base">
				{totalAppointments === 0
					? 'No upcoming appointments'
					: `You have ${totalAppointments} upcoming visit${totalAppointments === 1 ? '' : 's'}`}
			</p>
		</div>

		{#if loading}
			<div class="space-y-6">
				{#each Array(3) as _, i (i)}
					<div class="animate-pulse rounded-xl border bg-white p-5 shadow-sm">
						<div class="mb-3 flex items-center gap-3">
							<div class="h-4 w-24 rounded bg-gray-200"></div>
							<div class="h-6 w-20 rounded-full bg-gray-100"></div>
						</div>
						<div class="mb-3 h-4 w-48 rounded bg-gray-200"></div>
						<div class="flex items-center justify-between">
							<div class="h-5 w-16 rounded bg-gray-200"></div>
							<div class="h-4 w-16 rounded bg-gray-100"></div>
						</div>
					</div>
				{/each}
			</div>
		{:else if bookings.length === 0}
			<div class="rounded-xl border border-dashed border-gray-200 bg-gray-50/50 py-16 text-center">
				<div
					class="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-gray-100"
				>
					<svg
						class="h-8 w-8 text-gray-400"
						fill="none"
						viewBox="0 0 24 24"
						stroke="currentColor"
						stroke-width="1.5"
					>
						<path
							stroke-linecap="round"
							stroke-linejoin="round"
							d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
						/>
					</svg>
				</div>
				<h3 class="mb-1 text-lg font-semibold text-gray-900">No Upcoming Appointments</h3>
				<p class="mb-6 text-sm text-gray-500">
					You don't have any upcoming appointments scheduled.
				</p>
				<Button href={resolve('/book')}>Book an Appointment</Button>
			</div>
		{:else}
			<div class="space-y-10">
				{#each bookingGroups as group (group.key)}
					<section>
						<div class="mb-5 flex items-center gap-4">
							<h2 class="text-base font-bold text-gray-700">
								{group.label}
							</h2>
							<div class="h-px flex-1 bg-gray-200"></div>
						</div>

						<div class="space-y-4">
							{#each group.bookings as booking (booking.id)}
								{@const cfg = getConfig(booking.status)}
								{@const serviceNames =
									booking.services
										?.map((s: BookingService) => s.service_name)
										.filter(Boolean)
										.join(', ') || ''}

								<div
									in:fly={{ y: 12, duration: 300, delay: 50 }}
									class="group/card relative overflow-hidden rounded-xl border bg-white shadow-sm transition-all duration-200 hover:shadow-md"
								>
									<div class="absolute top-0 left-0 h-full w-1 {cfg.bar}"></div>

									<div class="pt-4 pr-5 pb-4 pl-5 md:pt-5 md:pr-6 md:pb-5 md:pl-6">
										<div class="mb-3 flex items-start justify-between gap-3 md:mb-3">
											<div class="flex items-center gap-2">
												<svg
													class="h-4 w-4 shrink-0 text-gray-400"
													fill="none"
													viewBox="0 0 24 24"
													stroke="currentColor"
													stroke-width="2"
												>
													<path
														stroke-linecap="round"
														stroke-linejoin="round"
														d="M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z"
													/>
												</svg>
												<span class="text-sm text-gray-500">
													{formatCardDate(booking.start_time)}
												</span>
												<span class="text-base font-semibold text-gray-900 md:text-lg">
													{formatTime(booking.start_time)}
													–
													{formatEndTime(booking.start_time, booking.duration_minutes || 0)}
												</span>
												{#if booking.duration_minutes}
													<span class="text-sm text-gray-400">· {booking.duration_minutes} min</span
													>
												{/if}
											</div>
											<span
												class="inline-flex shrink-0 items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs leading-none font-medium {cfg.badge}"
											>
												<span class="h-1.5 w-1.5 rounded-full {cfg.dot}"></span>
												{cfg.label}
											</span>
										</div>

										<div class="mb-3 h-px bg-gray-100 md:mb-4"></div>

										<div>
											{#if booking.services && booking.services.length > 0}
												<p class="font-medium text-gray-900">{serviceNames}</p>
											{/if}

											<div
												class="{booking.services && booking.services.length > 0
													? 'mt-3 md:mt-4'
													: ''} flex items-center justify-between"
											>
												{#if booking.total_amount}
													<span class="text-lg font-bold text-gray-900">
														£{booking.total_amount.toFixed(2)}
														{#if businessSettings?.is_vat_registered}
															<span class="text-xs font-normal text-gray-400"> incl. VAT</span>
														{/if}
													</span>
												{:else}
													<span></span>
												{/if}

												<button
													onclick={() => openBooking(booking.id)}
													class="inline-flex items-center gap-1 rounded-lg px-2.5 py-1.5 text-sm font-medium text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-900"
												>
													Details
													<svg
														class="h-4 w-4"
														fill="none"
														viewBox="0 0 24 24"
														stroke="currentColor"
														stroke-width="2"
													>
														<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7" />
													</svg>
												</button>
											</div>
										</div>
									</div>
								</div>
							{/each}
						</div>
					</section>
				{/each}
			</div>
		{/if}
	</div>
{/if}

<UserBookingModal bind:open={showBookingModal} bookingId={selectedBookingId || ''} />
