<script lang="ts">
	import { SvelteDate } from 'svelte/reactivity';
	import { apiFetch } from '$lib/utils/api';
	import { CalendarDate } from '@internationalized/date';
	import { toast } from 'svelte-sonner';
	import { sanitizeText } from '$lib/utils/toast-safe';
	import { formatDuration } from '$lib/utils/format';
	import { formatUserName } from '$lib/utils/nameDisplay';
	import { formatLocalDateTime, parseWallClockDate } from '$lib/utils/timeSlots';

	import { Button } from '$lib/components/ui/button';
	import * as Card from '$lib/components/ui/card';
	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 { Skeleton } from '$lib/components/ui/skeleton';

	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 WorkingHourRow = {
		weekday: number;
		startTime: string;
		endTime: string;
		isOpen: boolean;
	};

	interface Props {
		openUserModal?: (userId: string) => void;
		openBookingModal?: (bookingId: string) => void;
		rescheduleVersion?: number;
		defaultHours?: WorkingHourRow[];
	}

	const {
		openUserModal,
		openBookingModal,
		rescheduleVersion = 0,
		defaultHours: defaultHoursProp
	}: Props = $props();

	const PAGE_SIZE = 5;

	let blockers = $state<TimeBlocker[]>([]);
	let loading = $state(true);
	let creating = $state(false);
	let checkingOverlap = $state(false);

	let showCreateModal = $state(false);
	let newDescription = $state('');
	let newStartDate = $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 startSelectValue = $derived(`${startHour}:${startMinute}:${startPeriod}`);
	let endSelectValue = $derived(`${endHour}:${endMinute}:${endPeriod}`);

	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 };
	}

	let overlappingBookings = $state<OverlappingBooking[]>([]);
	let hasOverlap = $state(false);
	const hasDayConflicts = $derived(overlappingBookings.length > 0);

	let showDeleteAlert = $state(false);
	let blockerToDelete = $state<TimeBlocker | null>(null);

	let currentPage = $state(1);

	let defaultHours = $state<WorkingHourRow[]>([]);
	let hoursLoading = $state(true);

	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 timeToMinutes(time: string): number {
		const [h, m] = time.split(':').map(Number);
		return h * 60 + m;
	}

	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) h -= 12;
		if (h === 0) h = 12;
		return { hour: String(h), minute: String(m).padStart(2, '0'), period };
	}

	function getWorkingHoursForDate(dateStr: string): WorkingHourRow | null {
		if (!dateStr || defaultHours.length === 0) return null;
		const d = new SvelteDate(dateStr + 'T00:00:00Z');
		const jsDay = d.getDay();
		const weekday = jsDay === 0 ? 6 : jsDay - 1;
		return defaultHours.find((h) => h.weekday === weekday) ?? null;
	}

	function workingHoursSignature(row: WorkingHourRow | null): string {
		if (!row) return '';
		return `${row.startTime}-${row.endTime}-${row.isOpen}`;
	}

	const selectedWorkingHours = $derived.by(() => getWorkingHoursForDate(newStartDate));

	const availableStartOptions = $derived.by(() => {
		const wh = selectedWorkingHours;
		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);
			const isStart = m === startMin;
			options.push({
				...t,
				totalMin: m,
				label: `${t.hour}:${t.minute} ${t.period}${t.period === 'PM' && t.hour === '12' && t.minute === '00' ? ' (noon)' : ''}${isStart ? ' (start of day)' : ''}`
			});
		}
		return options;
	});

	const availableEndOptions = $derived.by(() => {
		const wh = selectedWorkingHours;
		if (!wh || !wh.isOpen) return [];
		const startMin = timeToMinutes(wh.startTime);
		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(startMin, currentStartMin + 15); m <= endMin; m += 15) {
			const t = minutesTo12h(m);
			const isEnd = m === endMin;
			options.push({
				...t,
				totalMin: m,
				label: `${t.hour}:${t.minute} ${t.period}${t.period === 'PM' && t.hour === '12' && t.minute === '00' ? ' (noon)' : ''}${isEnd ? ' (end of day)' : ''}`
			});
		}
		return options;
	});

	function formatRelativeTime(iso: string): string {
		const d = new SvelteDate(iso);
		const now = new SvelteDate();
		const diffMs = d.getTime() - now.getTime();
		if (diffMs < 0) {
			const absMin = Math.floor(Math.abs(diffMs) / 60000);
			if (absMin < 60) return `${absMin}m ago`;
			const absHr = Math.floor(absMin / 60);
			if (absHr < 24) return `${absHr}h ago`;
			return `${Math.floor(absHr / 24)}d ago`;
		}
		const min = Math.floor(diffMs / 60000);
		if (min < 60) return `in ${min}m`;
		const hr = Math.floor(min / 60);
		if (hr < 24) return `in ${hr}h`;
		return `in ${Math.floor(hr / 24)}d`;
	}

	const sortedBlockers = $derived.by(() => {
		return [...blockers].sort(
			(a, b) => new SvelteDate(a.start_time).getTime() - new SvelteDate(b.start_time).getTime()
		);
	});

	const totalPages = $derived.by(() => Math.max(1, Math.ceil(sortedBlockers.length / PAGE_SIZE)));
	const pagedBlockers = $derived.by(() => {
		const start = (currentPage - 1) * PAGE_SIZE;
		return sortedBlockers.slice(start, start + PAGE_SIZE);
	});

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

	async function fetchBlockers() {
		loading = true;
		try {
			const response = await apiFetch('/api/admin/time-blockers', {
				headers: {
					'Content-Type': 'application/json'
				}
			});

			if (response.ok) {
				const data: TimeBlocker[] = await response.json();
				blockers = (data || []).filter((b) => !isAutoGenerated(b));
			} else {
				toast.error('Failed to load time blockers');
			}
		} catch (err) {
			console.error('Error fetching time blockers:', err);
			toast.error('Network error loading time blockers');
		} finally {
			loading = false;
		}
	}

	async function fetchDefaultHours() {
		hoursLoading = true;
		try {
			const response = await apiFetch('/api/scheduling/default-hours', {
				headers: {
					'Content-Type': 'application/json'
				}
			});

			if (response.ok) {
				defaultHours = await response.json();
			}
		} catch (err) {
			console.error('Error fetching default hours:', err);
		} finally {
			hoursLoading = 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 formComplete = $derived.by(() => {
		return (
			newDescription.trim() !== '' && newStartDate !== '' && startHour !== '' && endHour !== ''
		);
	});

	const canCreate = $derived.by(() => {
		return formComplete && !hasOverlap && !hasDayConflicts && !checkingOverlap;
	});

	async function checkOverlappingBookings() {
		const startIso = buildDateTime(newStartDate, startHour, startMinute, startPeriod);
		const endIso = buildDateTime(newStartDate, 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 dateParam = newStartDate;
			const response = await apiFetch(
				`/api/admin/bookings/by-date-range?start=${encodeURIComponent(dateParam)}&end=${encodeURIComponent(dateParam)}`,
				{
					headers: {
						'Content-Type': 'application/json'
					}
				}
			);

			if (response.ok) {
				const data = await response.json();
				const allBookings: OverlappingBooking[] = data.bookings || [];
				// Client-side filter: only bookings that overlap with the proposed blocker timespan
				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;
		}
	}

	let prevWorkingHoursSig = $state('');

	function onStartTimeChange() {
		checkOverlappingBookings();
	}

	function onEndTimeChange() {
		checkOverlappingBookings();
	}

	function onStartDateChange() {
		const wh = getWorkingHoursForDate(newStartDate);
		const sig = workingHoursSignature(wh);

		if (sig !== prevWorkingHoursSig && prevWorkingHoursSig !== '') {
			resetTimeToDefaults(wh);
		}
		prevWorkingHoursSig = sig;
		checkOverlappingBookings();
	}

	function resetTimeToDefaults(wh: WorkingHourRow | null) {
		if (!wh || !wh.isOpen) {
			startHour = '9';
			startMinute = '00';
			startPeriod = 'AM';
			endHour = '10';
			endMinute = '00';
			endPeriod = 'AM';
			return;
		}

		const startOpt = minutesTo12h(timeToMinutes(wh.startTime));
		const endOpt = minutesTo12h(timeToMinutes(wh.startTime) + 60);

		startHour = startOpt.hour;
		startMinute = startOpt.minute;
		startPeriod = startOpt.period;
		endHour = endOpt.hour;
		endMinute = endOpt.minute;
		endPeriod = endOpt.period;
	}

	async function createBlocker() {
		if (!canCreate) return;

		const startIso = buildDateTime(newStartDate, startHour, startMinute, startPeriod);
		const endIso = buildDateTime(newStartDate, 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 {
			// Create placeholder blockers for conflicting bookings (1-hour TTL)
			if (overlappingBookings.length > 0) {
				for (const booking of overlappingBookings) {
					try {
						await apiFetch('/api/admin/time-blockers', {
							method: 'POST',
							headers: {
								'Content-Type': 'application/json'
							},
							body: JSON.stringify({
								start_time: startIso,
								duration_minutes: 60,
								description: `RESERVATION:placeholder:${booking.id}`
							})
						});
					} catch (placeholderErr) {
						console.error('Failed to create placeholder for booking', booking.id, placeholderErr);
					}
				}
			}

			// Create the actual time blocker
			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()
				})
			});

			if (response.ok) {
				toast.success('Time blocker created!', { id: loadingToast });
				showCreateModal = false;
				resetCreateForm();
				await fetchBlockers();
			} 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 fetchBlockers();
			} 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 = '';
		newStartDate = '';
		startHour = '9';
		startMinute = '00';
		startPeriod = 'AM';
		endHour = '10';
		endMinute = '00';
		endPeriod = 'AM';
		overlappingBookings = [];
		hasOverlap = false;
		prevWorkingHoursSig = '';
	}

	function openCreateModal() {
		resetCreateForm();
		showCreateModal = true;
	}

	$effect(() => {
		fetchBlockers();
	});

	$effect(() => {
		if (defaultHoursProp !== undefined) {
			if (defaultHoursProp.length > 0) {
				defaultHours = defaultHoursProp;
			}
			hoursLoading = false;
		} else {
			fetchDefaultHours();
		}
	});

	$effect(() => {
		if (showCreateModal) {
			currentPage = 1;
		}
	});

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

<Card.Root>
	<Card.Header>
		<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
			<div>
				<Card.Title>Time Blockers</Card.Title>
				<Card.Description>
					Manage one-off blocked periods like appointments, breaks, or closures.
				</Card.Description>
			</div>
			<Button variant="default" onclick={openCreateModal}>
				<svg
					xmlns="http://www.w3.org/2000/svg"
					class="mr-2 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>
				New Blocker
			</Button>
		</div>
	</Card.Header>

	<Card.Content class="space-y-4">
		{#if loading}
			<div class="space-y-3">
				{#each Array(3) as _, i (i)}
					<Skeleton class="h-16 w-full" />
				{/each}
			</div>
		{:else if blockers.length === 0}
			<p class="text-sm text-gray-500">No time blockers found.</p>
		{:else}
			<div class="space-y-3">
				{#each pagedBlockers as b (b.id)}
					<div
						class="flex items-center justify-between gap-3 rounded-lg border p-3 transition-all hover:shadow-sm sm:p-4"
					>
						<div class="flex min-w-0 flex-1 items-center gap-3">
							<div class="hidden shrink-0 rounded-lg bg-gray-50 p-1.5 sm:block">
								<svg
									xmlns="http://www.w3.org/2000/svg"
									class="h-4 w-4 text-gray-600"
									viewBox="0 0 24 24"
									fill="none"
									stroke="currentColor"
									stroke-width="2"
								>
									<rect x="3" y="4" width="18" height="18" rx="2" ry="2" />
									<line x1="16" y1="2" x2="16" y2="6" />
									<line x1="8" y1="2" x2="8" y2="6" />
									<line x1="3" y1="10" x2="21" y2="10" />
								</svg>
							</div>
							<div class="min-w-0">
								<div class="truncate font-medium text-gray-900">{b.description || 'Untitled'}</div>
								<div class="flex flex-wrap items-center gap-x-2 gap-y-0.5 text-sm text-gray-600">
									<span>
										{parseWallClockDate(b.start_time).toLocaleDateString('en-GB', {
											weekday: 'short',
											day: 'numeric',
											month: 'short'
										})}
									</span>
									<span class="text-gray-400">·</span>
									<span>
										{parseWallClockDate(b.start_time).toLocaleTimeString('en-GB', {
											hour: 'numeric',
											minute: '2-digit',
											hour12: true
										})}
									</span>
									<span class="text-gray-400">–</span>
									<span>
										{(() => {
											const end = parseWallClockDate(b.start_time);
											end.setMinutes(end.getMinutes() + b.duration_minutes);
											return end.toLocaleTimeString('en-GB', {
												hour: 'numeric',
												minute: '2-digit',
												hour12: true
											});
										})()}
									</span>
									<span class="rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium">
										{formatDuration(b.duration_minutes)}
									</span>
								</div>
								<div class="text-xs text-gray-400">
									{formatRelativeTime(b.start_time)}
								</div>
							</div>
						</div>
						<Button
							variant="destructive"
							size="sm"
							class="shrink-0"
							onclick={() => {
								blockerToDelete = b;
								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>
				{/each}
			</div>

			{#if totalPages > 1}
				<div
					class="flex flex-col-reverse gap-2 pt-2 sm:flex-row sm:items-center sm:justify-between"
				>
					<p class="text-sm text-gray-500">
						{(currentPage - 1) * PAGE_SIZE + 1}–{Math.min(
							currentPage * PAGE_SIZE,
							sortedBlockers.length
						)} of {sortedBlockers.length}
					</p>
					<div class="flex items-center gap-1">
						<Button
							variant="outline"
							size="sm"
							disabled={currentPage <= 1}
							onclick={() => (currentPage -= 1)}
						>
							Prev
						</Button>
						{#each Array(totalPages) as _, i (i)}
							<Button
								variant={currentPage === i + 1 ? 'default' : 'outline'}
								size="sm"
								class="h-8 w-8 p-0"
								onclick={() => (currentPage = i + 1)}
							>
								{i + 1}
							</Button>
						{/each}
						<Button
							variant="outline"
							size="sm"
							disabled={currentPage >= totalPages}
							onclick={() => (currentPage += 1)}
						>
							Next
						</Button>
					</div>
				</div>
			{/if}
		{/if}
	</Card.Content>
</Card.Root>

<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">Create Time Blocker</Modal.Title>
			<Modal.Description>
				Block off a period of time so no bookings can be made during it.
			</Modal.Description>
		</Modal.Header>

		<div class="space-y-6 px-4 pb-4">
			<div class="space-y-2">
				<label for="blocker-description" class="text-sm font-medium">Description *</label>
				<Input
					id="blocker-description"
					type="text"
					placeholder="e.g., Extended lunch, Doctor's appointment, Illness"
					bind:value={newDescription}
				/>
			</div>

			<Separator />

			<div class="space-y-4">
				<h3 class="text-sm font-medium">Start</h3>
				<div class="grid grid-cols-1 gap-3 sm:grid-cols-2">
					<div class="space-y-2">
						<label for="blocker-start-date" class="text-xs text-gray-600">Date</label>
						<div class="flex gap-2">
							<Button
								type="button"
								variant="outline"
								size="sm"
								class="flex-1 text-xs"
								onclick={() => {
									newStartDate = new Date().toLocaleDateString('en-CA', {
										timeZone: 'Europe/London'
									});
									onStartDateChange();
								}}
							>
								Today
							</Button>
							<Button
								type="button"
								variant="outline"
								size="sm"
								class="flex-1 text-xs"
								onclick={() => {
									newStartDate = new Date(Date.now() + 86400000).toLocaleDateString('en-CA', {
										timeZone: 'Europe/London'
									});
									onStartDateChange();
								}}
							>
								Tomorrow
							</Button>
						</div>
						<Input
							id="blocker-start-date"
							type="date"
							bind:value={newStartDate}
							onchange={onStartDateChange}
						/>
					</div>
					<div class="space-y-2">
						<div class="text-xs text-gray-600">Time</div>
						{#if hoursLoading}
							<Skeleton class="h-9 w-full" />
						{:else if !selectedWorkingHours}
							<p class="text-sm text-gray-400">Select a date first</p>
						{:else if !selectedWorkingHours.isOpen}
							<p class="text-sm text-red-500">
								Closed on {new SvelteDate(newStartDate + 'T00:00:00Z').toLocaleDateString('en-GB', {
									weekday: 'long'
								})}
							</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;
									onStartTimeChange();
								}}
							>
								{#each availableStartOptions as opt (opt.totalMin)}
									<option value={`${opt.hour}:${opt.minute}:${opt.period}`}>
										{opt.label}
									</option>
								{/each}
							</select>
						{/if}
					</div>
				</div>
			</div>

			<Separator />

			<div class="space-y-4">
				<h3 class="text-sm font-medium">End Time</h3>
				{#if hoursLoading}
					<Skeleton class="h-9 w-full" />
				{:else if !selectedWorkingHours}
					<p class="text-sm text-gray-400">Select a date first</p>
				{:else if !selectedWorkingHours.isOpen}
					<p class="text-sm text-red-500">Closed on this day</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;
							onEndTimeChange();
						}}
					>
						{#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-4">
					<div class="mb-3 flex items-center gap-2">
						<svg
							xmlns="http://www.w3.org/2000/svg"
							class="h-4 w-4 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">
							{overlappingBookings.length} booking{overlappingBookings.length > 1 ? 's' : ''} conflict{overlappingBookings.length >
							1
								? ''
								: 's'} with this slot
						</span>
					</div>
					<div class="space-y-3">
						{#each overlappingBookings as booking (booking.id)}
							<div class="rounded-md border border-amber-200 bg-white p-3">
								<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">
										{parseWallClockDate(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-2 flex gap-2">
									{#if openBookingModal}
										<Button
											variant="outline"
											size="sm"
											class="h-7 text-xs"
											onclick={() => openBookingModal(booking.id)}
										>
											View Booking
										</Button>
									{/if}
									{#if openUserModal && booking.user?.id}
										<Button
											variant="outline"
											size="sm"
											class="h-7 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}>
				{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. Bookings may become
				available during this period. 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>
