<script lang="ts">
	import { SvelteDate } from 'svelte/reactivity';
	import { onMount } from 'svelte';
	import { fly } from 'svelte/transition';
	import { cubicOut } from 'svelte/easing';
	import { browser } from '$app/environment';
	import { authStore } from '$lib/stores/auth.svelte';
	import { apiFetch } from '$lib/utils/api';
	import { Skeleton } from '$lib/components/ui/skeleton';
	import { Button } from '$lib/components/ui/button';
	import { Checkbox } from '$lib/components/ui/checkbox';
	import ApprovalModal from '$lib/components/admin/ApprovalModal.svelte';
	import BookingModal from '$lib/components/admin/BookingModal.svelte';
	import UserModal from '$lib/components/admin/UserModal.svelte';
	import EditRequestModal from '$lib/components/admin/EditRequestModal.svelte';
	import { toast } from 'svelte-sonner';
	import type { Booking } from '$lib/types/booking';

	interface Notification {
		id: number;
		reason: string;
		booking_id?: string;
		user_id?: string;
		user_name?: string;
		booking_start_time?: string;
		acknowledged_at?: string;
		created_at: string;
	}

	interface ServiceItem {
		id: string;
		name: string;
		price: number;
		duration_minutes: number;
	}

	interface EditRequest {
		id: string;
		booking_id: string;
		requested_by: string;
		requested_at: string;
		notes: string | null;
		original: {
			start_time: string;
			end_time: string;
			services: ServiceItem[];
			notes: string;
		};
		proposed: {
			start_time: string | null;
			end_time: string | null;
			services: ServiceItem[];
			notes: string | null;
		};
		user: {
			id: string;
			full_name: string;
			email: string;
			phone: string;
		};
	}

	let notifications = $state<Notification[]>([]);
	let loading = $state(true);
	let error = $state(false);
	let page = $state(1);
	const perPage = $state(20);
	let total = $state(0);
	let includeAcknowledged = $state(false);

	let showApprovalModal = $state(false);
	let selectedBooking = $state<Booking | null>(null);
	let showBookingModal = $state(false);
	let showUserModal = $state(false);
	let selectedUserId = $state<string | null>(null);

	let showEditRequestModal = $state(false);
	let selectedEditRequest = $state<EditRequest | null>(null);

	function openBookingModal(bookingId: string) {
		selectedBooking = { id: bookingId } as Booking;
		showBookingModal = true;
	}

	let pageState = $state<'loading' | 'authorized' | 'unauthorized'>('loading');

	$effect(() => {
		if (!browser) return;
		if (authStore.isLoading) {
			pageState = 'loading';
			return;
		}
		if (!authStore.isAuthenticated || authStore.currentUser?.role !== 'admin') {
			pageState = 'unauthorized';
			return;
		}
		pageState = 'authorized';
	});

	const reasonLabels: Record<string, string> = {
		pending_booking: 'Booking Pending Approval',
		edit_request: 'Customer Requested Booking Change',
		edit_requested: 'Booking Edit/Reschedule Requested',
		new_booking: 'New Booking Received',
		cancelled_booking: 'Booking Cancelled',
		late_cancellation: 'Late Cancellation (< 24h)',
		deposit_paid: 'Deposit Payment Received',
		deposit_not_paid_by_deadline: 'Deposit Deadline Passed',
		affiliate_claim: 'Affiliate Referral Claimed',
		'1_month_no_pay': 'No Payments in 1 Month',
		'1_week_no_pay': 'No Payments in 1 Week'
	};

	function hasAction(reason: string): string | null {
		switch (reason) {
			case 'pending_booking':
				return 'approve';
			case 'edit_request':
			case 'new_booking':
				return 'view';
			case 'edit_requested':
				return 'edit_approve';
			case 'late_cancellation':
			case 'deposit_not_paid_by_deadline':
			case '1_week_no_pay':
			case '1_month_no_pay':
				return 'see_user';
			default:
				return null;
		}
	}

	async function fetchNotifications() {
		loading = true;
		error = false;
		try {
			const params = new URLSearchParams({
				page: page.toString(),
				per_page: perPage.toString(),
				include_acknowledged: includeAcknowledged.toString()
			});
			const response = await apiFetch(`/api/admin/notifications?${params}`);
			if (!response.ok) {
				throw new Error(`Failed: ${response.status}`);
			}
			const data = await response.json();
			notifications = data.notifications;
			total = data.total;
		} catch {
			error = true;
		} finally {
			loading = false;
		}
	}

	async function fetchBookingDetails(bookingId: string): Promise<Booking | null> {
		const response = await apiFetch(`/api/admin/bookings/${bookingId}`);
		if (!response.ok) return null;
		return response.json();
	}

	async function handleAction(notification: Notification) {
		if (!notification.acknowledged_at) {
			await apiFetch(`/api/admin/notifications/${notification.id}/acknowledge`, {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' }
			});
		}

		const action = hasAction(notification.reason);
		if (action === 'approve' && notification.booking_id) {
			const booking = await fetchBookingDetails(notification.booking_id);
			if (booking) {
				selectedBooking = booking;
				showApprovalModal = true;
			} else {
				toast.error('Could not load booking details');
			}
		} else if (action === 'view' && notification.booking_id) {
			const booking = await fetchBookingDetails(notification.booking_id);
			if (booking) {
				selectedBooking = booking;
				showBookingModal = true;
			} else {
				toast.error('Could not load booking details');
			}
		} else if (action === 'edit_approve' && notification.booking_id) {
			try {
				const response = await apiFetch(
					`/api/admin/bookings/${notification.booking_id}/edit-request`
				);
				if (response.ok) {
					const data = await response.json();
					selectedEditRequest = data.edit_request;
					showEditRequestModal = true;
				} else if (response.status === 404) {
					toast.error('This edit/reschedule request has already been processed');
				} else {
					toast.error('Could not load edit/reschedule request details');
				}
			} catch (err) {
				console.error('Error fetching edit request:', err);
				toast.error('Network error loading edit/reschedule request');
			}
		} else if (action === 'see_user' && notification.user_id) {
			selectedUserId = notification.user_id;
			showUserModal = true;
		}
	}

	async function handleAcknowledge(notification: Notification) {
		try {
			const response = await apiFetch(`/api/admin/notifications/${notification.id}/acknowledge`, {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' }
			});
			if (!response.ok) {
				toast.error('Failed to acknowledge notification');
				return;
			}
			notifications = notifications.filter((n) => n.id !== notification.id);
			total = Math.max(0, total - 1);
			if (notifications.length === 0 && page > 1) {
				page--;
				await fetchNotifications();
			}
		} catch {
			toast.error('Network error');
		}
	}

	function handleApproved() {
		showApprovalModal = false;
		selectedBooking = null;
		fetchNotifications();
	}

	function handleEditRequestAction() {
		showEditRequestModal = false;
		selectedEditRequest = null;
		fetchNotifications();
	}

	function toggleView() {
		includeAcknowledged = !includeAcknowledged;
		page = 1;
		fetchNotifications();
	}

	function prevPage() {
		if (page > 1) {
			page--;
			fetchNotifications();
		}
	}

	function nextPage() {
		if (page * perPage < total) {
			page++;
			fetchNotifications();
		}
	}

	function formatRelative(iso: string): string {
		const d = new SvelteDate(iso);
		const now = new SvelteDate();
		const diffMs = now.getTime() - d.getTime();
		const diffMin = Math.floor(diffMs / 60000);
		const diffHr = Math.floor(diffMin / 60);
		const diffDay = Math.floor(diffHr / 24);
		const diffWeek = Math.floor(diffDay / 7);

		if (diffMin < 1) return 'Just now';
		if (diffMin < 60) return `${diffMin}m ago`;
		if (diffHr < 24) return `${diffHr}h ago`;
		if (diffDay < 7) return `${diffDay}d ago`;
		if (diffWeek < 5) return `${diffWeek}w ago`;
		return d.toLocaleDateString('en-GB', {
			day: 'numeric',
			month: 'short',
			year: d.getFullYear() !== now.getFullYear() ? 'numeric' : undefined
		});
	}

	function formatBookingDate(iso: string): string {
		const d = new SvelteDate(iso);
		const now = new SvelteDate();
		const today = new SvelteDate(now.getFullYear(), now.getMonth(), now.getDate());
		const tomorrow = new SvelteDate(today);
		tomorrow.setDate(tomorrow.getDate() + 1);
		const bookingDay = new SvelteDate(d.getFullYear(), d.getMonth(), d.getDate());
		const diffDays = Math.round((bookingDay.getTime() - today.getTime()) / 86400000);

		if (diffDays === 0) return 'Today';
		if (diffDays === 1) return 'Tomorrow';
		if (diffDays === -1) return 'Yesterday';
		if (diffDays > 1 && diffDays <= 6) {
			return d.toLocaleDateString('en-GB', { weekday: 'long' });
		}
		if (diffDays > 6 && diffDays <= 13) {
			return 'Next ' + d.toLocaleDateString('en-GB', { weekday: 'long' });
		}
		return d.toLocaleDateString('en-GB', {
			weekday: 'long',
			day: 'numeric',
			month: 'long',
			year: d.getFullYear() !== now.getFullYear() ? 'numeric' : undefined
		});
	}

	function getNotificationTitle(n: Notification): string {
		const base = reasonLabels[n.reason] || n.reason;
		if (n.booking_start_time) {
			return `${base} — ${formatBookingDate(n.booking_start_time)}`;
		}
		return base;
	}

	function getNotificationSubtitle(n: Notification): string {
		const parts = [formatRelative(n.created_at)];
		if (n.user_name) {
			parts.push(n.user_name);
			{
				/* TODO: add formerly name when previous name data is available */
			}
		}
		return parts.join(' — ');
	}

	const totalPages = $derived(Math.ceil(total / perPage));

	onMount(() => {
		if (pageState === 'authorized') {
			fetchNotifications();
		}
	});
</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 in <svelte:head> 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');
					return;
				}
				if (payload.role !== 'admin') {
					window.location.replace('/');
				}
			} catch (e) {
				window.location.replace('/login');
			}
		})();
	</script>
</svelte:head>

{#if pageState === 'loading'}
	<div class="mx-auto max-w-3xl space-y-4 p-6 pt-24">
		<Skeleton class="h-8 w-48" />
		{#each Array(5) as _, i (i)}
			<Skeleton class="h-24 w-full" />
		{/each}
	</div>
{:else if pageState === 'unauthorized'}
	<div class="flex min-h-screen items-center justify-center p-4">
		<div class="max-w-md text-center">
			<svg
				class="mx-auto mb-4 h-16 w-16 text-gray-400"
				fill="none"
				stroke="currentColor"
				viewBox="0 0 24 24"
			>
				<path
					stroke-linecap="round"
					stroke-linejoin="round"
					stroke-width="2"
					d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
				/>
			</svg>
			<h2 class="mb-2 text-xl font-semibold text-gray-900">Coming Soon</h2>
			<p class="text-gray-600">
				Notifications are available for admin accounts. This feature will be enabled for all users
				before launch.
			</p>
		</div>
	</div>
{:else if error}
	<div class="flex min-h-screen items-center justify-center p-4">
		<div class="max-w-md text-center">
			<h2 class="mb-2 text-xl font-semibold text-gray-900">Unable to Load Notifications</h2>
			<p class="mb-4 text-gray-600">Something went wrong. Please try again.</p>
			<Button onclick={fetchNotifications}>Retry</Button>
		</div>
	</div>
{:else}
	<div class="mx-auto max-w-3xl p-6 pt-24">
		<div class="mb-6 flex items-center justify-between">
			<h1 class="text-2xl font-semibold text-gray-900">Notifications</h1>
			<label class="flex cursor-pointer items-center gap-2 text-sm text-gray-600">
				<Checkbox checked={includeAcknowledged} onchange={toggleView} />
				Show acknowledged
			</label>
		</div>

		{#if notifications.length === 0}
			<div class="rounded-lg border border-gray-200 bg-gray-50 py-16 text-center">
				<svg
					class="mx-auto mb-3 h-12 w-12 text-gray-400"
					fill="none"
					stroke="currentColor"
					viewBox="0 0 24 24"
				>
					<path
						stroke-linecap="round"
						stroke-linejoin="round"
						stroke-width="1.5"
						d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"
					/>
				</svg>
				<p class="text-gray-500">
					{includeAcknowledged ? 'No notifications yet' : 'No unread notifications'}
				</p>
			</div>
		{:else}
			<div class="space-y-3 {loading ? 'opacity-60' : ''}">
				{#each notifications as n (n.id)}
					{@const actionable =
						!n.acknowledged_at &&
						(hasAction(n.reason) === 'approve' || hasAction(n.reason) === 'edit_approve')}
					<div
						transition:fly={{ x: 100, duration: 250, easing: cubicOut }}
						class="rounded-lg border p-4 transition-colors {n.acknowledged_at
							? 'border-gray-200 bg-gray-50'
							: actionable
								? 'border-amber-300 bg-amber-50/50'
								: 'border-gray-300 bg-white'}"
					>
						<div class="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
							<div class="min-w-0 flex-1">
								<div class="flex items-center gap-2">
									{#if !n.acknowledged_at}
										<span class="h-2 w-2 shrink-0 rounded-full bg-primary"></span>
									{/if}
									<h3 class="font-medium text-gray-900">{getNotificationTitle(n)}</h3>
								</div>
								<p class="mt-1 text-sm text-gray-500">{getNotificationSubtitle(n)}</p>
							</div>
							<div class="flex shrink-0 items-center gap-2 sm:flex-col sm:items-end">
								{#if hasAction(n.reason)}
									<Button size="sm" onclick={() => handleAction(n)}>
										{#if hasAction(n.reason) === 'approve'}
											Approve Booking
										{:else if hasAction(n.reason) === 'see_user'}
											See User
										{:else if hasAction(n.reason) === 'edit_approve'}
											Review Change
										{:else}
											See Booking
										{/if}
									</Button>
								{/if}
								{#if !n.acknowledged_at}
									<Button size="sm" variant="outline" onclick={() => handleAcknowledge(n)}>
										Acknowledge
									</Button>
								{/if}
							</div>
						</div>
					</div>
				{/each}
			</div>

			{#if totalPages > 1}
				<div class="mt-6 flex items-center justify-between">
					<p class="text-sm text-gray-500">
						{(page - 1) * perPage + 1}–{Math.min(page * perPage, total)} of {total}
					</p>
					<div class="flex gap-2">
						<Button size="sm" variant="outline" onclick={prevPage} disabled={page <= 1}>
							Previous
						</Button>
						<Button
							size="sm"
							variant="outline"
							onclick={nextPage}
							disabled={page * perPage >= total}
						>
							Next
						</Button>
					</div>
				</div>
			{/if}
		{/if}
	</div>
{/if}

{#if showApprovalModal && selectedBooking}
	<ApprovalModal
		bind:open={showApprovalModal}
		booking={selectedBooking}
		onApproved={handleApproved}
	/>
{/if}

<BookingModal bind:open={showBookingModal} bookingId={selectedBooking?.id ?? ''} />

<UserModal bind:open={showUserModal} userId={selectedUserId ?? ''} {openBookingModal} />

{#if showEditRequestModal && selectedEditRequest}
	<EditRequestModal
		bind:open={showEditRequestModal}
		editRequest={selectedEditRequest}
		onApproved={handleEditRequestAction}
		onDenied={handleEditRequestAction}
	/>
{/if}
