<script lang="ts">
	import { SvelteDate } from 'svelte/reactivity';
	import { apiFetch } from '$lib/utils/api';
	import { toast } from 'svelte-sonner';
	import { sanitizeText } from '$lib/utils/toast-safe';
	import { formatDateTime, formatDuration } from '$lib/utils/format';
	import { formatUserName } from '$lib/utils/nameDisplay';
	import { parseWallClockDate } from '$lib/utils/timeSlots';
	import * as Modal from '$lib/components/ui/dialog';
	import { Button } from '$lib/components/ui/button';
	import { Input } from '$lib/components/ui/input';
	import { Textarea } from '$lib/components/ui/textarea';
	import * as AlertDialog from '$lib/components/ui/alert-dialog';
	import CharCounter from '$lib/components/ui/CharCounter.svelte';
	import type { BookingDiscount } from '$lib/types/booking';

	interface Props {
		open: boolean;
		booking: {
			id: string;
			start_time: string;
			created_at: string;
			notes?: string;
			user?: {
				full_name: string;
				email?: string;
				phone?: string;
				previous_first_name?: string | null;
				previous_last_name?: string | null;
			};
			services?: Array<{
				service_id: string;
				service_name?: string;
				price?: number;
				duration_minutes?: number;
			}>;
			discounts?: BookingDiscount[];
		};
		onApproved: () => void;
	}

	let { open = $bindable(), booking, onApproved }: Props = $props();

	type ServiceOverride = {
		serviceId: string;
		overridePrice?: number;
		overrideDurationMinutes?: number;
	};

	let notes = $state('');

	// Sync notes with booking.notes when booking changes
	$effect(() => {
		if (booking?.notes !== undefined) {
			notes = booking.notes || '';
		}
	});
	let serviceOverrides = $state<
		Record<
			string,
			{
				price: string;
				duration: string;
				originalPrice: number;
				originalDuration: number;
			}
		>
	>({});
	let submitting = $state(false);
	let showDeclineConfirm = $state(false);
	let overlappingBookings = $state<OverlappingBooking[]>([]);
	let loadingOverlaps = $state(false);

	function getBookingDateTime(): string {
		if (!booking?.start_time) return '';
		const d = parseWallClockDate(booking.start_time);
		return (
			d.toLocaleDateString('en-GB', {
				weekday: 'long',
				day: 'numeric',
				month: 'long',
				year: 'numeric'
			}) +
			' at ' +
			d.toLocaleTimeString('en-GB', {
				hour: 'numeric',
				minute: '2-digit',
				hour12: true
			})
		);
	}

	function getTotalCost(): number {
		if (!booking?.services?.length) return 0;
		let total = 0;
		for (const service of booking.services) {
			if (!service?.service_id) continue;
			const override = serviceOverrides[service.service_id];
			if (override && hasPriceChanged(service.service_id)) {
				total += parseFloat(override.price) || 0;
			} else {
				total += service.price || 0;
			}
		}
		return Math.round(total * 100) / 100;
	}

	function getTotalDuration(): number {
		if (!booking?.services?.length) return 0;
		let total = 0;
		for (const service of booking.services) {
			if (!service?.service_id) continue;
			const override = serviceOverrides[service.service_id];
			if (override && hasDurationChanged(service.service_id)) {
				total += parseInt(override.duration) || 0;
			} else {
				total += service.duration_minutes || 0;
			}
		}
		return total;
	}

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

	// Fetch overlapping bookings when modal opens
	async function fetchOverlappingBookings() {
		if (!booking?.id) return;
		loadingOverlaps = true;
		try {
			const response = await apiFetch(`/api/admin/bookings/${booking.id}/overlapping`, {
				method: 'GET',
				headers: {
					'Content-Type': 'application/json'
				}
			});
			if (response.ok) {
				const data = await response.json();
				overlappingBookings = data.bookings || [];
			}
		} catch (_err) {
			// Silently handle - overlapping bookings couldn't be fetched
		} finally {
			loadingOverlaps = false;
		}
	}

	// Find the oldest booking (including current) among overlaps
	function findOldestBooking(): { id: string; isCurrent: boolean } | null {
		if (overlappingBookings.length === 0) return null;

		const currentCreatedAt = new SvelteDate(booking.created_at).getTime();
		let oldestId = booking.id;
		let oldestTime = currentCreatedAt;

		for (const ob of overlappingBookings) {
			const obTime = new SvelteDate(ob.created_at).getTime();
			if (obTime < oldestTime) {
				oldestTime = obTime;
				oldestId = ob.id;
			}
		}

		return { id: oldestId, isCurrent: oldestId === booking.id };
	}

	$effect(() => {
		if (open && booking?.id) {
			fetchOverlappingBookings();
		}
	});
	// Initialize overrides with original values
	$effect(() => {
		if (!booking?.services?.length) return;

		const overrides: Record<
			string,
			{
				price: string;
				duration: string;
				originalPrice: number;
				originalDuration: number;
			}
		> = {};

		booking.services.forEach((service) => {
			if (!service?.service_id) return;

			const originalPrice = service.price || 0;
			const originalDuration = service.duration_minutes || 60;

			overrides[service.service_id] = {
				price: originalPrice.toFixed(2),
				duration: originalDuration.toString(),
				originalPrice,
				originalDuration
			};
		});
		serviceOverrides = overrides;
	});

	// Validate and format price input - FIXED VERSION
	function handlePriceInput(serviceId: string, value: string) {
		const override = serviceOverrides[serviceId];
		if (!override) return;

		// Allow only numbers and one decimal point
		let cleaned = value;

		// Remove any characters that aren't digits or decimal point
		cleaned = cleaned.replace(/[^\d.]/g, '');

		// Ensure only one decimal point
		const parts = cleaned.split('.');
		if (parts.length > 2) {
			cleaned = parts[0] + '.' + parts.slice(1).join('');
		}

		// If there's a decimal point, ensure max 2 decimal places
		if (cleaned.includes('.')) {
			const [integer, decimal] = cleaned.split('.');
			if (decimal.length > 2) {
				cleaned = integer + '.' + decimal.substring(0, 2);
			}
		}

		serviceOverrides = {
			...serviceOverrides,
			[serviceId]: {
				...override,
				price: cleaned
			}
		};
	}

	// Validate and format duration input
	function handleDurationInput(serviceId: string, value: string) {
		const override = serviceOverrides[serviceId];
		if (!override) return;

		// Remove any non-numeric characters
		const cleaned = value.replace(/\D/g, '');

		serviceOverrides = {
			...serviceOverrides,
			[serviceId]: {
				...override,
				duration: cleaned
			}
		};
	}

	// Check if a value has changed from original
	function hasPriceChanged(serviceId: string): boolean {
		const override = serviceOverrides[serviceId];
		if (!override) return false;

		const currentPrice = parseFloat(override.price) || 0;
		return Math.abs(currentPrice - override.originalPrice) > 0.001; // Account for floating point precision
	}

	function hasDurationChanged(serviceId: string): boolean {
		const override = serviceOverrides[serviceId];
		if (!override) return false;

		const currentDuration = parseInt(override.duration) || 0;
		return currentDuration !== override.originalDuration;
	}

	async function handleApprove() {
		submitting = true;
		const loadingToast = toast.loading('Confirming booking...');

		try {
			// Only include notes if different from original
			const notesToSend =
				notes.trim() !== (booking.notes || '') ? notes.trim() || undefined : undefined;

			// Build service overrides array (only include if values are different)
			const overrides: ServiceOverride[] = [];

			for (const [serviceId, override] of Object.entries(serviceOverrides)) {
				const priceChanged = hasPriceChanged(serviceId);
				const durationChanged = hasDurationChanged(serviceId);

				if (!priceChanged && !durationChanged) continue;

				const overrideObj: ServiceOverride = { serviceId };

				if (priceChanged) {
					const overridePrice = parseFloat(override.price);
					if (!isNaN(overridePrice)) {
						overrideObj.overridePrice = overridePrice;
					}
				}

				if (durationChanged) {
					const overrideDuration = parseInt(override.duration);
					if (!isNaN(overrideDuration)) {
						overrideObj.overrideDurationMinutes = overrideDuration;
					}
				}

				overrides.push(overrideObj);
			}

			const payload = {
				notes: notesToSend,
				serviceOverrides: overrides.length > 0 ? overrides : undefined
			};

			const response = await apiFetch(`/api/admin/bookings/${booking.id}/confirm`, {
				method: 'POST',
				headers: {
					'Content-Type': 'application/json'
				},
				body: JSON.stringify(payload)
			});

			if (response.ok) {
				toast.success('Booking confirmed successfully!', { id: loadingToast });
				open = false;
				onApproved();
			} else {
				const text = await response.text();
				toast.error('Failed to confirm: ' + sanitizeText(text), { id: loadingToast });
			}
		} catch (_err) {
			toast.error('Network error confirming booking', { id: loadingToast });
		} finally {
			submitting = false;
		}
	}

	async function handleDecline() {
		submitting = true;
		const loadingToast = toast.loading('Declining booking...');

		try {
			const response = await apiFetch(`/api/admin/bookings/${booking.id}/cancel`, {
				method: 'POST',
				headers: {
					'Content-Type': 'application/json'
				}
			});

			if (response.ok) {
				toast.success('Booking declined successfully', { id: loadingToast });
				showDeclineConfirm = false;
				open = false;
				onApproved();
			} else {
				const text = await response.text();
				toast.error('Failed to decline: ' + sanitizeText(text), { id: loadingToast });
			}
		} catch (_err) {
			toast.error('Network error declining booking', { id: loadingToast });
		} finally {
			submitting = false;
			showDeclineConfirm = false;
		}
	}
</script>

<Modal.Root bind:open>
	<Modal.Content
		class="!z-[70] max-h-[90vh] max-w-[calc(100%-2rem)] overflow-y-auto sm:max-w-lg md:max-w-2xl"
	>
		<Modal.Header>
			<Modal.Title class="text-lg font-semibold">Approve Booking</Modal.Title>
			<Modal.Description>
				Review and confirm this booking. Adjust pricing or duration if needed.
			</Modal.Description>
		</Modal.Header>

		<div class="space-y-6 px-4 pb-4">
			<!-- Overlapping Bookings Warning -->
			{#if loadingOverlaps}
				<div class="rounded-lg border border-gray-200 bg-gray-50 p-4">
					<div class="text-sm text-gray-500">Checking for overlapping bookings...</div>
				</div>
			{:else if overlappingBookings.length > 0}
				{@const oldest = findOldestBooking()}
				<div class="rounded-lg border border-amber-300 bg-amber-50 p-4">
					<h3 class="mb-3 text-sm font-semibold tracking-wide text-amber-800 uppercase">
						⚠️ Overlapping Bookings ({overlappingBookings.length})
					</h3>
					{#if oldest?.isCurrent}
						<div class="mb-3 rounded bg-green-100 px-3 py-2 text-sm text-green-800">
							★ This booking was created first - it has priority
						</div>
					{/if}
					<div class="space-y-2">
						{#each overlappingBookings as ob (ob.id)}
							<div class="rounded border bg-white p-3 text-sm">
								<div class="flex items-start justify-between">
									<div>
										<div class="font-medium">
											{#if oldest?.id === ob.id}
												<span class="text-amber-600" title="Booked first">★</span>
											{/if}
											{formatUserName(
												ob.user?.full_name || 'Unknown',
												ob.user?.previous_first_name,
												ob.user?.previous_last_name
											)}
										</div>
										<div class="text-xs text-gray-500">
											{parseWallClockDate(ob.start_time).toLocaleDateString('en-GB', {
												weekday: 'short',
												day: 'numeric',
												month: 'short',
												hour: 'numeric',
												minute: '2-digit',
												hour12: true
											})}
											({ob.duration_minutes} min)
										</div>
										{#if ob.services && ob.services.length > 0}
											<div class="mt-1 text-xs text-gray-600">
												{ob.services.join(', ')}
											</div>
										{/if}
									</div>
									<div class="text-right">
										<span
											class="inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium
											{ob.status === 'pending'
												? 'bg-amber-100 text-amber-800'
												: ob.status === 'confirmed'
													? 'bg-emerald-100 text-emerald-800'
													: 'bg-gray-100 text-gray-800'}"
										>
											{ob.status}
										</span>
										<div class="mt-1 text-xs text-gray-400">
											{new SvelteDate(ob.created_at).toLocaleDateString('en-GB', {
												day: 'numeric',
												month: 'short',
												hour: 'numeric',
												minute: '2-digit',
												hour12: true
											})}
										</div>
									</div>
								</div>
							</div>
						{/each}
					</div>
				</div>
			{/if}

			<!-- Appointment Details -->
			<div class="rounded-lg border border-gray-200 bg-gray-50 p-4">
				<h3 class="mb-3 text-sm font-semibold tracking-wide text-gray-600 uppercase">
					Appointment Details
				</h3>
				<div class="grid grid-cols-1 gap-3 sm:grid-cols-2">
					<div>
						<div class="text-xs text-gray-500">Scheduled Date & Time</div>
						<div class="font-medium">{getBookingDateTime()}</div>
					</div>
					{#if getTotalDuration() > 0}
						<div>
							<div class="text-xs text-gray-500">Duration</div>
							<div class="font-medium">{formatDuration(getTotalDuration())}</div>
						</div>
					{/if}
					<div>
						<div class="text-xs text-gray-500">Created</div>
						<div class="text-sm">{formatDateTime(booking.created_at)}</div>
					</div>
				</div>
				{#if booking.notes}
					<div class="mt-3 rounded-md border border-amber-200 bg-amber-50 p-3">
						<div class="mb-1 text-xs font-semibold text-amber-800">Booking Notes</div>
						<div class="text-sm text-amber-900">{booking.notes}</div>
					</div>
				{/if}
			</div>

			<!-- Customer Information -->
			<div class="rounded-lg border border-gray-200 bg-gray-50 p-4">
				<h3 class="mb-3 text-sm font-semibold tracking-wide text-gray-600 uppercase">
					Customer Information
				</h3>

				<div class="mb-4 flex items-center gap-4">
					<div>
						<div class="text-lg font-semibold">
							{formatUserName(
								booking.user?.full_name || '—',
								booking.user?.previous_first_name,
								booking.user?.previous_last_name
							)}
						</div>
					</div>
				</div>

				<div class="grid grid-cols-1 gap-3 sm:grid-cols-2">
					<div>
						<div class="text-xs text-gray-500">Email</div>
						{#if booking.user?.email}
							<a
								href="mailto:{booking.user.email}"
								class="font-medium break-words text-blue-600 hover:underline"
								>{booking.user.email}</a
							>
						{:else}
							<div class="font-medium">—</div>
						{/if}
					</div>
					<div>
						<div class="text-xs text-gray-500">Phone</div>
						{#if booking.user?.phone}
							<a href="tel:{booking.user.phone}" class="font-medium text-blue-600 hover:underline"
								>{booking.user.phone}</a
							>
						{:else}
							<div class="font-medium">—</div>
						{/if}
					</div>
				</div>
			</div>

			<!-- Booking Notes -->
			<div>
				<label for="booking-notes" class="mb-2 block text-sm font-medium"> Booking Notes </label>
				<Textarea
					id="booking-notes"
					bind:value={notes}
					placeholder="Add any notes about this booking... (client will see this, appears on receipt)"
					rows={3}
					class="w-full"
				/>
				<CharCounter text={notes} />
				{#if notes.trim() !== (booking.notes || '')}
					<div class="mt-1 text-xs text-emerald-600">
						✓ Notes will be saved (different from original)
					</div>
				{:else if booking.notes}
					<div class="mt-1 text-xs text-gray-500">Notes unchanged from original</div>
				{/if}
			</div>

			<!-- Services & Pricing -->
			<div class="rounded-lg border border-gray-200 bg-gray-50 p-4">
				<h3 class="mb-3 text-sm font-semibold tracking-wide text-gray-600 uppercase">
					Services & Pricing
				</h3>
				<div class="space-y-3">
					{#each booking.services ?? [] as service, i (i)}
						{#if service && serviceOverrides[service.service_id]}
							<div class="rounded-lg border border-gray-200 bg-white p-4">
								<div class="font-medium">{service.service_name || 'Unknown Service'}</div>
								<div class="grid gap-3 md:grid-cols-2">
									<div>
										<label for="price-{service.service_id}" class="mb-1 block text-xs text-gray-600"
											>Price Override</label
										>
										<div class="relative">
											<div
												class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3"
											>
												<span class="text-gray-500">£</span>
											</div>
											<!-- Changed to type="text" for better decimal handling -->
											<Input
												id="price-{service.service_id}"
												type="text"
												inputmode="decimal"
												value={serviceOverrides[service.service_id].price}
												oninput={(e) => handlePriceInput(service.service_id, e.currentTarget.value)}
												onblur={() => {
													// Format to 2 decimal places on blur if needed
													const val = serviceOverrides[service.service_id].price;
													if (val) {
														// If there's no decimal point, add .00
														if (!val.includes('.')) {
															const num = parseFloat(val);
															if (!isNaN(num)) {
																serviceOverrides[service.service_id].price = num.toFixed(2);
																serviceOverrides = serviceOverrides;
															}
														}
														// If there's a decimal point with less than 2 decimal places, pad with zeros
														else if (val.includes('.')) {
															const parts = val.split('.');
															if (parts[1].length === 0) {
																serviceOverrides[service.service_id].price = parts[0] + '.00';
																serviceOverrides = serviceOverrides;
															} else if (parts[1].length === 1) {
																serviceOverrides[service.service_id].price =
																	parts[0] + '.' + parts[1] + '0';
																serviceOverrides = serviceOverrides;
															}
														}
													}
												}}
												class="no-spin w-full pl-7"
												placeholder={service.price?.toFixed(2) || '0.00'}
											/>
										</div>
										<div class="mt-1 flex items-center justify-between">
											<div class="text-xs text-gray-500">
												Default: £{service.price?.toFixed(2) || '0.00'}
											</div>
											{#if hasPriceChanged(service.service_id)}
												<div class="text-xs font-medium text-emerald-600">✓ Changed</div>
											{/if}
										</div>
									</div>
									<div>
										<label
											for="duration-{service.service_id}"
											class="mb-1 block text-xs text-gray-600">Duration Override (min)</label
										>
										<div class="relative">
											<Input
												id="duration-{service.service_id}"
												type="number"
												min="1"
												step="1"
												value={serviceOverrides[service.service_id].duration}
												oninput={(e) =>
													handleDurationInput(service.service_id, e.currentTarget.value)}
												class="no-spin w-full"
												placeholder={service.duration_minutes?.toString() || '60'}
											/>
										</div>
										<div class="mt-1 flex items-center justify-between">
											<div class="text-xs text-gray-500">
												Default: {service.duration_minutes || 60} min
											</div>
											{#if hasDurationChanged(service.service_id)}
												<div class="text-xs font-medium text-emerald-600">✓ Changed</div>
											{/if}
										</div>
									</div>
								</div>
							</div>
						{/if}
					{/each}
				</div>
			</div>

			{#if booking.discounts && booking.discounts.length > 0}
				<div class="mt-3 rounded-md border border-blue-200 bg-blue-50 p-3 text-sm text-blue-800">
					<p class="font-medium">Applied Discounts</p>
					{#each booking.discounts as d (d.id)}
						<p class="mt-1">
							- {d.discount_source === 'loyalty'
								? 'Loyalty Stamp Card'
								: d.discount_source === 'referral'
									? 'Referral Discount'
									: d.campaign_name || 'Promo Campaign'}
							({d.discount_percent}% off): -£{d.discount_amount.toFixed(2)}
						</p>
					{/each}
				</div>
			{/if}
		</div>

		<Modal.Footer class="flex items-center justify-between gap-2">
			<div class="flex items-center gap-4 text-sm text-gray-600">
				<span class="text-lg font-semibold">£{getTotalCost().toFixed(2)}</span>
				<span class="text-gray-300">·</span>
				<span class="text-sm text-gray-500">{getTotalDuration()} min</span>
			</div>
			<div class="flex items-center gap-2">
				<Button
					variant="destructive"
					onclick={() => (showDeclineConfirm = true)}
					disabled={submitting}
				>
					Decline Booking
				</Button>
				<Button
					onclick={handleApprove}
					disabled={submitting}
					class="bg-emerald-600 hover:bg-emerald-700"
				>
					{submitting ? 'Confirming...' : 'Confirm Booking'}
				</Button>
			</div>
		</Modal.Footer>
	</Modal.Content>
</Modal.Root>

<!-- Decline Confirmation Dialog -->
<AlertDialog.Root bind:open={showDeclineConfirm}>
	<AlertDialog.Content class="z-60">
		<AlertDialog.Header>
			<AlertDialog.Title>Decline this booking?</AlertDialog.Title>
			<AlertDialog.Description>
				This will cancel the booking and notify the customer. This action cannot be undone.
			</AlertDialog.Description>
		</AlertDialog.Header>
		<AlertDialog.Footer>
			<AlertDialog.Cancel>Cancel</AlertDialog.Cancel>
			<AlertDialog.Action onclick={handleDecline} class="bg-red-600 hover:bg-red-700">
				Decline Booking
			</AlertDialog.Action>
		</AlertDialog.Footer>
	</AlertDialog.Content>
</AlertDialog.Root>
