<script lang="ts">
	import { authStore } from '$lib/stores/auth.svelte';
	import { SvelteDate } from 'svelte/reactivity';
	import { CalendarDate, getLocalTimeZone, type DateValue } from '@internationalized/date';
	import { toast } from 'svelte-sonner';
	import * as Modal from '$lib/components/ui/dialog';
	import { Button } from '$lib/components/ui/button';
	import * as Textarea from '$lib/components/ui/textarea';
	import * as Label from '$lib/components/ui/label';
	import DatePicker from '$lib/components/booking/DatePicker.svelte';
	import type { Booking, WorkingHoursDay, AvailableHoursDay } from '$lib/types/booking';
	import { extractBookedSlots, getLunchProtectionForSlots } from '$lib/lunchProtection';

	interface Props {
		open: boolean;
		bookingId: string;
	}

	let { open = $bindable(), bookingId }: Props = $props();

	let selectedBooking = $state<Booking | null>(null);
	let loading = $state(false);

	let showCancelConfirm = $state(false);
	let cancelling = $state(false);

	let showRescheduleForm = $state(false);
	let rescheduleDate = $state<CalendarDate | undefined>(undefined);
	let rescheduleTime = $state('');
	let rescheduleNotes = $state('');
	let rescheduleSubmitting = $state(false);

	let rescheduleWorkingHours = $state<Record<string, { isOpen: boolean; startTime: string; endTime: string }> | null>(null);
	let rescheduleAvailableHours = $state<Record<string, { isOpen: boolean; slots: Array<{ startTime: string; endTime: string }> }> | null>(null);
	let loadingRescheduleHours = $state(false);

	const today = new Date();
	const minDate = new CalendarDate(today.getFullYear(), today.getMonth() + 1, today.getDate());
	const maxDate = new Date();
	maxDate.setMonth(today.getMonth() + 6);
	const maxCalendarDate = new CalendarDate(maxDate.getFullYear(), maxDate.getMonth() + 1, maxDate.getDate());
	let reschedulePlaceholder = $state<CalendarDate>(minDate);

	let totalDuration = $derived(
		selectedBooking?.services?.reduce((sum, service) => sum + (service.duration_minutes || 0), 0) || 0
	);

	const rescheduleLunchProtection = $derived(() => {
		if (!rescheduleDate || !rescheduleWorkingHours || !rescheduleAvailableHours || totalDuration === 0) {
			return new Map();
		}

		const dateStr = rescheduleDate.toString();
		const dayWorkingHours = rescheduleWorkingHours[dateStr];
		const dayAvailableHours = rescheduleAvailableHours[dateStr];

		if (!dayWorkingHours?.isOpen || !dayAvailableHours?.slots) {
			return new Map();
		}

		const existingBookings = extractBookedSlots(
			dayWorkingHours.startTime,
			dayWorkingHours.endTime,
			dayAvailableHours.slots
		);

		return getLunchProtectionForSlots(
			dayWorkingHours.startTime,
			dayWorkingHours.endTime,
			existingBookings,
			totalDuration,
			15, // 15 minute slot intervals
			false // User journey - requires 1h minimum
		);
	});

	let isFutureBooking = $derived(
		selectedBooking ? new Date(selectedBooking.start_time) > new Date() : false
	);

	let isCancellable = $derived(
		selectedBooking &&
		isFutureBooking &&
		['pending', 'confirmed'].includes(selectedBooking.status)
	);

	let hasPayments = $derived(
		selectedBooking && selectedBooking.payments && selectedBooking.payments.length > 0
	);

	let totalPaid = $derived(
		selectedBooking?.payments
			?.filter((p) => p.status === 'completed')
			.reduce((sum, p) => sum + p.amount, 0) || 0
	);

	let isRescheduleValid = $derived(
		rescheduleDate && rescheduleTime && rescheduleTime.length >= 4
	);

	async function fetchBookingDetails() {
		if (!bookingId) return;
		loading = true;
		try {
			const response = await fetch(`/api/bookings/${bookingId}`, {
				method: 'GET',
				headers: {
					'Content-Type': 'application/json',
					Authorization: `Bearer ${authStore.currentToken}`
				}
			});

			if (response.ok) {
				const data = await response.json();
				selectedBooking = data as Booking;
			} else {
				const text = await response.text();
				toast.error('Failed to load booking: ' + text);
				open = false;
			}
		} catch (err) {
			console.error('Error fetching booking:', err);
			toast.error('Network error');
			open = false;
		} finally {
			loading = false;
		}
	}

	$effect(() => {
		if (!open) {
			setTimeout(() => {
				selectedBooking = null;
				showCancelConfirm = false;
				showRescheduleForm = false;
				rescheduleDate = undefined;
				rescheduleTime = '';
				rescheduleNotes = '';
				reschedulePlaceholder = minDate;
				rescheduleWorkingHours = null;
				rescheduleAvailableHours = null;
			}, 200);
		} else if (bookingId && !selectedBooking) {
			fetchBookingDetails();
		}
	});

	async function cancelBooking() {
		if (!selectedBooking) return;
		cancelling = true;
		try {
			const body = hasPayments ? { reason: 'client_cancelled' } : undefined;
			const response = await fetch(`/api/bookings/${selectedBooking.id}`, {
				method: 'DELETE',
				headers: {
					'Content-Type': 'application/json',
					Authorization: `Bearer ${authStore.currentToken}`
				},
				body: body ? JSON.stringify(body) : undefined
			});

			if (response.ok) {
				toast.success('Booking cancelled');
				showCancelConfirm = false;
				open = false;
			} else {
				const text = await response.text();
				toast.error('Failed to cancel: ' + text);
			}
		} catch {
			toast.error('Network error');
		} finally {
			cancelling = false;
		}
	}

	async function fetchRescheduleHours(date: CalendarDate) {
		const monthKey = `${date.year}-${String(date.month).padStart(2, '0')}`;
		loadingRescheduleHours = true;
		try {
			const startOfMonth = new CalendarDate(date.year, date.month, 1);
			const endOfMonth = new CalendarDate(date.year, date.month, date.calendar.getDaysInMonth(date));
			const startStr = startOfMonth.toString();
			const endStr = endOfMonth.toString();

			const [whRes, ahRes] = await Promise.all([
				fetch(`/api/scheduling/working-hours?start=${startStr}&end=${endStr}`),
				fetch(`/api/scheduling/available-hours?start=${startStr}&end=${endStr}`)
			]);

			if (whRes.ok && ahRes.ok) {
				const whData: WorkingHoursDay[] = await whRes.json();
				const ahData: AvailableHoursDay[] = await ahRes.json();

				const whMap: Record<string, { isOpen: boolean; startTime: string; endTime: string }> = {};
				whData.forEach((d) => { whMap[d.date] = { isOpen: d.isOpen, startTime: d.startTime, endTime: d.endTime }; });

				const ahMap: Record<string, { isOpen: boolean; slots: Array<{ startTime: string; endTime: string }> }> = {};
				ahData.forEach((d) => { ahMap[d.date] = { isOpen: d.isOpen, slots: d.slots }; });

				rescheduleWorkingHours = whMap;
				rescheduleAvailableHours = ahMap;
			}
		} catch (err) {
			console.error('Failed to fetch reschedule hours:', err);
		} finally {
			loadingRescheduleHours = false;
		}
	}

	function isDateUnavailable(date: DateValue): boolean {
		const d = date as CalendarDate;
		const jsDate = d.toDate(getLocalTimeZone());
		const now = new Date();
		const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
		if (jsDate < todayStart) return true;
		if (d.compare(minDate) < 0 || d.compare(maxCalendarDate) > 0) return true;
		if (!rescheduleWorkingHours) return false;
		const dateStr = d.toString();
		const dayHours = rescheduleWorkingHours[dateStr];
		if (!dayHours || !dayHours.isOpen) return true;
		if (totalDuration === 0) return false;
		const slots = generateAvailableTimeSlots(totalDuration, d);
		return slots.length === 0;
	}

	function formatTime(time: string): string {
		const parts = time.split(':').map(Number);
		const hours = parts[0];
		const minutes = parts.length > 1 ? parts[1] : 0;
		if (hours === 12 && minutes === 0) return 'Noon';
		if (hours === 0 && minutes === 0) return 'Midnight';
		const period = hours >= 12 ? 'PM' : 'AM';
		const displayHours = hours % 12 || 12;
		return `${displayHours}:${minutes.toString().padStart(2, '0')} ${period}`;
	}

	function calculateEndTime(startTime: string, durationMinutes: number): string {
		const [hours, minutes] = startTime.split(':').map(Number);
		let total = hours * 60 + minutes + durationMinutes;
		const h = Math.floor(total / 60);
		const m = total % 60;
		return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;
	}

	function timeToMinutes(time: string): number {
		const [h, m] = time.split(':').map(Number);
		return h * 60 + m;
	}

	function calculatePreviousTime(time: string): string {
		const [h, m] = time.split(':').map(Number);
		let total = h * 60 + m - 15;
		return `${String(Math.floor(total / 60)).padStart(2, '0')}:${String(total % 60).padStart(2, '0')}`;
	}

	function generateAvailableTimeSlots(duration: number, date: CalendarDate): string[] {
		if (!rescheduleWorkingHours || !rescheduleAvailableHours) return [];
		const dateStr = date.toString();
		const dayWH = rescheduleWorkingHours[dateStr];
		const dayAH = rescheduleAvailableHours[dateStr];
		if (!dayWH || !dayWH.isOpen || !dayAH || !dayAH.slots) return [];

		const slots: string[] = [];
		const now = new SvelteDate();
		const todayCal = new CalendarDate(now.getFullYear(), now.getMonth() + 1, now.getDate());
		const isToday = date.compare(todayCal) === 0;

		for (const slot of dayAH.slots) {
			const [sh, sm] = slot.startTime.split(':').map(Number);
			const [eh, em] = slot.endTime.split(':').map(Number);
			let startMin = sh * 60 + sm;
			const endMin = eh * 60 + em;

			if (isToday) {
				const currentMin = now.getHours() * 60 + now.getMinutes();
				startMin = Math.max(startMin, currentMin + 120);
			}

			for (let m = startMin; m < endMin; m += 15) {
				if (m + duration <= endMin) {
					slots.push(`${String(Math.floor(m / 60)).padStart(2, '0')}:${String(m % 60).padStart(2, '0')}`);
				}
			}
		}
		return slots;
	}

	function generateGroupedTimeSlots(
		duration: number,
		date: CalendarDate,
		lunchProtection: Map<string, { isBlocked: boolean; showWarning: boolean; warningMessage?: string }> = new Map()
	): Array<{ type: 'available' | 'unavailable'; startTime: string; endTime: string; isGrouped?: boolean }> {
		if (!rescheduleWorkingHours) return [];
		const dateStr = date.toString();
		const dayWH = rescheduleWorkingHours[dateStr];
		if (!dayWH || !dayWH.isOpen) return [];

		const grouped: Array<{ type: 'available' | 'unavailable'; startTime: string; endTime: string; isGrouped?: boolean }> = [];
		const [sh, sm] = dayWH.startTime.split(':').map(Number);
		const [eh, em] = dayWH.endTime.split(':').map(Number);
		let startMin = sh * 60 + sm;
		const endMin = eh * 60 + em;

		const now = new SvelteDate();
		const todayCal = new CalendarDate(now.getFullYear(), now.getMonth() + 1, now.getDate());
		const isToday = date.compare(todayCal) === 0;
		if (isToday) {
			const currentMin = now.getHours() * 60 + now.getMinutes();
			startMin = Math.max(startMin, currentMin + 120);
		}

		const availableSlots = generateAvailableTimeSlots(duration, date);
		let currentUnavailableStart: string | null = null;
		let lastAvailableEnd: string | null = null;

		for (let m = startMin; m < endMin; m += 15) {
			const timeStr = `${String(Math.floor(m / 60)).padStart(2, '0')}:${String(m % 60).padStart(2, '0')}`;
			const isAvailable = availableSlots.includes(timeStr) && !lunchProtection.get(timeStr)?.isBlocked;

			if (isAvailable) {
				if (currentUnavailableStart !== null) {
					const groupEnd = calculatePreviousTime(timeStr);
					const unavailableStartTime = lastAvailableEnd || currentUnavailableStart;
					if (unavailableStartTime && timeToMinutes(unavailableStartTime) < timeToMinutes(groupEnd)) {
						grouped.push({ type: 'unavailable', startTime: unavailableStartTime, endTime: groupEnd, isGrouped: true });
					}
					currentUnavailableStart = null;
				}
				const slotEnd = calculateEndTime(timeStr, duration);
				lastAvailableEnd = slotEnd;
				grouped.push({ type: 'available', startTime: timeStr, endTime: slotEnd });
			} else {
				if (currentUnavailableStart === null) {
					currentUnavailableStart = timeStr;
				}
			}
		}

		if (currentUnavailableStart !== null) {
			const lastAvail = grouped.filter((s) => s.type === 'available').pop();
			const lastAvailEnd = lastAvail ? timeToMinutes(lastAvail.endTime) : 0;
			const unavailableStartMinutes = timeToMinutes(currentUnavailableStart);
			if (unavailableStartMinutes < endMin && lastAvailEnd < endMin) {
				grouped.push({ type: 'unavailable', startTime: lastAvail ? lastAvail.endTime : currentUnavailableStart, endTime: dayWH.endTime, isGrouped: true });
			}
		}

		return grouped;
	}

	async function submitReschedule() {
		if (!selectedBooking || !rescheduleDate || !rescheduleTime) return;

		// Re-fetch available hours to confirm slot is still open
		try {
			const dateStr = rescheduleDate.toString();
			const monthKey = `${rescheduleDate.year}-${String(rescheduleDate.month).padStart(2, '0')}`;
			const startOfMonth = new CalendarDate(rescheduleDate.year, rescheduleDate.month, 1);
			const endOfMonth = new CalendarDate(rescheduleDate.year, rescheduleDate.month, rescheduleDate.calendar.getDaysInMonth(rescheduleDate));

			const [whRes, ahRes] = await Promise.all([
				fetch(`/api/scheduling/working-hours?start=${startOfMonth}&end=${endOfMonth}`),
				fetch(`/api/scheduling/available-hours?start=${startOfMonth}&end=${endOfMonth}`)
			]);

			if (whRes.ok && ahRes.ok) {
				const whData: WorkingHoursDay[] = await whRes.json();
				const ahData: AvailableHoursDay[] = await ahRes.json();

				const freshWH: Record<string, { isOpen: boolean; startTime: string; endTime: string }> = {};
				whData.forEach((d) => { freshWH[d.date] = { isOpen: d.isOpen, startTime: d.startTime, endTime: d.endTime }; });
				const freshAH: Record<string, { isOpen: boolean; slots: Array<{ startTime: string; endTime: string }> }> = {};
				ahData.forEach((d) => { freshAH[d.date] = { isOpen: d.isOpen, slots: d.slots }; });

				const dayWH = freshWH[dateStr];
				const dayAH = freshAH[dateStr];

				if (!dayWH?.isOpen || !dayAH?.slots) {
					toast.error('This date is no longer available. Please select a different date.');
					rescheduleDate = undefined;
					rescheduleTime = '';
					return;
				}

				// Check if the selected time is still available
				const freshSlots: string[] = [];
				for (const slot of dayAH.slots) {
					const [sh, sm] = slot.startTime.split(':').map(Number);
					const [eh, em] = slot.endTime.split(':').map(Number);
					for (let m = sh * 60 + sm; m < eh * 60 + em; m += 15) {
						if (m + totalDuration <= eh * 60 + em) {
							freshSlots.push(`${String(Math.floor(m / 60)).padStart(2, '0')}:${String(m % 60).padStart(2, '0')}`);
						}
					}
				}

				if (!freshSlots.includes(rescheduleTime)) {
					toast.error('This time slot is no longer available. Please choose a different time.');
					rescheduleTime = '';
					return;
				}

				// Check lunch protection
				const existingBookings = extractBookedSlots(dayWH.startTime, dayWH.endTime, dayAH.slots);
				const freshLunch = getLunchProtectionForSlots(dayWH.startTime, dayWH.endTime, existingBookings, totalDuration, 15, false);
				if (freshLunch.get(rescheduleTime)?.isBlocked) {
					toast.error('This time slot is no longer available. Please choose a different time.');
					rescheduleTime = '';
					return;
				}
			}
		} catch {
			toast.error('Could not verify slot availability. Please try again.');
			return;
		}

		rescheduleSubmitting = true;
		try {
			const [hours, minutes] = rescheduleTime.split(':').map(Number);
			const bookingDate = rescheduleDate.toDate(getLocalTimeZone());
			bookingDate.setHours(hours || 0, minutes || 0, 0, 0);

			const body: Record<string, unknown> = {
				new_start_time: bookingDate.toISOString()
			};
			if (rescheduleNotes.trim()) {
				body.notes = rescheduleNotes.trim();
			}

			const response = await fetch(`/api/bookings/${selectedBooking.id}/edit-request`, {
				method: 'POST',
				headers: {
					'Content-Type': 'application/json',
					Authorization: `Bearer ${authStore.currentToken}`
				},
				body: JSON.stringify(body)
			});

			if (response.ok) {
				toast.success('Reschedule request sent — we\'ll confirm shortly');
				showRescheduleForm = false;
				rescheduleDate = undefined;
				rescheduleTime = '';
				rescheduleNotes = '';
			} else {
				const text = await response.text();
				toast.error(text || 'Failed to submit reschedule request');
			}
		} catch {
			toast.error('Network error');
		} finally {
			rescheduleSubmitting = false;
		}
	}
</script>

<Modal.Root bind:open>
	<Modal.Content class="max-h-[90vh] max-w-sm overflow-y-auto md:max-w-3xl">
		<Modal.Header>
			<div class="flex items-center justify-between">
				<div>
					<Modal.Title class="text-lg font-semibold">Booking Details</Modal.Title>
					{#if selectedBooking}
						<div class="mt-1 text-sm text-gray-500">ID: {selectedBooking.id}</div>
					{/if}
				</div>

				{#if selectedBooking}
					{@const isPastBooking = new Date(selectedBooking.start_time) < new Date()}
					{@const isUnpaid = selectedBooking.amount_due > 0}
					{@const showChip = !isPastBooking || isUnpaid}
					{@const isConfirmedOrLater = ['confirmed', 'in_progress', 'completed'].includes(selectedBooking.status)}

					{#if showChip}
						<div class="flex items-center gap-2">
							<span
								class="inline-flex items-center rounded-full px-3 py-1 text-sm font-medium
								{isPastBooking
									? 'bg-red-100 text-red-800'
									: selectedBooking.status === 'confirmed' || selectedBooking.status === 'completed'
										? 'bg-emerald-100 text-emerald-800'
										: selectedBooking.status === 'pending'
											? 'bg-amber-100 text-amber-800'
											: 'bg-gray-100 text-gray-800'}"
							>
								{isPastBooking ? 'Unpaid' : selectedBooking.status.replace('_', ' ')}
							</span>

							{#if selectedBooking.deposit_required}
								{#if selectedBooking.status === 'pending'}
									<span
										class="inline-flex items-center rounded-full bg-blue-100 px-3 py-1 text-sm font-medium text-blue-800"
									>
										Will Require Deposit
									</span>
								{:else if isConfirmedOrLater}
									<span
										class="inline-flex items-center rounded-full px-3 py-1 text-sm font-medium
										{selectedBooking.deposit_paid
											? 'bg-green-100 text-green-800'
											: 'bg-orange-100 text-orange-800'}"
									>
										{selectedBooking.deposit_paid ? 'Deposit Paid' : 'Deposit Due'}
									</span>
								{/if}
							{/if}
						</div>
					{/if}
				{/if}
			</div>
		</Modal.Header>

		{#if loading}
			<div class="flex items-center justify-center p-8 text-gray-500">Loading...</div>
		{:else if selectedBooking}
			<div class="space-y-6 px-4 pb-4">
				<div class="rounded-lg border border-gray-200 bg-gray-50 p-4">
					<h3 class="mb-3 text-sm font-semibold tracking-wide text-gray-600 uppercase">
						Appointment Details
					</h3>
					<div class="grid gap-3 md:grid-cols-2">
						<div>
							<div class="text-xs text-gray-500">Scheduled Date & Time</div>
							<div class="font-medium">
								{(() => {
									const date = new SvelteDate(selectedBooking.start_time);
									const dateStr = date.toLocaleDateString('en-US', {
										weekday: 'long',
										day: 'numeric',
										month: 'short'
									});
									const timeStr = date.toLocaleTimeString('en-US', {
										hour: 'numeric',
										minute: '2-digit',
										hour12: true
									});
									return `${dateStr} at ${timeStr}`;
								})()}
							</div>
						</div>
						<div>
							<div class="text-xs text-gray-500">Duration</div>
							<div class="font-medium">{totalDuration} minutes</div>
						</div>
						{#if selectedBooking.notes}
							<div class="md:col-span-2">
								<div class="text-xs text-gray-500">Notes</div>
								<div class="mt-1 rounded-md border border-gray-300 bg-white p-2 text-sm">
									{selectedBooking.notes}
								</div>
							</div>
						{/if}
					</div>
				</div>

				{#if selectedBooking.services && selectedBooking.services.length > 0}
					<div class="rounded-lg border border-gray-200 bg-gray-50 p-4">
						<h3 class="mb-3 text-sm font-semibold tracking-wide text-gray-600 uppercase">
							Services
						</h3>
						<div class="space-y-3">
							{#each selectedBooking.services as service, index (index)}
								<div class="rounded-md border border-gray-300 bg-white p-3">
									<div class="font-medium">{service.service_name || '—'}</div>
									{#if service.service_description}
										<div class="mt-1 text-sm text-gray-600">{service.service_description}</div>
									{/if}
									<div class="mt-2 flex items-center justify-between text-sm">
										<span class="text-gray-600">{service.duration_minutes} min</span>
										<span class="font-semibold">£{service.price?.toFixed(2) || '0.00'}</span>
									</div>
								</div>
							{/each}
						</div>
					</div>
				{/if}

				<div class="rounded-lg border border-gray-200 bg-gray-50 p-4">
					<h3 class="mb-3 text-sm font-semibold tracking-wide text-gray-600 uppercase">
						Financial Summary
					</h3>
					<div class="space-y-2">
						{#if ['confirmed', 'in_progress', 'completed'].includes(selectedBooking.status) && selectedBooking.deposit_required}
							<div class="flex items-center justify-between border-b border-gray-200 pb-2">
								<span class="text-sm text-gray-600">Deposit Required</span>
								<div class="text-right">
									<div class="font-semibold">£{selectedBooking.deposit_amount?.toFixed(2) || '0.00'}</div>
									<div class="text-xs">
										<span
											class="{selectedBooking.deposit_paid
												? 'text-green-600'
												: 'text-orange-600'}"
										>
											{selectedBooking.deposit_paid ? 'Paid' : 'Outstanding'}
										</span>
										{#if !selectedBooking.deposit_paid && selectedBooking.deposit_deadline}
											<span class="text-gray-500">
												• Due: {new SvelteDate(selectedBooking.deposit_deadline).toLocaleDateString('en-GB', {
													weekday: 'short',
													day: 'numeric',
													month: 'short',
													year: 'numeric'
												})} at {new SvelteDate(selectedBooking.deposit_deadline).toLocaleTimeString('en-GB', {
													hour: 'numeric',
													minute: '2-digit',
													hour12: true
												})}
											</span>
										{/if}
									</div>
								</div>
							</div>
						{/if}

						<div class="flex items-center justify-between">
							<span class="text-sm text-gray-600">Total Amount</span>
							<span class="font-semibold">£{selectedBooking.total_amount.toFixed(2)}</span>
						</div>
						<div class="flex items-center justify-between">
							<span class="text-sm text-gray-600">Amount Paid</span>
							<span class="font-semibold text-green-700"
								>£{selectedBooking.amount_paid.toFixed(2)}</span
							>
						</div>
						<div class="flex items-center justify-between border-t border-gray-300 pt-2">
							<span class="font-medium text-gray-900">
								{isFutureBooking ? 'Estimated Subtotal' : 'Amount Due'}
							</span>
							<span
								class="text-lg font-bold {selectedBooking.amount_due > 0
									? 'text-red-600'
									: 'text-green-600'}"
							>
								£{selectedBooking.amount_due.toFixed(2)}
							</span>
						</div>
					</div>
				</div>

				{#if selectedBooking.payments && selectedBooking.payments.length > 0}
					<div class="rounded-lg border border-gray-200 bg-gray-50 p-4">
						<h3 class="mb-3 text-sm font-semibold tracking-wide text-gray-600 uppercase">
							Payment History
						</h3>
						<div class="space-y-3">
							{#each selectedBooking.payments as payment (payment.id)}
								<div class="rounded-md border border-gray-300 bg-white p-3">
									<div class="flex items-start justify-between">
										<div class="flex-1">
											<div class="flex items-center gap-2">
												<span class="font-medium capitalize"
													>{payment.payment_method.replace('_', ' ')}</span
												>
												<span
													class="inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium
                                                    {payment.status === 'completed'
															? 'bg-green-100 text-green-800'
															: payment.status === 'pending'
																? 'bg-yellow-100 text-yellow-800'
																: 'bg-gray-100 text-gray-800'}"
												>
													{payment.status}
												</span>
											</div>
											<div class="mt-1 text-xs text-gray-500">
												{payment.payment_type.charAt(0).toUpperCase() +
													payment.payment_type.slice(1)}
											</div>
											{#if payment.is_vat_applicable}
												<div class="mt-2 text-xs text-gray-600">
													<div>Net: £{payment.net_amount?.toFixed(2) || '0.00'}</div>
													{#if payment.vat_amount}
														<div>
															VAT ({(payment.vat_rate || 0) * 100}%): £{payment.vat_amount.toFixed(
																2
															)}
														</div>
													{/if}
												</div>
											{/if}
											<div class="mt-1 text-xs text-gray-400">
												{new SvelteDate(payment.created_at).toLocaleString()}
											</div>
										</div>
										<div class="text-right font-semibold">
											£{payment.amount.toFixed(2)}
										</div>
									</div>
								</div>
							{/each}
						</div>
					</div>
				{/if}

				{#if showRescheduleForm}
					<div class="rounded-lg border border-gray-200 bg-gray-50 p-4">
						<h3 class="mb-3 text-sm font-semibold tracking-wide text-gray-600 uppercase">
							Request Reschedule
						</h3>

						{#if loadingRescheduleHours}
							<div class="flex items-center justify-center p-6">
								<p class="text-sm text-gray-500">Loading available dates...</p>
							</div>
						{:else}
							<div class="flex items-center justify-center">
								<DatePicker
									date={rescheduleDate}
									placeholder={reschedulePlaceholder}
									minValue={minDate}
									maxValue={maxCalendarDate}
									isDateUnavailable={isDateUnavailable}
									onchange={(d) => { rescheduleDate = d; rescheduleTime = ''; }}
									onPlaceholderChange={(p) => {
										reschedulePlaceholder = p;
										if (!rescheduleWorkingHours) fetchRescheduleHours(p);
									}}
								/>
							</div>
						{/if}

						{#if rescheduleDate}
							{#if loadingRescheduleHours}
								<div class="flex items-center justify-center border-t p-6">
									<p class="text-sm text-gray-500">Loading times...</p>
								</div>
							{:else}
								<div class="no-scrollbar mt-2 flex max-h-40 w-full scroll-pb-6 flex-col gap-4 overflow-y-auto border-t pt-4">
									<div class="grid justify-center gap-2 text-sm text-gray-600">
										{rescheduleDate.toDate(getLocalTimeZone()).toLocaleDateString('en-GB', { weekday: 'long', day: 'numeric', month: 'short' })}
									</div>
									{#if rescheduleWorkingHours && !rescheduleWorkingHours[rescheduleDate.toString()]?.isOpen}
										<p class="text-center text-sm text-gray-500">We're closed on this day</p>
									{:else}
										{@const grouped = generateGroupedTimeSlots(totalDuration, rescheduleDate, rescheduleLunchProtection())}
										{#if grouped.length > 0}
											<div class="grid gap-2">
												{#each grouped as slot (slot.type + '-' + slot.startTime + '-' + slot.endTime)}
													{#if slot.type === 'available'}
														<Button
															variant="outline"
															onclick={() => { rescheduleTime = slot.startTime; }}
															class="w-full hover:bg-fuchsia-50 {rescheduleTime === slot.startTime ? 'bg-fuchsia-100' : ''}"
														>
															{formatTime(slot.startTime)}
															<span class="text-gray-500">- {formatTime(slot.endTime)}</span>
														</Button>
													{:else}
														<Button
															variant="outline"
															class="w-full cursor-not-allowed opacity-50 hover:bg-gray-100"
															disabled
														>
															{formatTime(slot.startTime)}
															<span class="text-gray-500">- {formatTime(slot.endTime)}</span>
														</Button>
													{/if}
												{/each}
											</div>
										{:else}
											<p class="text-center text-sm text-gray-500">No available slots</p>
										{/if}
									{/if}
								</div>
							{/if}
						{/if}

						<div class="mt-4 space-y-2">
							<Label.Root for="reschedule-notes">Reason (optional)</Label.Root>
							<Textarea.Root
								id="reschedule-notes"
								bind:value={rescheduleNotes}
								placeholder="Tell us why you need to reschedule"
								rows={2}
							/>
						</div>

						<div class="mt-4 flex gap-2">
							<Button
								size="sm"
								onclick={submitReschedule}
								disabled={!isRescheduleValid || rescheduleSubmitting}
							>
								{rescheduleSubmitting ? 'Submitting...' : 'Submit Request'}
							</Button>
							<Button
								size="sm"
								variant="outline"
								onclick={() => {
									showRescheduleForm = false;
									rescheduleDate = undefined;
									rescheduleTime = '';
									rescheduleNotes = '';
								}}
							>
								Cancel
							</Button>
						</div>
					</div>
				{/if}
			</div>
		{/if}

		<div class="flex flex-col gap-2 border-t px-4 py-3">
			<div class="flex gap-2">
				{#if isCancellable}
					<Button
						variant="destructive"
						size="sm"
						class="flex-1"
						onclick={() => (showCancelConfirm = true)}
					>
						Cancel Booking
					</Button>
					<Button
						variant="outline"
						size="sm"
						class="flex-1"
						onclick={() => {
							showRescheduleForm = !showRescheduleForm;
							if (!showRescheduleForm) {
								rescheduleDate = undefined;
								rescheduleTime = '';
								rescheduleNotes = '';
							} else if (!rescheduleWorkingHours) {
								fetchRescheduleHours(reschedulePlaceholder);
							}
						}}
					>
						{showRescheduleForm ? 'Hide Reschedule' : 'Reschedule'}
					</Button>
				{/if}
			</div>
			<div class="flex gap-2">
				{#if selectedBooking}
					<Button
						variant="outline"
						size="sm"
						class="flex-1"
						onclick={() => {
							if (selectedBooking) {
								window.open(`/api/bookings/${selectedBooking.id}/calendar`, '_blank');
							}
						}}
					>
						Add to Calendar
					</Button>
				{/if}
				<Button size="sm" class="flex-1" onclick={() => (open = false)}>Close</Button>
			</div>
		</div>
	</Modal.Content>
</Modal.Root>

<Modal.Root open={showCancelConfirm} onOpenChange={(v) => (showCancelConfirm = v)}>
	<Modal.Content class="max-w-sm">
		<Modal.Header>
			<Modal.Title>Cancel Booking</Modal.Title>
			<Modal.Description>
				Are you sure you want to cancel this booking?
				{#if hasPayments}
					<div class="mt-2 rounded-md border border-amber-200 bg-amber-50 p-3 text-sm text-amber-800">
						<p class="font-medium">Please note:</p>
						<p class="mt-1">
							The <span class="font-semibold">£{totalPaid.toFixed(2)}</span> already paid for this booking
							will not be refunded, but will be retained as credit towards a future appointment.
						</p>
					</div>
				{/if}
			</Modal.Description>
		</Modal.Header>
		<Modal.Footer>
			<Button variant="outline" onclick={() => (showCancelConfirm = false)}>
				Keep Booking
			</Button>
			<Button variant="destructive" onclick={cancelBooking} disabled={cancelling}>
				{cancelling ? 'Cancelling...' : 'Yes, Cancel'}
			</Button>
		</Modal.Footer>
	</Modal.Content>
</Modal.Root>
