<script lang="ts">
	import { apiFetch } from '$lib/utils/api';
	import { SvelteDate } from 'svelte/reactivity';
	import { CalendarDate } from '@internationalized/date';
	import { toast } from 'svelte-sonner';
	import { sanitizeText } from '$lib/utils/toast-safe';
	import { formatUserName } from '$lib/utils/nameDisplay';
	import * as Card from '$lib/components/ui/card';
	import { Button } from '$lib/components/ui/button';
	import { Badge } from '$lib/components/ui/badge';
	import { Skeleton } from '$lib/components/ui/skeleton';
	import { Input } from '$lib/components/ui/input';
	import { Separator } from '$lib/components/ui/separator';
	import * as Modal from '$lib/components/ui/dialog';
	import * as AlertDialog from '$lib/components/ui/alert-dialog';
	import {
		calculateMiddleWindow,
		extractBookedSlots,
		findAllLunchGaps,
		shouldApplyLunchProtection,
		timeToMinutes
	} from '$lib/lunchProtection';
	import { formatDuration, formatDateISO } from '$lib/utils/format';
	import { formatLocalDateTime } from '$lib/utils/timeSlots';

	interface Props {
		openBookingModal: (bookingId: string) => void;
		openUserModal: (userId: string) => void;
	}

	const { openBookingModal, openUserModal }: Props = $props();

	type TodayAppointment = {
		id: string;
		start_time: string;
		status: string;
		user_name: string;
		user_id: string;
		services: string[];
		duration_minutes: number;
		previous_first_name?: string | null;
		previous_last_name?: string | null;
	};

	type TimeBlocker = {
		id: string;
		start_time: string;
		duration_minutes: number;
		description: string;
		cron_expression: string | null;
		created_at: string;
		created_by: string | null;
	};

	type OverlappingBooking = {
		id: string;
		start_time: string;
		duration_minutes: number;
		status: string;
		user: {
			id: string;
			full_name: string;
			email: string | null;
			phone: string | null;
			previous_first_name?: string | null;
			previous_last_name?: string | null;
		} | null;
		services: string[];
	};

	type DayWorkingHours = {
		date: string;
		isOpen: boolean;
		startTime: string;
		endTime: string;
	};

	type DayAvailableHours = {
		date: string;
		isOpen: boolean;
		slots: Array<{ startTime: string; endTime: string }>;
	};

	function isPastAppointment(startTime: string, durationMinutes: number): boolean {
		const start = new SvelteDate(startTime);
		const end = new SvelteDate(start.getTime() + durationMinutes * 60_000);
		return end.getTime() < Date.now();
	}

	let appointments = $state<TodayAppointment[]>([]);
	let loading = $state(true);

	// ======== Blocker State ========
	let blockers = $state<TimeBlocker[]>([]);
	let workingHours = $state<DayWorkingHours | null>(null);
	let whLoading = $state(true);
	let availableHours = $state<DayAvailableHours | null>(null);
	let showCreateModal = $state(false);
	let showDeleteAlert = $state(false);
	let blockerToDelete = $state<TimeBlocker | null>(null);
	let creating = $state(false);
	let checkingOverlap = $state(false);
	let newDescription = $state('');
	let startHour = $state('9');
	let startMinute = $state('00');
	let startPeriod = $state<'AM' | 'PM'>('AM');
	let endHour = $state('10');
	let endMinute = $state('00');
	let endPeriod = $state<'AM' | 'PM'>('AM');
	let overlappingBookings = $state<OverlappingBooking[]>([]);
	let hasOverlap = $state(false);

	let startSelectValue = $derived(`${startHour}:${startMinute}:${startPeriod}`);
	let endSelectValue = $derived(`${endHour}:${endMinute}:${endPeriod}`);

	const today = $derived(new Date().toLocaleDateString('en-CA', { timeZone: 'Europe/London' }));

	const weekStartStr = $derived.by(() => {
		const londonDateStr = new Date().toLocaleDateString('en-CA', { timeZone: 'Europe/London' });
		const d = new SvelteDate(londonDateStr + 'T00:00:00Z');
		const day = d.getDay();
		const diff = day === 0 ? 6 : day - 1;
		d.setDate(d.getDate() - diff);
		return formatDateISO(d);
	});

	const weekEndStr = $derived.by(() => {
		const d = new SvelteDate(weekStartStr + 'T00:00:00Z');
		d.setDate(d.getDate() + 6);
		return formatDateISO(d);
	});

	function to24h(hour: string, minute: string, period: 'AM' | 'PM'): string {
		let h = parseInt(hour);
		if (period === 'PM' && h !== 12) h += 12;
		if (period === 'AM' && h === 12) h = 0;
		return `${String(h).padStart(2, '0')}:${minute}`;
	}

	function minutesTo12h(totalMin: number): { hour: string; minute: string; period: 'AM' | 'PM' } {
		let h = Math.floor(totalMin / 60);
		const m = totalMin % 60;
		const period: 'AM' | 'PM' = h >= 12 ? 'PM' : 'AM';
		if (h > 12) h -= 12;
		if (h === 0) h = 12;
		return { hour: String(h), minute: String(m).padStart(2, '0'), period };
	}

	function parseSelectValue(val: string): { hour: string; minute: string; period: 'AM' | 'PM' } {
		const [hour, minute, period] = val.split(':') as [string, string, 'AM' | 'PM'];
		return { hour, minute, period };
	}

	function isAutoGenerated(blocker: TimeBlocker): boolean {
		return blocker.description?.startsWith('RESERVATION:') ?? false;
	}

	const availableStartOptions = $derived.by(() => {
		const wh = workingHours;
		if (!wh || !wh.isOpen) return [];
		const startMin = timeToMinutes(wh.startTime);
		const endMin = timeToMinutes(wh.endTime);
		const options: Array<{
			hour: string;
			minute: string;
			period: 'AM' | 'PM';
			totalMin: number;
			label: string;
		}> = [];
		for (let m = startMin; m < endMin; m += 15) {
			const t = minutesTo12h(m);
			options.push({ ...t, totalMin: m, label: `${t.hour}:${t.minute} ${t.period}` });
		}
		return options;
	});

	const availableEndOptions = $derived.by(() => {
		const wh = workingHours;
		if (!wh || !wh.isOpen) return [];
		const endMin = timeToMinutes(wh.endTime);
		const currentStartMin = timeToMinutes(to24h(startHour, startMinute, startPeriod));
		const options: Array<{
			hour: string;
			minute: string;
			period: 'AM' | 'PM';
			totalMin: number;
			label: string;
		}> = [];
		for (
			let m = Math.max(timeToMinutes(wh.startTime), currentStartMin + 15);
			m <= endMin;
			m += 15
		) {
			const t = minutesTo12h(m);
			options.push({ ...t, totalMin: m, label: `${t.hour}:${t.minute} ${t.period}` });
		}
		return options;
	});

	const suggestedLunch = $derived.by(() => {
		if (!workingHours || !availableHours || !workingHours.isOpen) return null;
		const wh = workingHours;
		const ah = availableHours;

		if (!shouldApplyLunchProtection(wh.startTime, wh.endTime)) return null;

		const { windowStart, windowEnd } = calculateMiddleWindow(wh.startTime, wh.endTime);
		const existingBookings = extractBookedSlots(wh.startTime, wh.endTime, ah.slots);
		const gaps = findAllLunchGaps(windowStart, windowEnd, existingBookings);
		if (gaps.length === 0) return null;

		const relevantBookings = existingBookings
			.filter((b) => {
				const s = timeToMinutes(b.startTime);
				const e = timeToMinutes(b.endTime);
				return s < windowEnd && e > windowStart;
			})
			.map((b) => ({
				startTime: Math.max(timeToMinutes(b.startTime), windowStart),
				endTime: Math.min(timeToMinutes(b.endTime), windowEnd)
			}))
			.sort((a, b) => a.startTime - b.startTime);

		const gapInfos: Array<{ start: number; end: number; duration: number }> = [];
		let cursor = windowStart;
		for (const b of relevantBookings) {
			if (b.startTime > cursor) {
				gapInfos.push({ start: cursor, end: b.startTime, duration: b.startTime - cursor });
			}
			cursor = Math.max(cursor, b.endTime);
		}
		if (cursor < windowEnd) {
			gapInfos.push({ start: cursor, end: windowEnd, duration: windowEnd - cursor });
		}

		gapInfos.sort((a, b) => b.duration - a.duration);
		if (gapInfos.length === 0) return null;
		const largestGap = gapInfos[0];
		const startTimeStr = `${minutesTo12h(largestGap.start).hour}:${minutesTo12h(largestGap.start).minute} ${minutesTo12h(largestGap.start).period}`;
		const endTimeStr = `${minutesTo12h(largestGap.end).hour}:${minutesTo12h(largestGap.end).minute} ${minutesTo12h(largestGap.end).period}`;
		return {
			startMin: largestGap.start,
			endMin: largestGap.end,
			duration: largestGap.duration,
			startLabel: startTimeStr,
			endLabel: endTimeStr
		};
	});

	type AppointmentTimelineItem = {
		id: string;
		startMinutes: number;
		endMinutes: number;
		type: 'appointment';
		data: TodayAppointment;
	};

	type BlockerTimelineItem = {
		id: string;
		startMinutes: number;
		endMinutes: number;
		type: 'blocker';
		data: TimeBlocker;
	};

	type LunchTimelineItem = {
		id: string;
		startMinutes: number;
		endMinutes: number;
		type: 'lunch';
		data: { duration: number; startLabel: string; endLabel: string };
	};

	type ClosingTimeTimelineItem = {
		id: string;
		startMinutes: number;
		type: 'closing';
		data: { label: string };
	};

	type TimelineItem =
		AppointmentTimelineItem | BlockerTimelineItem | LunchTimelineItem | ClosingTimeTimelineItem;

	const timeline = $derived.by(() => {
		const items: TimelineItem[] = [];

		for (const apt of appointments) {
			const start = new SvelteDate(apt.start_time);
			const startM = start.getHours() * 60 + start.getMinutes();
			items.push({
				id: `apt-${apt.id}`,
				startMinutes: startM,
				endMinutes: startM + apt.duration_minutes,
				type: 'appointment',
				data: apt
			});
		}

		for (const b of blockers) {
			const start = new SvelteDate(b.start_time);
			const startM = start.getHours() * 60 + start.getMinutes();
			items.push({
				id: `blk-${b.id}`,
				startMinutes: startM,
				endMinutes: startM + b.duration_minutes,
				type: 'blocker',
				data: b
			});
		}

		if (suggestedLunch) {
			items.push({
				id: 'lunch',
				startMinutes: suggestedLunch.startMin,
				endMinutes: suggestedLunch.endMin,
				type: 'lunch',
				data: {
					duration: suggestedLunch.duration,
					startLabel: suggestedLunch.startLabel,
					endLabel: suggestedLunch.endLabel
				}
			});
		}

		if (workingHours?.isOpen && workingHours.endTime) {
			const closeMin = timeToMinutes(workingHours.endTime);
			const t = minutesTo12h(closeMin);
			items.push({
				id: 'closing',
				startMinutes: closeMin,
				type: 'closing',
				data: { label: `${t.hour}:${t.minute} ${t.period}` }
			});
		}

		return items.sort((a, b) => a.startMinutes - b.startMinutes);
	});

	let prevAppointmentsJson = $state('');
	let apptsInitialized = $state(false);

	async function fetchTodayAppointments() {
		if (!apptsInitialized) loading = true;
		try {
			const response = await apiFetch('/api/admin/today/appointments', {
				headers: { 'Content-Type': 'application/json' }
			});

			if (response.ok) {
				const data = await response.json();
				const newAppointments = data.appointments || [];
				const newJson = JSON.stringify(newAppointments);
				if (newJson !== prevAppointmentsJson) {
					appointments = newAppointments;
					prevAppointmentsJson = newJson;
				}
			} else {
				toast.error("Failed to load today's appointments");
			}
		} catch (err) {
			console.error("Error fetching today's appointments:", err);
			toast.error('Network error loading appointments');
		} finally {
			if (!apptsInitialized) {
				loading = false;
				apptsInitialized = true;
			}
		}
	}

	let prevBlockersJson = $state('');
	let blockersInitialized = $state(false);

	async function fetchTodayBlockersData() {
		if (!blockersInitialized) whLoading = true;
		try {
			const dateParam = today;
			const [blockersRes, whRes, ahRes] = await Promise.all([
				apiFetch(
					`/api/admin/time-blockers?start=${encodeURIComponent(dateParam)}&end=${encodeURIComponent(dateParam)}`,
					{
						headers: { 'Content-Type': 'application/json' }
					}
				),
				apiFetch(
					`/api/scheduling/working-hours?start=${encodeURIComponent(weekStartStr)}&end=${encodeURIComponent(weekEndStr)}`,
					{
						headers: { 'Content-Type': 'application/json' }
					}
				),
				apiFetch(
					`/api/scheduling/available-hours?start=${encodeURIComponent(weekStartStr)}&end=${encodeURIComponent(weekEndStr)}`,
					{
						headers: { 'Content-Type': 'application/json' }
					}
				)
			]);

			if (blockersRes.ok) {
				const data: TimeBlocker[] = await blockersRes.json();
				const newBlockers = (data || []).filter((b) => !isAutoGenerated(b));
				const newJson = JSON.stringify(newBlockers);
				if (newJson !== prevBlockersJson) {
					blockers = newBlockers;
					prevBlockersJson = newJson;
				}
			}

			if (whRes.ok) {
				const data: DayWorkingHours[] = await whRes.json();
				const newWh = (data || []).find((d) => d.date === dateParam) ?? null;
				if (JSON.stringify(newWh) !== JSON.stringify(workingHours)) {
					workingHours = newWh;
				}
			}

			if (ahRes.ok) {
				const data: DayAvailableHours[] = await ahRes.json();
				const newAh = (data || []).find((d) => d.date === dateParam) ?? null;
				if (JSON.stringify(newAh) !== JSON.stringify(availableHours)) {
					availableHours = newAh;
				}
			}
		} catch (err) {
			console.error('Error fetching today data:', err);
		} finally {
			if (!blockersInitialized) {
				whLoading = false;
				blockersInitialized = true;
			}
		}
	}

	async function checkOverlappingBookings() {
		const startIso = buildDateTime(today, startHour, startMinute, startPeriod);
		const endIso = buildDateTime(today, endHour, endMinute, endPeriod);
		if (!startIso || !endIso) {
			overlappingBookings = [];
			hasOverlap = false;
			return;
		}
		const blockerStart = new SvelteDate(startIso);
		const blockerEnd = new SvelteDate(endIso);
		if (blockerEnd.getTime() <= blockerStart.getTime()) {
			overlappingBookings = [];
			hasOverlap = false;
			return;
		}
		checkingOverlap = true;
		try {
			const response = await apiFetch(
				`/api/admin/bookings/by-date-range?start=${encodeURIComponent(today)}&end=${encodeURIComponent(today)}`,
				{
					headers: { 'Content-Type': 'application/json' }
				}
			);
			if (response.ok) {
				const data = await response.json();
				const allBookings: OverlappingBooking[] = data.bookings || [];
				const filtered = allBookings.filter((b) => {
					const bStart = new SvelteDate(b.start_time);
					const bEnd = new SvelteDate(bStart.getTime() + b.duration_minutes * 60000);
					return bStart < blockerEnd && bEnd > blockerStart;
				});
				overlappingBookings = filtered;
				hasOverlap = overlappingBookings.length > 0;
			} else {
				overlappingBookings = [];
				hasOverlap = false;
			}
		} catch (err) {
			console.error('Error checking overlapping bookings:', err);
			overlappingBookings = [];
			hasOverlap = false;
		} finally {
			checkingOverlap = false;
		}
	}

	function buildDateTime(
		date: string,
		hour: string,
		minute: string,
		period: 'AM' | 'PM'
	): string | null {
		if (!date) return null;
		const t24 = to24h(hour, minute, period);
		const [y, m, d] = date.split('-').map(Number);
		const cal = new CalendarDate(y, m, d);
		const [h, min] = t24.split(':').map(Number);
		const dt = cal.toDate('Europe/London');
		dt.setHours(h, min, 0, 0);
		return formatLocalDateTime(dt);
	}

	const canCreate = $derived.by(() => !hasOverlap && !checkingOverlap);

	async function createBlocker() {
		if (!canCreate) return;
		const startIso = buildDateTime(today, startHour, startMinute, startPeriod);
		const endIso = buildDateTime(today, endHour, endMinute, endPeriod);
		if (!startIso || !endIso) return;
		const start = new Date(startIso);
		const end = new Date(endIso);
		const durationMinutes = Math.round((end.getTime() - start.getTime()) / 60000);
		creating = true;
		const loadingToast = toast.loading('Creating time blocker...');
		try {
			const response = await apiFetch('/api/admin/time-blockers', {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({
					start_time: startIso,
					duration_minutes: durationMinutes,
					description: newDescription.trim() || 'break'
				})
			});
			if (response.ok) {
				toast.success('Time blocker created!', { id: loadingToast });
				showCreateModal = false;
				resetCreateForm();
				await fetchTodayBlockersData();
			} else {
				const text = await response.text();
				toast.error('Failed to create: ' + sanitizeText(text), { id: loadingToast });
			}
		} catch (err) {
			console.error('Error creating time blocker:', err);
			toast.error('Network error creating time blocker', { id: loadingToast });
		} finally {
			creating = false;
		}
	}

	async function confirmDeleteBlocker() {
		if (!blockerToDelete) return;
		const loadingToast = toast.loading('Deleting time blocker...');
		try {
			const response = await apiFetch(`/api/admin/time-blockers/${blockerToDelete.id}`, {
				method: 'DELETE'
			});
			if (response.ok || response.status === 204) {
				toast.success('Time blocker deleted', { id: loadingToast });
				showDeleteAlert = false;
				blockerToDelete = null;
				await fetchTodayBlockersData();
			} else {
				const text = await response.text();
				toast.error('Failed to delete: ' + sanitizeText(text), { id: loadingToast });
			}
		} catch (err) {
			console.error('Error deleting time blocker:', err);
			toast.error('Network error deleting time blocker', { id: loadingToast });
		}
	}

	function resetCreateForm() {
		newDescription = '';
		startHour = '9';
		startMinute = '00';
		startPeriod = 'AM';
		endHour = '10';
		endMinute = '00';
		endPeriod = 'AM';
		overlappingBookings = [];
		hasOverlap = false;
	}

	function openCreateModal() {
		resetCreateForm();
		if (workingHours && workingHours.isOpen) {
			const startOpt = minutesTo12h(timeToMinutes(workingHours.startTime));
			const endOpt = minutesTo12h(timeToMinutes(workingHours.startTime) + 60);
			startHour = startOpt.hour;
			startMinute = startOpt.minute;
			startPeriod = startOpt.period;
			endHour = endOpt.hour;
			endMinute = endOpt.minute;
			endPeriod = endOpt.period;
		}
		showCreateModal = true;
	}

	function getStatusColor(status: string): string {
		switch (status) {
			case 'completed':
				return 'bg-green-100 text-green-800 hover:bg-green-100';
			case 'in_progress':
				return 'bg-blue-100 text-blue-800 hover:bg-blue-100';
			case 'confirmed':
				return 'bg-emerald-100 text-emerald-800 hover:bg-emerald-100';
			case 'pending':
				return 'bg-yellow-100 text-yellow-800 hover:bg-yellow-100';
			case 'client_cancelled':
			case 'we_cancelled':
				return 'bg-red-100 text-red-800 hover:bg-red-100';
			case 'no_show':
				return 'bg-gray-100 text-gray-800 hover:bg-gray-100';
			default:
				return 'bg-gray-100 text-gray-800 hover:bg-gray-100';
		}
	}

	function getStatusBarColor(status: string): string {
		switch (status) {
			case 'completed':
				return 'bg-green-500';
			case 'in_progress':
				return 'bg-blue-500';
			case 'confirmed':
				return 'bg-emerald-500';
			case 'pending':
				return 'bg-yellow-500';
			case 'client_cancelled':
			case 'we_cancelled':
				return 'bg-red-500';
			case 'no_show':
				return 'bg-gray-500';
			default:
				return 'bg-gray-500';
		}
	}

	function formatTime(dateString: string): string {
		const date = new SvelteDate(dateString);
		return date.toLocaleTimeString('en-US', {
			hour: 'numeric',
			minute: '2-digit',
			hour12: true
		});
	}

	function formatStatus(status: string): string {
		return status.replace(/_/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase());
	}

	$effect(() => {
		fetchTodayAppointments();
		fetchTodayBlockersData();

		const intervalId = setInterval(() => {
			fetchTodayAppointments();
		}, 600_000);

		function handleApproval() {
			fetchTodayAppointments();
		}
		window.addEventListener('bookingApproved', handleApproval);

		return () => {
			clearInterval(intervalId);
			window.removeEventListener('bookingApproved', handleApproval);
		};
	});

	$effect(() => {
		if (showCreateModal) {
			checkOverlappingBookings();
		}
	});
</script>

<div class="lg:col-span-2">
	<Card.Root>
		<Card.Header>
			<div class="flex items-center justify-between">
				<div>
					<Card.Title>Today's Appointments</Card.Title>
					<Card.Description>Timeline view of all bookings</Card.Description>
				</div>
				<Button variant="outline" size="sm" onclick={openCreateModal}>
					<svg
						xmlns="http://www.w3.org/2000/svg"
						class="mr-1 h-4 w-4"
						viewBox="0 0 24 24"
						fill="none"
						stroke="currentColor"
						stroke-width="2"
					>
						<line x1="12" y1="5" x2="12" y2="19" />
						<line x1="5" y1="12" x2="19" y2="12" />
					</svg>
					Add Blocker
				</Button>
			</div>
		</Card.Header>
		<Card.Content>
			{#if loading}
				<div class="space-y-3">
					{#each Array(5) as _, i (i)}
						<div class="flex items-center gap-3 rounded-lg border p-3 sm:gap-4">
							<Skeleton class="h-4 w-[45px] sm:w-[60px] lg:w-[80px]" />
							<Skeleton class="h-10 w-1 shrink-0" />
							<div class="min-w-0 flex-1 space-y-2">
								<Skeleton class="h-4 w-32" />
								<Skeleton class="h-3 w-48" />
							</div>
							<Skeleton class="hidden h-6 w-20 shrink-0 sm:block" />
							<Skeleton class="h-8 w-9 shrink-0 sm:w-16" />
						</div>
					{/each}
				</div>
			{:else if timeline.length === 0}
				<div class="py-12 text-center">
					<svg
						xmlns="http://www.w3.org/2000/svg"
						class="mx-auto mb-4 h-16 w-16 text-gray-300"
						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>
					<p class="text-lg font-medium text-gray-600">No appointments today</p>
					<p class="text-sm text-gray-500">Looks like you have a quiet day</p>
				</div>
			{:else}
				<div class="space-y-3">
					{#each timeline as item (item.id)}
						{#if item.type === 'appointment'}
							<div
								class="flex items-center gap-3 rounded-lg border p-3 transition-all hover:shadow-md sm:gap-4
								{isPastAppointment(item.data.start_time, item.data.duration_minutes)
									? 'line-through opacity-50'
									: ''}"
							>
								<div
									class="min-w-[45px] shrink-0 text-xs font-semibold text-gray-700 sm:min-w-[60px] sm:text-sm lg:min-w-[80px]"
								>
									{formatTime(item.data.start_time)}
								</div>
								<div class="h-10 w-1 shrink-0 rounded {getStatusBarColor(item.data.status)}"></div>
								<div class="min-w-0 flex-1">
									<button
										type="button"
										class="block max-w-full truncate font-medium hover:text-blue-600 hover:underline"
										onclick={() => openUserModal(item.data.user_id)}
									>
										{formatUserName(
											item.data.user_name,
											item.data.previous_first_name,
											item.data.previous_last_name
										)}
									</button>
									<div class="flex flex-wrap items-center gap-x-1 text-sm text-gray-600">
										<span class="truncate">{(item.data.services ?? []).join(', ')}</span>
										<span
											class="shrink-0 rounded-full bg-gray-100 px-1.5 py-0.5 text-xs font-medium"
										>
											{formatDuration(item.data.duration_minutes)}
										</span>
									</div>
								</div>
								<Badge class="{getStatusColor(item.data.status)} hidden shrink-0 sm:inline-flex">
									{formatStatus(item.data.status)}
								</Badge>
								<Button
									size="sm"
									variant="outline"
									class="h-9 w-9 shrink-0 sm:w-auto sm:px-3"
									onclick={() => openBookingModal(item.data.id)}
								>
									<svg
										xmlns="http://www.w3.org/2000/svg"
										class="h-4 w-4 sm:mr-1.5"
										viewBox="0 0 24 24"
										fill="none"
										stroke="currentColor"
										stroke-width="2"
									>
										<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
										<circle cx="12" cy="12" r="3" />
									</svg>
									<span class="hidden sm:inline">View</span>
								</Button>
							</div>
						{:else if item.type === 'blocker'}
							<div
								class="flex items-center gap-4 rounded-lg border border-amber-200 bg-amber-50/40 p-3 transition-all hover:shadow-sm"
							>
								<div class="min-w-[60px] text-sm font-semibold text-gray-700 sm:min-w-[80px]">
									{formatTime(item.data.start_time)}
								</div>
								<div
									class="flex h-10 w-6 shrink-0 items-center justify-center rounded bg-amber-100"
								>
									<svg
										class="h-4 w-4 text-amber-600"
										viewBox="0 0 24 24"
										fill="none"
										stroke="currentColor"
										stroke-width="2"
									>
										<rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
										<path d="M7 11V7a5 5 0 0 1 10 0v4" />
									</svg>
								</div>
								<div class="flex min-w-0 flex-1 flex-wrap items-center gap-x-1">
									<div class="truncate text-sm font-medium text-gray-900">
										{item.data.description || 'Untitled'}
									</div>
									<span
										class="rounded-full bg-gray-100 px-1.5 py-0.5 text-xs font-medium text-gray-600"
									>
										{formatDuration(item.data.duration_minutes)}
									</span>
								</div>
								<Button
									variant="destructive"
									size="sm"
									class="h-9 w-9 shrink-0 p-0"
									onclick={() => {
										blockerToDelete = item.data;
										showDeleteAlert = true;
									}}
								>
									<svg
										xmlns="http://www.w3.org/2000/svg"
										class="h-3 w-3"
										viewBox="0 0 24 24"
										fill="none"
										stroke="currentColor"
										stroke-width="2"
									>
										<polyline points="3 6 5 6 21 6" />
										<path
											d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"
										/>
									</svg>
								</Button>
							</div>
						{:else if item.type === 'lunch'}
							<div
								class="flex items-center gap-4 rounded-lg border border-green-200 bg-green-50 p-3"
							>
								<div class="min-w-[60px] text-sm font-semibold text-green-700 sm:min-w-[80px]">
									{item.data.startLabel}
								</div>
								<div
									class="flex h-10 w-6 shrink-0 items-center justify-center rounded bg-green-100"
								>
									<svg
										class="h-4 w-4 text-green-600"
										viewBox="0 0 24 24"
										fill="none"
										stroke="currentColor"
										stroke-width="2"
									>
										<path d="M18 8h1a4 4 0 0 1 0 8h-1" />
										<path d="M2 8h16v9a4 4 0 0 1-4 4H6a4 4 0 0 1-4-4V8z" />
										<line x1="6" y1="1" x2="6" y2="4" />
										<line x1="10" y1="1" x2="10" y2="4" />
										<line x1="14" y1="1" x2="14" y2="4" />
									</svg>
								</div>
								<div class="flex-1">
									<p class="text-sm font-medium text-green-800">
										Suggested lunch: {formatDuration(item.data.duration)} available
									</p>
									<p class="text-xs text-green-700">
										{item.data.startLabel} – {item.data.endLabel}
									</p>
								</div>
							</div>
						{:else if item.type === 'closing'}
							<div class="flex items-center gap-3 border-t border-gray-100 px-1 pt-3">
								<div class="text-xs font-medium text-gray-400">
									{item.data.label}
								</div>
								<div class="h-px flex-1 bg-gray-100"></div>
								<span class="text-[11px] text-gray-400">Close</span>
							</div>
						{/if}
					{/each}
				</div>
			{/if}
		</Card.Content>
	</Card.Root>
</div>

<!-- Create Blocker Modal -->
<Modal.Root bind:open={showCreateModal}>
	<Modal.Content class="max-h-[90vh] max-w-lg overflow-y-auto">
		<Modal.Header>
			<Modal.Title class="text-lg font-semibold">Add Time Blocker</Modal.Title>
			<Modal.Description>Block off a period of time today.</Modal.Description>
		</Modal.Header>
		<div class="space-y-5 px-4 pb-4">
			<div class="space-y-2">
				<label for="blocker-desc" class="text-sm font-medium">Description</label>
				<Input
					id="blocker-desc"
					type="text"
					placeholder="e.g., Lunch, Appointment, Break"
					bind:value={newDescription}
				/>
				<p class="text-xs text-gray-400">Defaults to "break" if left empty</p>
			</div>
			<Separator />
			<div class="space-y-3">
				<h3 class="text-sm font-medium">Start Time</h3>
				{#if whLoading}
					<Skeleton class="h-9 w-full" />
				{:else if !workingHours}
					<p class="text-sm text-gray-400">Loading working hours…</p>
				{:else if !workingHours.isOpen}
					<p class="text-sm text-red-500">Closed today</p>
				{:else}
					<select
						class="flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-xs ring-offset-background transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50"
						bind:value={startSelectValue}
						onchange={() => {
							const p = parseSelectValue(startSelectValue);
							startHour = p.hour;
							startMinute = p.minute;
							startPeriod = p.period;
							checkOverlappingBookings();
						}}
					>
						{#each availableStartOptions as opt (opt.totalMin)}
							<option value={`${opt.hour}:${opt.minute}:${opt.period}`}>{opt.label}</option>
						{/each}
					</select>
				{/if}
			</div>
			<div class="space-y-3">
				<h3 class="text-sm font-medium">End Time</h3>
				{#if whLoading}
					<Skeleton class="h-9 w-full" />
				{:else if !workingHours}
					<p class="text-sm text-gray-400">Loading working hours…</p>
				{:else if !workingHours.isOpen}
					<p class="text-sm text-red-500">Closed today</p>
				{:else if availableEndOptions.length === 0}
					<p class="text-sm text-gray-400">No available end time after selected start</p>
				{:else}
					<select
						class="flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-xs ring-offset-background transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50"
						bind:value={endSelectValue}
						onchange={() => {
							const p = parseSelectValue(endSelectValue);
							endHour = p.hour;
							endMinute = p.minute;
							endPeriod = p.period;
							checkOverlappingBookings();
						}}
					>
						{#each availableEndOptions as opt (opt.totalMin)}
							<option value={`${opt.hour}:${opt.minute}:${opt.period}`}>{opt.label}</option>
						{/each}
					</select>
				{/if}
			</div>
			{#if checkingOverlap}
				<div class="flex items-center gap-2 text-sm text-gray-500">
					<svg class="h-4 w-4 animate-spin" viewBox="0 0 24 24" fill="none">
						<circle
							class="opacity-25"
							cx="12"
							cy="12"
							r="10"
							stroke="currentColor"
							stroke-width="4"
						/>
						<path
							class="opacity-75"
							fill="currentColor"
							d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
						/>
					</svg>
					Checking for conflicting bookings…
				</div>
			{:else if hasOverlap}
				<div class="rounded-lg border border-amber-200 bg-amber-50 p-3">
					<div class="mb-2 flex items-center gap-2">
						<svg
							xmlns="http://www.w3.org/2000/svg"
							class="h-4 w-4 shrink-0 text-amber-600"
							viewBox="0 0 24 24"
							fill="none"
							stroke="currentColor"
							stroke-width="2"
						>
							<path
								d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"
							/>
							<line x1="12" y1="9" x2="12" y2="13" />
							<line x1="12" y1="17" x2="12.01" y2="17" />
						</svg>
						<span class="text-sm font-medium text-amber-800">Booking exists in this timeslot</span>
					</div>
					<div class="space-y-2">
						{#each overlappingBookings as booking (booking.id)}
							<div class="rounded-md border border-amber-200 bg-white p-2">
								<div class="min-w-0">
									<div class="text-sm font-medium">
										{formatUserName(
											booking.user?.full_name || 'Unknown',
											booking.user?.previous_first_name,
											booking.user?.previous_last_name
										)}
									</div>
									<div class="text-xs text-gray-500">
										{new SvelteDate(booking.start_time).toLocaleTimeString('en-GB', {
											hour: 'numeric',
											minute: '2-digit',
											hour12: true
										})}
										· {formatDuration(booking.duration_minutes)}
										{#if booking.services?.length}
											· {booking.services.join(', ')}{/if}
									</div>
								</div>
								<div class="mt-1.5 flex gap-2">
									<Button
										variant="outline"
										size="sm"
										class="h-6 text-xs"
										onclick={() => openBookingModal(booking.id)}>View Booking</Button
									>
									{#if booking.user?.id}
										<Button
											variant="outline"
											size="sm"
											class="h-6 text-xs"
											onclick={() => openUserModal(booking.user!.id)}>View Client</Button
										>
									{/if}
								</div>
							</div>
						{/each}
					</div>
				</div>
			{/if}
		</div>
		<Modal.Footer class="flex items-center justify-end gap-2">
			<Button
				variant="outline"
				onclick={() => {
					showCreateModal = false;
					resetCreateForm();
				}}
				disabled={creating}>Cancel</Button
			>
			<Button onclick={createBlocker} disabled={!canCreate || creating || checkingOverlap}>
				{creating ? 'Creating…' : 'Create Blocker'}
			</Button>
		</Modal.Footer>
	</Modal.Content>
</Modal.Root>

<AlertDialog.Root bind:open={showDeleteAlert}>
	<AlertDialog.Content class="z-60">
		<AlertDialog.Header>
			<AlertDialog.Title>Delete time blocker?</AlertDialog.Title>
			<AlertDialog.Description
				>This will remove the "{blockerToDelete?.description}" time blocker. This action cannot be
				undone.</AlertDialog.Description
			>
		</AlertDialog.Header>
		<AlertDialog.Footer>
			<AlertDialog.Cancel
				onclick={() => {
					showDeleteAlert = false;
					blockerToDelete = null;
				}}>Cancel</AlertDialog.Cancel
			>
			<AlertDialog.Action onclick={confirmDeleteBlocker} class="bg-red-600 hover:bg-red-700"
				>Delete</AlertDialog.Action
			>
		</AlertDialog.Footer>
	</AlertDialog.Content>
</AlertDialog.Root>
