<script lang="ts">
	import { SvelteDate } from 'svelte/reactivity';
	import { toast } from 'svelte-sonner';
	import { sanitizeText } from '$lib/utils/toast-safe';
	import { apiFetch } from '$lib/utils/api';

	// shadcn-svelte components
	import { Button } from '$lib/components/ui/button';
	import * as Card from '$lib/components/ui/card';
	import { Input } from '$lib/components/ui/input';
	import { Checkbox } from '$lib/components/ui/checkbox';
	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';

	const TIME15 = ['00', '15', '30', '45'];

	// =============== Types ===============
	type WorkingHourRow = {
		weekday: number;
		start_time: string;
		end_time: string;
		is_open: boolean;
	};

	type ExceptionGroup = {
		id?: number;
		name: string;
		description: string;
		weekStarts: string[];
		hours: WorkingHourRow[];
	};

	// =============== State ===============
	let exceptionGroups = $state<ExceptionGroup[]>([]);
	let exceptionGroupsLoading = $state(true);
	let savingHours = $state(false);

	const formErrors = $state({
		name: '',
		weeks: ''
	});

	// Exception modal state
	let showExceptionModal = $state(false);
	let exceptionDraft = $state<ExceptionGroup>({
		name: '',
		description: '',
		weekStarts: [],
		hours: [
			{ weekday: 0, start_time: '00:00', end_time: '00:00', is_open: false },
			{ weekday: 1, start_time: '09:00', end_time: '17:00', is_open: true },
			{ weekday: 2, start_time: '09:00', end_time: '17:00', is_open: true },
			{ weekday: 3, start_time: '09:00', end_time: '17:00', is_open: true },
			{ weekday: 4, start_time: '12:00', end_time: '20:00', is_open: true },
			{ weekday: 5, start_time: '09:00', end_time: '17:00', is_open: true },
			{ weekday: 6, start_time: '00:00', end_time: '00:00', is_open: false }
		]
	});

	const isFormValid = $derived(
		exceptionDraft.name.trim() !== '' && exceptionDraft.weekStarts.length > 0
	);

	function validateNameField() {
		formErrors.name = exceptionDraft.name.trim() === '' ? 'Name is required' : '';
	}

	function validateWeeksField() {
		formErrors.weeks =
			exceptionDraft.weekStarts.length === 0 ? 'At least one week must be selected' : '';
	}

	function validateAllFields() {
		validateNameField();
		validateWeeksField();
	}

	let weekRangeFrom = $state('');
	let weekRangeTo = $state('');

	// Delete confirmation state
	let showDeleteExceptionAlert = $state(false);
	let exceptionToDelete = $state<number | undefined>(undefined);

	// View exception state
	let showViewExceptionModal = $state(false);
	let viewingException = $state<ExceptionGroup | null>(null);

	const dayNames = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];

	// =============== Helper Functions ===============
	function weekdayLabel(i: number) {
		return dayNames[i];
	}

	function isoDateOf(d: Date) {
		const y = d.getFullYear();
		const m = String(d.getMonth() + 1).padStart(2, '0');
		const day = String(d.getDate()).padStart(2, '0');
		return `${y}-${m}-${day}`;
	}

	function addWeeksToException(fromISO: string, toISO: string, dest: string[]) {
		const from = new SvelteDate(fromISO + 'T00:00:00Z');
		const to = new SvelteDate(toISO + 'T00:00:00Z');
		const first = new SvelteDate(from);
		const day = first.getDay();
		const daysToMonday = day === 0 ? -6 : 1 - day;

		// Set to the Monday of the current week
		first.setDate(first.getDate() + daysToMonday);

		// Add all Mondays in the range
		for (let d = new SvelteDate(first); d <= to; d.setDate(d.getDate() + 7)) {
			dest.push(isoDateOf(new SvelteDate(d)));
		}
	}

	/** Format time from HH:MM:SS to 12-hour format, with "Noon" for 12:00 PM */
	function formatTime(time: string): string {
		const [hours, minutes] = time.split(':').map(Number);

		// Special case for 12:00
		if (hours === 12 && minutes === 0) {
			return 'Noon';
		} else 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}`;
	}

	// =============== API Functions ===============
	async function fetchExceptionGroups() {
		exceptionGroupsLoading = true;
		try {
			const response = await apiFetch('/api/scheduling/exceptional-groups', {
				headers: {
					'Content-Type': 'application/json'
				}
			});

			if (response.ok) {
				const data = await response.json();
				if (data === null || data.length === 0) {
					return;
				}
				exceptionGroups = data.map((group: ExceptionGroup) => ({
					id: group.id,
					name: group.name,
					description: group.description,
					weekStarts: group.weekStarts || [],
					hours:
						// eslint-disable-next-line @typescript-eslint/no-explicit-any
						(group.hours as any[])?.map(
							(h: {
								id: number;
								weekday: number;
								startTime: string;
								endTime: string;
								isOpen: boolean;
							}) => ({
								id: h.id,
								weekday: h.weekday,
								start_time: formatTime(h.startTime),
								end_time: formatTime(h.endTime),
								is_open: h.isOpen
							})
						) || []
				}));
			} else {
				console.error('Failed to fetch exception groups:', response.status);
				toast.error('Failed to load exception groups');
			}
		} catch (err) {
			console.error('Error fetching exception groups:', err);
			toast.error('Network error loading exception groups');
		} finally {
			exceptionGroupsLoading = false;
		}
	}

	async function saveExceptionGroup() {
		validateAllFields();
		if (!isFormValid) {
			toast.error('Please fix validation errors before submitting');
			return;
		}

		savingHours = true;
		const loadingToast = toast.loading('Creating exception group...');

		try {
			// Map to API format
			const payload = {
				name: exceptionDraft.name,
				description: exceptionDraft.description,
				weekStarts: exceptionDraft.weekStarts,
				hours: exceptionDraft.hours.map((h) => ({
					weekday: h.weekday,
					startTime: h.start_time,
					endTime: h.end_time,
					isOpen: h.is_open
				}))
			};

			const response = await apiFetch('/api/scheduling/exceptional-groups', {
				method: 'POST',
				headers: {
					'Content-Type': 'application/json'
				},
				body: JSON.stringify(payload)
			});

			if (response.ok) {
				toast.success('Exception group created successfully!', { id: loadingToast });
				showExceptionModal = false;
				resetExceptionForm();
				await fetchExceptionGroups();
			} else {
				const text = await response.text();
				toast.error('Failed to create: ' + sanitizeText(text), { id: loadingToast });
			}
		} catch (err) {
			console.error('Error creating exception group:', err);
			toast.error('Network error creating exception group', { id: loadingToast });
		} finally {
			savingHours = false;
		}
	}

	async function confirmDeleteExceptionGroup() {
		if (exceptionToDelete === undefined) return;

		const loadingToast = toast.loading('Deleting exception group...');

		try {
			const response = await apiFetch(
				`/api/scheduling/exceptional-groups?id=${exceptionToDelete}`,
				{
					method: 'DELETE'
				}
			);

			if (response.ok || response.status === 204) {
				toast.success('Exception group deleted successfully!', { id: loadingToast });
				showDeleteExceptionAlert = false;
				exceptionToDelete = undefined;
				// Refresh the exception groups list
				await fetchExceptionGroups();
			} else {
				const text = await response.text();
				toast.error('Failed to delete: ' + sanitizeText(text), { id: loadingToast });
			}
		} catch (err) {
			console.error('Error deleting exception group:', err);
			toast.error('Network error deleting exception group', { id: loadingToast });
		}
	}

	// =============== UI Actions ===============
	function resetExceptionForm() {
		exceptionDraft = {
			name: '',
			description: '',
			weekStarts: [],
			hours: [
				{ weekday: 0, start_time: '00:00', end_time: '00:00', is_open: false },
				{ weekday: 1, start_time: '09:00', end_time: '17:00', is_open: true },
				{ weekday: 2, start_time: '09:00', end_time: '17:00', is_open: true },
				{ weekday: 3, start_time: '09:00', end_time: '17:00', is_open: true },
				{ weekday: 4, start_time: '12:00', end_time: '20:00', is_open: true },
				{ weekday: 5, start_time: '09:00', end_time: '17:00', is_open: true },
				{ weekday: 6, start_time: '00:00', end_time: '00:00', is_open: false }
			]
		};
		weekRangeFrom = '';
		weekRangeTo = '';
	}

	function createNewException() {
		resetExceptionForm();
		showExceptionModal = true;
	}

	function addWeekRange() {
		if (!weekRangeFrom || !weekRangeTo) {
			toast.error('Please select both start and end dates');
			return;
		}

		addWeeksToException(weekRangeFrom, weekRangeTo, exceptionDraft.weekStarts);
		weekRangeFrom = '';
		weekRangeTo = '';
	}

	function removeWeek(index: number) {
		exceptionDraft.weekStarts = exceptionDraft.weekStarts.filter((_, i) => i !== index);
	}

	function openViewExceptionModal(exception: ExceptionGroup) {
		viewingException = exception;
		showViewExceptionModal = true;
	}

	// =============== Effects ===============
	$effect(() => {
		fetchExceptionGroups();
	});
</script>

<Card.Root>
	<Card.Header>
		<div class="flex items-center justify-between">
			<div>
				<Card.Title>Holiday Hours</Card.Title>
				<Card.Description>
					Manage temporary schedules for holidays, closures, and special events.
				</Card.Description>
			</div>
			<Button variant="default" onclick={createNewException}>
				<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 Schedule
			</Button>
		</div>
	</Card.Header>

	<Card.Content class="space-y-4">
		{#if exceptionGroupsLoading}
			<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
				{#each Array(2) as _, i (i)}
					<Skeleton class="h-32 w-full" />
				{/each}
			</div>
		{:else}
			<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
				{#if exceptionGroups.length === 0}
					<p class="col-span-2 text-sm text-gray-500">No exception groups found.</p>
				{/if}

				{#each exceptionGroups as g (g.weekStarts)}
					<div class="group relative h-full rounded-lg border p-4 transition-all">
						<div class="flex h-full flex-col gap-3">
							<div class="flex-1">
								<div class="mb-2 flex items-start justify-between">
									<div class="flex items-center gap-2">
										<div class="rounded-lg bg-gray-50 p-2">
											<svg
												xmlns="http://www.w3.org/2000/svg"
												class="h-4 w-4"
												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>
										<h3 class="font-semibold text-gray-900">{g.name}</h3>
									</div>
									<span class="rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium">
										{g.weekStarts?.length || 0} weeks
									</span>
								</div>

								<p class="mb-3 text-sm text-gray-600">{g.description}</p>

								<div class="rounded-lg bg-gray-50 p-2">
									<div class="mb-1 text-xs font-medium text-gray-500">Applies to weeks:</div>
									<div class="text-xs text-gray-700">
										{g.weekStarts
											?.slice(0, 3)
											.map((w) =>
												new SvelteDate(w).toLocaleDateString('en-GB', {
													day: 'numeric',
													month: 'short'
												})
											)
											.join(', ')}
										{#if (g.weekStarts?.length ?? 0) > 3}
											<span class="text-gray-500"> (+{(g.weekStarts?.length ?? 0) - 3} more)</span>
										{/if}
									</div>
								</div>
							</div>

							<div class="flex gap-2 border-t pt-2">
								<Button
									variant="outline"
									size="sm"
									onclick={() => openViewExceptionModal(g)}
									class="flex-1"
								>
									<svg
										xmlns="http://www.w3.org/2000/svg"
										class="mr-1 h-3 w-3"
										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>
									View Details
								</Button>
								<Button
									variant="destructive"
									size="sm"
									onclick={() => {
										exceptionToDelete = g.id;
										showDeleteExceptionAlert = 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>
						</div>
					</div>
				{/each}
			</div>
		{/if}
	</Card.Content>
</Card.Root>

<!-- Exception Group Modal -->
<Modal.Root bind:open={showExceptionModal}>
	<Modal.Content class="max-h-[90vh] max-w-2xl overflow-y-auto">
		<Modal.Header>
			<Modal.Title class="text-lg font-semibold">Create Exception Schedule</Modal.Title>
			<Modal.Description>
				Define custom working hours for holidays, closures, or special events.
			</Modal.Description>
		</Modal.Header>

		<div class="space-y-6 px-4 pb-4">
			<!-- Basic Info -->
			<div class="space-y-4">
				<div class="space-y-2">
					<label for="exception-name" class="text-sm font-medium">Schedule Name *</label>
					<Input
						id="exception-name"
						type="text"
						placeholder="e.g., Christmas Week, Summer Holiday"
						bind:value={exceptionDraft.name}
						onblur={validateNameField}
						class="w-full {formErrors.name ? 'border-red-500' : ''}"
					/>
					{#if formErrors.name}
						<p class="text-xs text-red-600">{formErrors.name}</p>
					{/if}
				</div>

				<div class="space-y-2">
					<label for="exception-description" class="text-sm font-medium">Description</label>
					<Input
						id="exception-description"
						type="text"
						placeholder="Brief description of the service, will be shown to customers"
						bind:value={exceptionDraft.description}
					/>
				</div>
			</div>

			<Separator />

			<!-- Week Selection -->
			<div class="space-y-4">
				<div>
					<h3 class="mb-2 text-sm font-medium">Apply to Weeks *</h3>
					<p class="mb-3 text-xs text-gray-500">
						Select a date range to add all Mondays within that range
					</p>

					<div class="grid grid-cols-1 gap-3 md:grid-cols-2">
						<div class="space-y-2">
							<label for="week-from" class="text-xs text-gray-600">From Date</label>
							<Input id="week-from" type="date" bind:value={weekRangeFrom} />
						</div>
						<div class="space-y-2">
							<label for="week-to" class="text-xs text-gray-600">To Date</label>
							<Input id="week-to" type="date" bind:value={weekRangeTo} />
						</div>
					</div>

					<Button variant="outline" size="sm" onclick={addWeekRange} class="mt-3">
						Add Week Range
					</Button>
				</div>

				{#if exceptionDraft.weekStarts.length > 0}
					<div class="space-y-2">
						<div class="text-xs text-gray-600">
							Selected weeks ({exceptionDraft.weekStarts.length}):
						</div>
						<div class="max-h-32 space-y-1 overflow-y-auto rounded border p-2">
							{#each exceptionDraft.weekStarts as week, index (week)}
								<div class="flex items-center justify-between text-sm">
									<span>Week starting: {week}</span>
									<button
										class="text-xs text-red-500 hover:text-red-700"
										onclick={() => removeWeek(index)}
									>
										Remove
									</button>
								</div>
							{/each}
						</div>
					</div>
				{/if}
			</div>

			<Separator />

			<!-- Working Hours -->
			<div class="space-y-4">
				<h3 class="text-sm font-medium">Working Hours for these Weeks *</h3>
				<div class="w-full overflow-x-auto">
					<table class="w-full table-auto text-sm">
						<thead>
							<tr class="text-left text-xs text-gray-500">
								<th class="py-2">Day</th>
								<th class="py-2">Open</th>
								<th class="py-2">Start</th>
								<th class="py-2">End</th>
							</tr>
						</thead>
						<tbody>
							{#each exceptionDraft.hours as row (row.weekday)}
								<tr class="border-t">
									<td class="py-2">{weekdayLabel(row.weekday)}</td>
									<td class="py-2">
										<Checkbox bind:checked={row.is_open} />
									</td>
									<td class="py-2">
										<select
											bind:value={row.start_time}
											disabled={!row.is_open}
											class="flex h-9 w-24 rounded-md border border-input bg-background px-2 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"
										>
											{#each Array(24) as _, hour (hour)}
												{#each TIME15 as min (min)}
													<option value="{String(hour).padStart(2, '0')}:{min}"
														>{String(hour).padStart(2, '0')}:{min}</option
													>
												{/each}
											{/each}
										</select>
									</td>
									<td class="py-2">
										<select
											bind:value={row.end_time}
											disabled={!row.is_open}
											class="flex h-9 w-24 rounded-md border border-input bg-background px-2 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"
										>
											{#each Array(24) as _, hour (hour)}
												{#each TIME15 as min (min)}
													<option value="{String(hour).padStart(2, '0')}:{min}"
														>{String(hour).padStart(2, '0')}:{min}</option
													>
												{/each}
											{/each}
										</select>
									</td>
								</tr>
							{/each}
						</tbody>
					</table>
				</div>
			</div>
		</div>

		<Modal.Footer class="flex items-center justify-end gap-2">
			<Button
				variant="outline"
				onclick={() => {
					showExceptionModal = false;
					resetExceptionForm();
				}}
				disabled={savingHours}
			>
				Cancel
			</Button>
			<Button onclick={saveExceptionGroup} disabled={savingHours || !isFormValid}>
				{savingHours ? 'Creating…' : 'Create Schedule'}
			</Button>
		</Modal.Footer>
	</Modal.Content>
</Modal.Root>

<!-- Delete Exception Confirmation -->
<AlertDialog.Root bind:open={showDeleteExceptionAlert}>
	<AlertDialog.Content class="z-60">
		<AlertDialog.Header>
			<AlertDialog.Title>Delete exception group?</AlertDialog.Title>
			<AlertDialog.Description>
				This action cannot be undone. This will permanently delete this exception group and all its
				associated schedule rows.
			</AlertDialog.Description>
		</AlertDialog.Header>
		<AlertDialog.Footer>
			<AlertDialog.Cancel
				onclick={() => {
					exceptionToDelete = undefined;
				}}
			>
				Cancel
			</AlertDialog.Cancel>
			<AlertDialog.Action onclick={confirmDeleteExceptionGroup}>Delete</AlertDialog.Action>
		</AlertDialog.Footer>
	</AlertDialog.Content>
</AlertDialog.Root>

<!-- View Exception Modal -->
{#if viewingException}
	<Modal.Root bind:open={showViewExceptionModal}>
		<Modal.Content class="max-h-[90vh] max-w-2xl overflow-y-auto">
			<Modal.Header>
				<Modal.Title class="text-lg font-semibold">{viewingException.name}</Modal.Title>
				<Modal.Description>
					{viewingException.description || 'Holiday schedule details'}
				</Modal.Description>
			</Modal.Header>

			<div class="space-y-6 px-4 pb-4">
				<!-- Applied Weeks -->
				<div class="space-y-2">
					<h3 class="text-sm font-medium">Applied to Weeks</h3>
					<div class="max-h-48 space-y-1 overflow-y-auto rounded border bg-gray-50 p-3">
						{#if viewingException.weekStarts && viewingException.weekStarts.length > 0}
							<div class="grid grid-cols-2 gap-2 md:grid-cols-3">
								{#each viewingException.weekStarts as week (week)}
									<div class="text-sm">
										Week of {new SvelteDate(week).toLocaleDateString('en-GB', {
											day: 'numeric',
											month: 'short',
											year: 'numeric'
										})}
									</div>
								{/each}
							</div>
						{:else}
							<p class="text-sm text-gray-500">No weeks specified</p>
						{/if}
					</div>
				</div>

				<Separator />

				<!-- Working Hours -->
				<div class="space-y-4">
					<h3 class="text-sm font-medium">Working Hours</h3>
					<div class="w-full overflow-x-auto">
						<table class="w-full table-auto">
							<thead>
								<tr class="text-left text-xs text-gray-500">
									<th class="py-2">Day</th>
									<th class="py-2">Status</th>
									<th class="py-2">Start</th>
									<th class="py-2">End</th>
								</tr>
							</thead>
							<tbody>
								{#each viewingException.hours as row (row.weekday)}
									<tr class="border-t">
										<td class="py-2 text-sm">{weekdayLabel(row.weekday)}</td>
										<td class="py-2">
											<span
												class="text-sm font-medium {row.is_open
													? 'text-emerald-600'
													: 'text-red-600'}"
											>
												{row.is_open ? 'Open' : 'Closed'}
											</span>
										</td>
										<td class="py-2 text-sm">
											{row.is_open ? row.start_time : '—'}
										</td>
										<td class="py-2 text-sm">
											{row.is_open ? row.end_time : '—'}
										</td>
									</tr>
								{/each}
							</tbody>
						</table>
					</div>
				</div>
			</div>

			<Modal.Footer class="flex items-center justify-end gap-2">
				<Button onclick={() => (showViewExceptionModal = false)}>Close</Button>
			</Modal.Footer>
		</Modal.Content>
	</Modal.Root>
{/if}
