<script lang="ts">
	import { toast } from 'svelte-sonner';
	import { Button } from '$lib/components/ui/button';
	import { apiFetch } from '$lib/utils/api';
	import * as Card from '$lib/components/ui/card';
	import { Input } from '$lib/components/ui/input';
	import { Checkbox } from '$lib/components/ui/checkbox';
	import { Skeleton } from '$lib/components/ui/skeleton';
	import * as Modal from '$lib/components/ui/dialog';
	import { SvelteMap } from 'svelte/reactivity';

	type Service = {
		id: string;
		name: string;
	};

	type PatchTest = {
		id: string;
		name: string;
		description: string | null;
		notice_duration_hours: number;
		expiry_months: number;
		service_ids: string[];
	};

	interface Props {
		services?: Service[];
	}

	let { services: servicesProp }: Props = $props();

	let patchTests = $state<PatchTest[]>([]);
	let availableServices = $state<Service[]>([]);
	let loading = $state(true);
	let isSubmitting = $state(false);

	let showModal = $state(false);
	let isEditing = $state(false);

	let formData = $state({
		id: '',
		name: '',
		description: '',
		notice_duration_hours: 48,
		expiry_months: 6,
		service_ids: [] as string[]
	});

	let formErrors = $state({
		name: '',
		notice_duration: '',
		expiry: ''
	});

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

	function validateNoticeDurationField() {
		const val = formData.notice_duration_hours as number | null | undefined;
		if (val === null || val === undefined) {
			formErrors.notice_duration = 'Must be a positive number';
			return;
		}
		const num = Number(val);
		if (isNaN(num) || num < 0 || !Number.isInteger(num)) {
			formErrors.notice_duration = 'Must be a positive whole number';
		} else {
			formErrors.notice_duration = '';
		}
	}

	function validateExpiryField() {
		const val = formData.expiry_months as number | null | undefined;
		if (val === null || val === undefined) {
			formErrors.expiry = 'Must be at least 1 month';
			return;
		}
		const num = Number(val);
		if (isNaN(num) || num < 1 || !Number.isInteger(num)) {
			formErrors.expiry = 'Must be a whole number of at least 1 month';
		} else {
			formErrors.expiry = '';
		}
	}

	function validateAllFields() {
		validateNameField();
		validateNoticeDurationField();
		validateExpiryField();
	}

	const isFormValid = $derived(
		formData.name.trim() !== '' &&
			!formErrors.name &&
			!formErrors.notice_duration &&
			!formErrors.expiry &&
			formData.notice_duration_hours !== null &&
			formData.notice_duration_hours !== undefined &&
			(formData.notice_duration_hours as number) >= 0 &&
			formData.expiry_months !== undefined &&
			Number(formData.expiry_months) >= 1
	);

	async function fetchData() {
		loading = true;
		try {
			const ptRes = await apiFetch('/api/admin/patch-tests');

			if (ptRes.ok) {
				patchTests = await ptRes.json();
			} else {
				toast.error('Failed to load patch test data');
			}

			// Only fetch services if not provided via prop
			if (!servicesProp) {
				const svcRes = await apiFetch('/api/admin/services');
				if (svcRes.ok) {
					const svcData = await svcRes.json();
					const uniqueSvc = new SvelteMap<string, Service>();
					svcData.forEach((s: Service) => {
						if (s.id) uniqueSvc.set(s.id, s);
					});
					availableServices = Array.from(uniqueSvc.values());
				}
			}
		} catch (err) {
			console.error(err);
			toast.error('Network error loading data');
		} finally {
			loading = false;
		}
	}

	function resetForm() {
		formData = {
			id: '',
			name: '',
			description: '',
			notice_duration_hours: 48,
			expiry_months: 6,
			service_ids: []
		};
		formErrors = {
			name: '',
			notice_duration: '',
			expiry: ''
		};
		isEditing = false;
	}

	function openAddModal() {
		resetForm();
		showModal = true;
	}

	function openEditModal(pt: PatchTest) {
		formData = {
			id: pt.id,
			name: pt.name,
			description: pt.description || '',
			notice_duration_hours: pt.notice_duration_hours,
			expiry_months: pt.expiry_months,
			service_ids: pt.service_ids || []
		};
		formErrors = {
			name: '',
			notice_duration: '',
			expiry: ''
		};
		isEditing = true;
		showModal = true;
	}

	function toggleServiceSelection(serviceId: string) {
		if (formData.service_ids.includes(serviceId)) {
			formData.service_ids = formData.service_ids.filter((id) => id !== serviceId);
		} else {
			formData.service_ids = [...formData.service_ids, serviceId];
		}
	}

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

		isSubmitting = true;
		const method = isEditing ? 'PUT' : 'POST';
		const url = isEditing ? `/api/admin/patch-tests/${formData.id}` : '/api/admin/patch-tests';

		const payload = {
			name: formData.name.trim(),
			description: formData.description.trim() || undefined,
			notice_duration_hours: Number(formData.notice_duration_hours),
			expiry_months: Number(formData.expiry_months),
			service_ids: formData.service_ids
		};

		try {
			const res = await apiFetch(url, {
				method,
				headers: {
					'Content-Type': 'application/json'
				},
				body: JSON.stringify(payload)
			});

			if (res.ok) {
				toast.success(`Patch test ${isEditing ? 'updated' : 'created'} successfully!`);
				showModal = false;
				await fetchData();
			} else {
				const errText = await res.text();
				toast.error(`Failed to save: ${errText}`);
			}
		} catch (err) {
			console.error(err);
			toast.error('Network error saving patch test');
		} finally {
			isSubmitting = false;
		}
	}

	async function deletePatchTest(id: string) {
		if (!confirm('Are you sure you want to delete this patch test requirement?')) return;

		try {
			const res = await apiFetch(`/api/admin/patch-tests/${id}`, {
				method: 'DELETE'
			});

			if (res.ok) {
				toast.success('Patch test deleted');
				await fetchData();
			} else {
				toast.error('Failed to delete patch test');
			}
		} catch (err) {
			console.error(err);
			toast.error('Network error deleting patch test');
		}
	}

	// Reactively update availableServices when the parent provides services via prop
	$effect(() => {
		if (servicesProp !== undefined) {
			availableServices = servicesProp;
		}
	});

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

<Card.Root>
	<Card.Header>
		<div class="flex items-center justify-between">
			<div>
				<Card.Title>Patch Test Management</Card.Title>
				<Card.Description>
					Create and manage patch test requirements and assign them to services.
				</Card.Description>
			</div>
			<Button onclick={openAddModal}>
				<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>
				Add Patch Test
			</Button>
		</div>
	</Card.Header>

	<Card.Content class="space-y-4">
		<div class="hidden w-full overflow-x-auto md:block">
			<table class="w-full table-auto border-collapse text-sm">
				<thead>
					<tr class="border-b text-left text-xs text-gray-500">
						<th class="w-[25%] py-3 font-medium">Name</th>
						<th class="w-[30%] py-3 font-medium">Description</th>
						<th class="w-[15%] py-3 text-center font-medium">Notice (hrs)</th>
						<th class="w-[15%] py-3 text-center font-medium">Expiry (months)</th>
						<th class="w-[15%] py-3 text-center font-medium">Actions</th>
					</tr>
				</thead>
				<tbody>
					{#if loading}
						{#each Array(2) as _, i (i)}
							<tr class="border-b">
								<td class="py-3"><Skeleton class="h-4 w-32" /></td>
								<td class="py-3"><Skeleton class="h-4 w-48" /></td>
								<td class="py-3"><Skeleton class="mx-auto h-4 w-12" /></td>
								<td class="py-3"><Skeleton class="mx-auto h-4 w-12" /></td>
								<td class="py-3 text-center">
									<div class="flex justify-center gap-2">
										<Skeleton class="h-8 w-16" />
										<Skeleton class="h-8 w-16" />
									</div>
								</td>
							</tr>
						{/each}
					{:else}
						{#each patchTests as pt (pt.id)}
							<tr class="border-b hover:bg-gray-50">
								<td class="py-3 font-medium">{pt.name}</td>
								<td class="max-w-[200px] truncate py-3 text-gray-600" title={pt.description || ''}>
									{pt.description || '—'}
								</td>
								<td class="py-3 text-center">{pt.notice_duration_hours}</td>
								<td class="py-3 text-center">{pt.expiry_months}</td>
								<td class="py-3">
									<div class="flex justify-center gap-2">
										<Button variant="outline" size="sm" onclick={() => openEditModal(pt)}>
											Edit
										</Button>
										<Button variant="destructive" size="sm" onclick={() => deletePatchTest(pt.id)}>
											Delete
										</Button>
									</div>
								</td>
							</tr>
						{/each}
						{#if patchTests.length === 0}
							<tr>
								<td colspan="5" class="py-8 text-center text-gray-500">
									No patch tests configured. Click "Add Patch Test" to create one.
								</td>
							</tr>
						{/if}
					{/if}
				</tbody>
			</table>
		</div>

		<div class="space-y-4 md:hidden">
			{#if loading}
				{#each Array(2) as _, i (i)}
					<div class="space-y-3 rounded-lg border p-4">
						<Skeleton class="h-5 w-32" />
						<Skeleton class="h-4 w-48" />
						<div class="flex justify-between">
							<Skeleton class="h-4 w-16" />
							<Skeleton class="h-4 w-16" />
						</div>
					</div>
				{/each}
			{:else}
				{#each patchTests as pt (pt.id)}
					<div class="space-y-3 rounded-lg border p-4 hover:bg-gray-50">
						<div class="flex items-start justify-between">
							<h3 class="font-medium">{pt.name}</h3>
						</div>
						{#if pt.description}
							<p class="text-sm text-gray-600">{pt.description}</p>
						{/if}
						<div class="flex justify-between text-sm">
							<div>
								<span class="font-medium">Notice:</span>
								{pt.notice_duration_hours}h
							</div>
							<div>
								<span class="font-medium">Expiry:</span>
								{pt.expiry_months}m
							</div>
						</div>
						<div class="flex gap-2 pt-2">
							<Button variant="outline" size="sm" onclick={() => openEditModal(pt)} class="flex-1">
								Edit
							</Button>
							<Button
								variant="destructive"
								size="sm"
								onclick={() => deletePatchTest(pt.id)}
								class="flex-1"
							>
								Delete
							</Button>
						</div>
					</div>
				{/each}
				{#if patchTests.length === 0}
					<div class="py-8 text-center text-gray-500">No patch tests configured.</div>
				{/if}
			{/if}
		</div>
	</Card.Content>
</Card.Root>

<Modal.Root bind:open={showModal}>
	<Modal.Content class="max-h-[90vh] max-w-sm overflow-y-auto md:max-w-lg">
		<Modal.Header>
			<Modal.Title class="text-lg font-semibold"
				>{isEditing ? 'Edit' : 'Add'} Patch Test</Modal.Title
			>
			<Modal.Description>Configure the rules for this patch test requirement.</Modal.Description>
		</Modal.Header>

		<div class="space-y-4 px-4 pb-4">
			<div class="space-y-2">
				<label for="pt-name" class="text-sm font-medium">Name *</label>
				<Input
					id="pt-name"
					type="text"
					placeholder="e.g. Standard Glue Patch Test"
					bind:value={formData.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="pt-description" class="text-sm font-medium">Description</label>
				<Input
					id="pt-description"
					type="text"
					placeholder="Optional details about this test"
					bind:value={formData.description}
					class="w-full"
				/>
			</div>

			<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
				<div class="space-y-2">
					<label for="pt-notice" class="text-sm font-medium">Notice Duration (hrs) *</label>
					<Input
						id="pt-notice"
						type="number"
						inputmode="numeric"
						min="0"
						bind:value={formData.notice_duration_hours}
						onblur={validateNoticeDurationField}
						class="w-full {formErrors.notice_duration ? 'border-red-500' : ''}"
					/>
					{#if formErrors.notice_duration}
						<p class="text-xs text-red-600">{formErrors.notice_duration}</p>
					{/if}
					<p class="text-xs text-gray-500">Hours prior to booking required</p>
				</div>

				<div class="space-y-2">
					<label for="pt-expiry" class="text-sm font-medium">Expiry (months) *</label>
					<Input
						id="pt-expiry"
						type="number"
						inputmode="numeric"
						min="1"
						bind:value={formData.expiry_months}
						onblur={validateExpiryField}
						class="w-full {formErrors.expiry ? 'border-red-500' : ''}"
					/>
					{#if formErrors.expiry}
						<p class="text-xs text-red-600">{formErrors.expiry}</p>
					{/if}
					<p class="text-xs text-gray-500">How long the test remains valid</p>
				</div>
			</div>

			<div class="space-y-2 pt-2">
				<div class="text-sm font-medium">Applicable Services</div>
				<p class="mb-2 text-xs text-gray-500">Select which services require this patch test</p>
				<div class="max-h-48 space-y-2 overflow-y-auto rounded-md border bg-gray-50 p-2">
					{#if availableServices.length === 0}
						<p class="p-2 text-sm text-gray-500 italic">No services available.</p>
					{:else}
						{#each availableServices as svc (svc.id)}
							<label class="flex cursor-pointer items-center gap-2 rounded p-1 hover:bg-gray-100">
								<Checkbox
									checked={formData.service_ids.includes(svc.id)}
									onCheckedChange={() => toggleServiceSelection(svc.id)}
								/>
								<span class="text-sm">{svc.name}</span>
							</label>
						{/each}
					{/if}
				</div>
			</div>
		</div>

		<Modal.Footer class="flex items-center justify-end gap-2">
			<Button variant="outline" onclick={() => (showModal = false)} disabled={isSubmitting}>
				Cancel
			</Button>
			<Button onclick={savePatchTest} disabled={isSubmitting || !isFormValid}>
				{isSubmitting ? 'Saving...' : 'Save'}
			</Button>
		</Modal.Footer>
	</Modal.Content>
</Modal.Root>
