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

	type CustomService = {
		id: string;
		name: string;
		description: string | null;
		price: number;
		duration_minutes: number;
		notes: string | null;
		created_at: string;
		created_by?: string;
		usage_count: number;
		last_used_at: string | null;
	};

	let services = $state<CustomService[]>([]);
	let total = $state(0);
	let page = $state(1);
	const perPage = $state(10);
	let searchQuery = $state('');
	let loading = $state(true);
	let creating = $state(false);
	let showCreateModal = $state(false);
	let serviceErrors = $state<Record<string, string>>({});

	let newService = $state({
		name: '',
		description: '',
		price: '',
		duration_minutes: '',
		minimum_age_required: ''
	});

	const durationOptions = Array.from({ length: 32 }, (_, i) => (i + 1) * 15);

	function validatePrice(price: unknown): string {
		const p = price === null || price === undefined ? '' : String(price);
		if (!p.trim()) return 'Price is required';
		const num = parseFloat(p);
		if (isNaN(num)) return 'Must be a valid number';
		if (num <= 0) return 'Must be greater than 0';
		if (!/^\d+(\.\d{1,2})?$/.test(p.trim())) return 'Up to 2 decimal places';
		return '';
	}

	function validateDuration(value: unknown): string {
		const v = value === null || value === undefined ? '' : String(value);
		if (!v.trim()) return 'Duration is required';
		const num = parseInt(v);
		if (isNaN(num)) return 'Must be a valid number';
		if (num <= 0) return 'Must be greater than 0';
		return '';
	}

	function validateName(name: unknown): string {
		const n = name === null || name === undefined ? '' : String(name);
		if (!n.trim()) return 'Name is required';
		if (n.trim().length > 100) return 'Max 100 characters';
		return '';
	}

	function validateMinimumAge(value: unknown): string {
		const v = value === null || value === undefined ? '' : String(value);
		if (!v.trim()) return 'Required';
		const num = parseInt(v);
		if (isNaN(num)) return 'Must be a valid number';
		if (num < 0 || num > 100) return 'Must be between 0 and 100';
		return '';
	}

	function updateAllErrors() {
		serviceErrors = {
			name: validateName(newService.name),
			price: validatePrice(newService.price),
			duration_minutes: validateDuration(newService.duration_minutes),
			minimum_age_required: validateMinimumAge(newService.minimum_age_required)
		};
	}

	function validateField(field: string) {
		if (field === 'name') serviceErrors.name = validateName(newService.name);
		if (field === 'price') serviceErrors.price = validatePrice(newService.price);
		if (field === 'duration_minutes')
			serviceErrors.duration_minutes = validateDuration(newService.duration_minutes);
		if (field === 'minimum_age_required')
			serviceErrors.minimum_age_required = validateMinimumAge(newService.minimum_age_required);
	}

	const isFormValid = $derived(
		(newService.name ?? '').trim() !== '' &&
			!serviceErrors.name &&
			!serviceErrors.price &&
			!serviceErrors.duration_minutes &&
			!serviceErrors.minimum_age_required
	);

	async function fetchServices() {
		loading = true;
		try {
			const params = new SvelteURLSearchParams({
				page: page.toString(),
				per_page: perPage.toString()
			});
			if (searchQuery.trim()) params.set('q', searchQuery.trim());
			const response = await apiFetch(`/api/admin/custom-services?${params}`);
			if (response.ok) {
				const data = await response.json();
				services = data.services;
				total = data.total;
			} else {
				toast.error('Failed to load custom services');
			}
		} catch {
			toast.error('Network error loading custom services');
		} finally {
			loading = false;
		}
	}

	async function createService() {
		updateAllErrors();
		if (!isFormValid) {
			toast.error('Please fix the validation errors');
			return;
		}
		creating = true;
		try {
			const response = await apiFetch('/api/admin/custom-services', {
				method: 'POST',
				headers: {
					'Content-Type': 'application/json'
				},
				body: JSON.stringify({
					name: (newService.name ?? '').trim(),
					description: (newService.description ?? '').trim() || undefined,
					price: parseFloat(newService.price ?? '0'),
					duration_minutes: parseInt(newService.duration_minutes ?? '0'),
					minimum_age_required: parseInt(newService.minimum_age_required ?? '0') || 0
				})
			});
			if (response.ok) {
				toast.success('Custom service created');
				showCreateModal = false;
				resetForm();
				await fetchServices();
			} else {
				const err = await response.text();
				toast.error('Failed: ' + sanitizeText(err));
			}
		} catch {
			toast.error('Network error');
		} finally {
			creating = false;
		}
	}

	async function promoteService(id: string, name: string) {
		if (
			!confirm(
				`Promote "${name}" to a regular catalog service? This will migrate all booking references.`
			)
		)
			return;
		try {
			const response = await apiFetch(`/api/admin/custom-services/${id}/promote`, {
				method: 'POST'
			});
			if (response.ok) {
				const data = await response.json();
				toast.success(`Promoted to service "${name}" (ID: ${data.new_service_id})`);
				await fetchServices();
			} else if (response.status === 409) {
				toast.error('A service with this name already exists');
			} else {
				const errText = await response.text();
				toast.error('Failed: ' + sanitizeText(errText));
			}
		} catch {
			toast.error('Network error');
		}
	}

	async function deleteService(id: string) {
		if (!confirm('Delete this custom service?')) return;
		try {
			const response = await apiFetch(`/api/admin/custom-services/${id}`, {
				method: 'DELETE'
			});
			if (response.ok) {
				toast.success('Deleted');
				await fetchServices();
			} else if (response.status === 409) {
				toast.error('Cannot delete: used in bookings. Promote first.');
			} else {
				const errText = await response.text();
				toast.error('Failed: ' + sanitizeText(errText));
			}
		} catch {
			toast.error('Network error');
		}
	}

	function resetForm() {
		newService = {
			name: '',
			description: '',
			price: '',
			duration_minutes: '',
			minimum_age_required: ''
		};
		serviceErrors = { name: '', price: '', duration_minutes: '', minimum_age_required: '' };
	}

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

<Card.Root>
	<Card.Header>
		<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
			<div>
				<Card.Title>Custom Services</Card.Title>
				<Card.Description>
					One-off services for bridal parties, special requests, and custom bookings.
				</Card.Description>
			</div>
			<Button
				onclick={() => {
					resetForm();
					showCreateModal = true;
				}}
			>
				<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 Custom Service
			</Button>
		</div>
	</Card.Header>

	<Card.Content class="space-y-4">
		<div class="flex gap-2">
			<Input
				placeholder="Search custom services..."
				bind:value={searchQuery}
				onkeydown={(e) => {
					if (e.key === 'Enter') {
						page = 1;
						fetchServices();
					}
				}}
				class="max-w-sm"
			/>
			<Button
				variant="outline"
				onclick={() => {
					page = 1;
					fetchServices();
				}}>Search</Button
			>
		</div>

		<Separator />

		{#if loading}
			<div class="space-y-3">
				{#each Array(3) as _, i (i)}
					<Skeleton class="h-12 w-full" />
				{/each}
			</div>
		{:else if services.length === 0}
			<div class="py-8 text-center text-gray-500">
				{searchQuery ? 'No custom services match your search.' : 'No custom services yet.'}
			</div>
		{:else}
			<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="py-3 font-medium">Name</th>
							<th class="py-3 font-medium">Description</th>
							<th class="py-3 text-right font-medium">Price</th>
							<th class="py-3 text-right font-medium">Duration</th>
							<th class="py-3 text-right font-medium">Used</th>
							<th class="py-3 text-center font-medium">Actions</th>
						</tr>
					</thead>
					<tbody>
						{#each services as service (service.id)}
							<tr class="border-b hover:bg-gray-50">
								<td class="py-3 font-medium">{service.name}</td>
								<td class="py-3 text-gray-600">
									{#if service.description}
										<div class="line-clamp-1" title={service.description}>
											{service.description}
										</div>
									{:else}
										<span class="text-gray-400">—</span>
									{/if}
								</td>
								<td class="py-3 text-right font-medium">£{service.price.toFixed(2)}</td>
								<td class="py-3 text-right">{service.duration_minutes} min</td>
								<td class="py-3 text-right">
									{service.usage_count}×{service.last_used_at
										? ` (last: ${new Date(service.last_used_at).toLocaleDateString('en-GB', { timeZone: 'Europe/London' })})`
										: ''}
								</td>
								<td class="py-3">
									<div class="flex justify-center gap-2">
										<Button
											variant="outline"
											size="sm"
											onclick={() => promoteService(service.id, service.name)}
										>
											Promote
										</Button>
										<Button
											variant="destructive"
											size="sm"
											onclick={() => deleteService(service.id)}
										>
											Delete
										</Button>
									</div>
								</td>
							</tr>
						{/each}
					</tbody>
				</table>
			</div>

			<div class="space-y-4 md:hidden">
				{#each services as service (service.id)}
					<div class="rounded-lg border p-4 hover:bg-gray-50">
						<div class="space-y-3">
							<div class="flex items-start justify-between">
								<h3 class="font-medium">{service.name}</h3>
								<span class="text-xs text-gray-500">{service.usage_count}× used</span>
							</div>
							{#if service.description}
								<p class="text-sm text-gray-600">{service.description}</p>
							{/if}
							<div class="flex justify-between text-sm">
								<div><span class="font-medium">Price:</span> £{service.price.toFixed(2)}</div>
								<div><span class="font-medium">Duration:</span> {service.duration_minutes} min</div>
							</div>
							<div class="flex gap-2 pt-2">
								<Button
									variant="outline"
									size="sm"
									class="flex-1"
									onclick={() => promoteService(service.id, service.name)}>Promote</Button
								>
								<Button
									variant="destructive"
									size="sm"
									class="flex-1"
									onclick={() => deleteService(service.id)}>Delete</Button
								>
							</div>
						</div>
					</div>
				{/each}
			</div>

			{#if total > perPage}
				<div class="flex items-center justify-between">
					<span class="text-sm text-gray-500">
						Page {page} of {Math.ceil(total / perPage)} ({total} total)
					</span>
					<div class="flex gap-2">
						<Button
							variant="outline"
							size="sm"
							disabled={page <= 1}
							onclick={() => {
								page--;
								fetchServices();
							}}>Previous</Button
						>
						<Button
							variant="outline"
							size="sm"
							disabled={page >= Math.ceil(total / perPage)}
							onclick={() => {
								page++;
								fetchServices();
							}}>Next</Button
						>
					</div>
				</div>
			{/if}
		{/if}
	</Card.Content>
</Card.Root>

<Modal.Root bind:open={showCreateModal}>
	<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">Add Custom Service</Modal.Title>
			<Modal.Description>Create a one-off service for special requests.</Modal.Description>
		</Modal.Header>

		<div class="space-y-4 px-4 pb-4">
			<div class="space-y-2">
				<label for="cs-name" class="text-sm font-medium">Name *</label>
				<Input
					id="cs-name"
					type="text"
					maxlength={100}
					placeholder="e.g., Bridal Party French Tips"
					bind:value={newService.name}
					oninput={() => validateField('name')}
					onblur={() => validateField('name')}
					class="w-full {serviceErrors.name ? 'border-red-500' : ''}"
				/>
				{#if serviceErrors.name}
					<p class="text-sm text-red-600">{serviceErrors.name}</p>
				{/if}
			</div>

			<div class="space-y-2">
				<label for="cs-desc" class="text-sm font-medium">Description</label>
				<Input
					id="cs-desc"
					type="text"
					placeholder="Brief description"
					bind:value={newService.description}
					class="w-full"
				/>
			</div>

			<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
				<div class="space-y-2">
					<label for="cs-price" class="text-sm font-medium">Price (£) *</label>
					<div class="relative">
						<span class="absolute top-1/2 left-3 -translate-y-1/2 text-sm text-gray-500">£</span>
						<Input
							id="cs-price"
							type="number"
							inputmode="decimal"
							step="0.01"
							min="0"
							placeholder="0.00"
							bind:value={newService.price}
							oninput={() => validateField('price')}
							onblur={() => validateField('price')}
							class="w-full pl-8 {serviceErrors.price ? 'border-red-500' : ''}"
						/>
					</div>
					{#if serviceErrors.price}
						<p class="text-sm text-red-600">{serviceErrors.price}</p>
					{/if}
				</div>

				<div class="space-y-2">
					<label for="cs-duration" class="text-sm font-medium">Duration *</label>
					<select
						id="cs-duration"
						bind:value={newService.duration_minutes}
						onchange={() => validateField('duration_minutes')}
						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 {serviceErrors.duration_minutes
							? 'border-red-500'
							: ''}"
					>
						<option value="">Select...</option>
						{#each durationOptions as mins (mins)}
							<option value={mins}
								>{mins} min{mins >= 60
									? ` (${Math.floor(mins / 60)}h${mins % 60 > 0 ? ` ${mins % 60}m` : ''})`
									: ''}</option
							>
						{/each}
					</select>
					{#if serviceErrors.duration_minutes}
						<p class="text-sm text-red-600">{serviceErrors.duration_minutes}</p>
					{/if}
				</div>
			</div>

			<div class="space-y-2">
				<label for="cs-min-age" class="text-sm font-medium">Minimum Age</label>
				<Input
					id="cs-min-age"
					type="number"
					inputmode="numeric"
					min="0"
					max="100"
					placeholder="0"
					bind:value={newService.minimum_age_required}
					oninput={() => validateField('minimum_age_required')}
					onblur={() => validateField('minimum_age_required')}
					class="w-full {serviceErrors.minimum_age_required ? 'border-red-500' : ''}"
				/>
				{#if serviceErrors.minimum_age_required}
					<p class="text-sm text-red-600">{serviceErrors.minimum_age_required}</p>
				{/if}
				<p class="text-xs text-gray-500">0 for no age restriction</p>
			</div>
		</div>

		<Modal.Footer class="flex items-center justify-end gap-2">
			<Button
				variant="outline"
				onclick={() => {
					showCreateModal = false;
					resetForm();
				}}
				disabled={creating}>Cancel</Button
			>
			<Button onclick={createService} disabled={creating || !isFormValid}>
				{creating ? 'Creating...' : 'Create'}
			</Button>
		</Modal.Footer>
	</Modal.Content>
</Modal.Root>
