<script lang="ts">
	import { toast } from 'svelte-sonner';
	import * as Dialog from '$lib/components/ui/dialog';
	import { Button } from '$lib/components/ui/button';
	import { Input } from '$lib/components/ui/input';
	import { Checkbox } from '$lib/components/ui/checkbox';
	import type { Booking, BookingService, BookingDiscount } from '$lib/types/booking';
	import { apiFetch } from '$lib/utils/api';

	const LOYALTY_DISCOUNT_RATE = 0.1;

	interface Props {
		booking: Booking;
		onClose: () => void;
		onComplete: (payment: PaymentResult) => void;
	}

	const { booking, onClose, onComplete }: Props = $props();

	type PaymentStatus =
		| 'idle'
		| 'selecting'
		| 'card-processing'
		| 'card-polling'
		| 'cash-entering'
		| 'cash-confirming'
		| 'gift-entering'
		| 'gift-confirming'
		| 'saved-card-selecting'
		| 'saved-card-processing'
		| 'success'
		| 'error';

	type PaymentResult = {
		checkout_id: string;
		status: string;
		card_brand?: string;
		last4?: string;
		amount: number;
	};

	type PaymentMethod = 'card' | 'cash' | 'giftcard' | 'savedcard' | null;

	let status = $state<PaymentStatus>('idle');
	let selectedMethod = $state<PaymentMethod>(null);
	let checkoutId = $state<string | null>(null);
	let paymentResult = $state<PaymentResult | null>(null);
	let error = $state<string | null>(null);

	const stamps = $derived(booking.user?.loyalty_stamps ?? 0);
	let useLoyalty = $state(false);

	const loyaltyEligible = $derived(
		stamps >= 10 &&
			!(booking.discounts ?? []).some((d: BookingDiscount) => d.discount_source === 'loyalty') &&
			booking.total_amount > 0 &&
			booking.amount_paid === 0
	);

	const loyaltyDiscount = $derived(
		useLoyalty ? Math.round(booking.total_amount * 100 * LOYALTY_DISCOUNT_RATE) : 0
	);

	let customerBalance = $state(0);
	let _loadingCustomerBalance = $state(false);
	let giftCardPaymentAmount = $state('');
	let savedCardList = $state<
		Array<{
			id: string;
			card_brand: string;
			card_last4: string;
			card_expiry: string;
			cardholder_name?: string;
		}>
	>([]);
	let _loadingSavedCardList = $state(false);

	async function fetchCustomerGiftCardBalance() {
		const targetUserId = booking.user_id ?? booking.user?.id;
		if (!targetUserId) return;
		_loadingCustomerBalance = true;
		try {
			const res = await apiFetch(`/api/admin/users/${targetUserId}/giftcard-balance`);
			if (res.ok) {
				const data = await res.json();
				customerBalance = data.balance;
				giftCardPaymentAmount = Math.min(data.balance, totalDue).toFixed(2);
				if (data.balance > 0) {
					useAccountBalance = true;
				}
			}
		} catch {
			// ignore
		} finally {
			_loadingCustomerBalance = false;
		}
	}

	async function fetchSavedCardList() {
		const targetUserId = booking.user_id ?? booking.user?.id;
		if (!targetUserId) return;
		_loadingSavedCardList = true;
		try {
			const res = await apiFetch(`/api/admin/users/${targetUserId}/payment-methods`);
			if (res.ok) {
				savedCardList = await res.json();
			}
		} catch {
			// ignore
		} finally {
			_loadingSavedCardList = false;
		}
	}

	type ServiceOverride = {
		price: string;
		originalPrice: number;
	};

	let serviceOverrides = $state<Record<string, ServiceOverride>>({});

	$effect(() => {
		const uid = booking.user_id ?? booking.user?.id;
		if (uid) {
			fetchCustomerGiftCardBalance();
			fetchSavedCardList();
		}
		const services = booking.services ?? [];
		const overrides: Record<string, ServiceOverride> = {};
		for (const s of services) {
			const price = s.override_price ?? s.price ?? 0;
			overrides[s.service_id] = {
				price: price.toFixed(2),
				originalPrice: s.price ?? 0
			};
		}
		serviceOverrides = overrides;
	});

	function handlePriceInput(serviceId: string, value: string) {
		const cleaned = value.replace(/[^0-9.]/g, '');
		const firstDot = cleaned.indexOf('.');
		let sanitized: string;
		if (firstDot !== -1) {
			const integerPart = cleaned.substring(0, firstDot);
			const decimalPart = cleaned.substring(firstDot + 1).replace(/\./g, '');
			sanitized = integerPart + '.' + decimalPart;
		} else {
			sanitized = cleaned;
		}
		if (/^\d+(\.\d{0,2})?$/.test(sanitized) || sanitized === '') {
			serviceOverrides = {
				...serviceOverrides,
				[serviceId]: {
					...serviceOverrides[serviceId],
					price: sanitized
				}
			};
		}
	}

	let tipEnabled = $state(false);
	let selectedTipPercent = $state<number | null>(null);
	let customTipAmount = $state<string>('');

	let pollingInterval: ReturnType<typeof setInterval> | null = null;

	function selectTipPercent(percent: number) {
		selectedTipPercent = percent;
		customTipAmount = '';
		tipEnabled = true;
	}

	function handleCustomTipInput(e: Event) {
		const input = e.target as HTMLInputElement;
		const cleaned = input.value.replace(/[^0-9.]/g, '');
		const firstDot = cleaned.indexOf('.');
		let sanitized: string;
		if (firstDot !== -1) {
			const integerPart = cleaned.substring(0, firstDot);
			const decimalPart = cleaned.substring(firstDot + 1).replace(/\./g, '');
			sanitized = integerPart + '.' + decimalPart;
		} else {
			sanitized = cleaned;
		}
		if (/^\d+(\.\d{0,2})?$/.test(sanitized) || sanitized === '') {
			customTipAmount = sanitized;
		}
		selectedTipPercent = null;
		tipEnabled = customTipAmount !== '' && parseFloat(customTipAmount) > 0;
	}

	function getServicePrice(service: BookingService): number {
		const override = serviceOverrides[service.service_id];
		if (override && override.price !== '') {
			const parsed = parseFloat(override.price);
			if (!isNaN(parsed) && parsed > 0) return parsed;
		}
		return service.override_price ?? service.price ?? 0;
	}

	const subtotal = $derived(
		(booking.services ?? []).reduce((sum, s) => sum + getServicePrice(s), 0)
	);
	const discountSum = $derived(
		(booking.discounts ?? []).reduce((sum, d) => sum + d.discount_amount, 0)
	);
	const netTotal = $derived(Math.max(0, subtotal - discountSum));

	const tipPercentages = $derived.by(() => {
		if (netTotal <= 0) return [];
		return [
			{ pct: 10, amount: Math.round(netTotal * 0.1 * 100) / 100 },
			{ pct: 15, amount: Math.round(netTotal * 0.15 * 100) / 100 },
			{ pct: 20, amount: Math.round(netTotal * 0.2 * 100) / 100 }
		];
	});

	const tipMultiplier = $derived(
		selectedTipPercent !== null
			? 1 + selectedTipPercent / 100
			: customTipAmount && parseFloat(customTipAmount) > 0
				? 1 + parseFloat(customTipAmount) / netTotal
				: 1
	);

	const totalWithTip = $derived(tipEnabled ? netTotal * tipMultiplier : netTotal);
	const tipDisplay = $derived(
		selectedTipPercent !== null
			? `${selectedTipPercent}%`
			: customTipAmount && parseFloat(customTipAmount) > 0
				? `£${parseFloat(customTipAmount).toFixed(2)}`
				: ''
	);

	const totalDue = $derived(tipEnabled ? totalWithTip : netTotal);

	function formatCurrency(value: number): string {
		return new Intl.NumberFormat('en-GB', {
			style: 'currency',
			currency: 'GBP'
		}).format(value);
	}

	async function applyLoyaltyRedemption(): Promise<void> {
		if (!useLoyalty) return;
		const res = await apiFetch(`/api/admin/bookings/${booking.id}/apply-redemption`, {
			method: 'POST',
			headers: { 'Content-Type': 'application/json' }
		});
		if (!res.ok) {
			const errData = await res.text();
			throw new Error(errData || 'Failed to apply loyalty discount');
		}
	}

	async function handleCardPayment() {
		const finalAmount = totalDue;

		if (isNaN(finalAmount) || finalAmount <= 0) {
			toast.error('Please enter a valid amount');
			return;
		}

		status = 'card-processing';
		error = null;

		try {
			await applyLoyaltyRedemption();

			const response = await apiFetch(`/api/admin/bookings/${booking.id}/payment`, {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({
					amount: Math.round(finalAmount * 100) - loyaltyDiscount,
					payment_type: 'full',
					tip_enabled: tipEnabled
				})
			});

			if (!response.ok) {
				const errData = await response.text();
				throw new Error(errData || 'Failed to initiate payment');
			}

			const data = await response.json();
			checkoutId = data.checkout_id;
			status = 'card-polling';
			startPolling();
		} catch (_err) {
			status = 'error';
			error = _err instanceof Error ? _err.message : 'Failed to initiate payment';
			toast.error(error ?? 'Unknown error');
		}
	}

	function startPolling() {
		if (!checkoutId) return;

		pollingInterval = setInterval(async () => {
			try {
				const response = await apiFetch(
					`/api/admin/payments/${checkoutId}/status?booking_id=${booking.id}`,
					{
						headers: { 'Content-Type': 'application/json' }
					}
				);

				if (!response.ok) {
					throw new Error('Failed to check payment status');
				}

				const data = await response.json();

				if (data.status === 'COMPLETED') {
					stopPolling();
					status = 'success';
					paymentResult = {
						checkout_id: checkoutId!,
						status: data.status,
						card_brand: data.card_brand,
						last4: data.last4,
						amount: data.amount
					};
					toast.success('Payment successful');
					onComplete(paymentResult);
				} else if (data.status === 'FAILED') {
					stopPolling();
					status = 'error';
					error = data.error_message || 'Payment failed';
					toast.error(error as string);
				}
			} catch (_err) {
				stopPolling();
				status = 'error';
				error = 'Failed to check payment status';
				toast.error(error);
			}
		}, 2000);
	}

	function stopPolling() {
		if (pollingInterval) {
			clearInterval(pollingInterval);
			pollingInterval = null;
		}
	}

	function handleClose() {
		stopPolling();
		onClose();
	}

	function resetToSelect() {
		stopPolling();
		status = 'idle';
		selectedMethod = null;
		checkoutId = null;
		error = null;
	}

	$effect(() => {
		return () => {
			stopPolling();
		};
	});

	let cashAmount = $state<string>('');
	const cashAmountNum = $derived(cashAmount === '' ? 0 : parseFloat(cashAmount));
	const changeDue = $derived(cashAmountNum > totalDue ? cashAmountNum - totalDue : 0);
	let extraAsTip = $state(false);

	function handleCashInput(e: Event) {
		const input = e.target as HTMLInputElement;
		const cleaned = input.value.replace(/[^0-9.]/g, '');
		const firstDot = cleaned.indexOf('.');
		let sanitized: string;
		if (firstDot !== -1) {
			const integerPart = cleaned.substring(0, firstDot);
			const decimalPart = cleaned.substring(firstDot + 1).replace(/\./g, '');
			sanitized = integerPart + '.' + decimalPart;
		} else {
			sanitized = cleaned;
		}
		if (/^\d+(\.\d{0,2})?$/.test(sanitized) || sanitized === '') {
			cashAmount = sanitized;
		}
	}

	async function handleCashPayment() {
		const cashDue = totalDue - loyaltyDiscount / 100;

		if (cashAmountNum < cashDue) {
			toast.error('Cash amount must cover the total');
			return;
		}

		const tipAmount = extraAsTip ? cashAmountNum - cashDue : 0;

		status = 'cash-confirming';
		error = null;

		try {
			await applyLoyaltyRedemption();

			const body: Record<string, unknown> = {
				amount: Math.round(cashDue * 100),
				payment_type: 'full',
				payment_method: 'cash'
			};
			if (tipAmount > 0) {
				body.tip_enabled = true;
				body.tip_amount = Math.round(tipAmount * 100);
			}

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

			if (!response.ok) {
				const errData = await response.text();
				throw new Error(errData || 'Failed to process payment');
			}

			const data = await response.json();
			status = 'success';
			paymentResult = {
				checkout_id: data.checkout_id || data.id || '',
				status: 'COMPLETED',
				amount: data.amount
			};
			toast.success('Cash payment recorded');
			onComplete(paymentResult);
		} catch (_err) {
			status = 'error';
			error = _err instanceof Error ? _err.message : 'Failed to process payment';
			toast.error(error ?? 'Unknown error');
		}
	}

	let giftCardId = $state('');
	let useAccountBalance = $state(false);

	function formatAndPreserveCursor(
		input: HTMLInputElement,
		formatter: (val: string) => string,
		charRegex: RegExp = /\d/
	): string {
		const rawValue = input.value;
		const oldSelectionStart = input.selectionStart || 0;

		let charsBeforeCursor = 0;
		for (let i = 0; i < oldSelectionStart; i++) {
			if (charRegex.test(rawValue[i])) {
				charsBeforeCursor++;
			}
		}

		const formatted = formatter(rawValue);
		input.value = formatted;

		let newSelectionStart = 0;
		let charsFound = 0;
		for (let i = 0; i < formatted.length; i++) {
			if (charsFound === charsBeforeCursor) {
				break;
			}
			if (charRegex.test(formatted[i])) {
				charsFound++;
			}
			newSelectionStart++;
		}

		requestAnimationFrame(() => {
			input.setSelectionRange(newSelectionStart, newSelectionStart);
		});

		return formatted;
	}

	function formatGiftCardId(value: string): string {
		let raw = value.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
		if (raw.length > 12) raw = raw.slice(0, 12);
		let formatted = '';
		if (raw.length > 0) formatted += raw.slice(0, 4);
		if (raw.length > 4) formatted += '-' + raw.slice(4, 8);
		if (raw.length > 8) formatted += '-' + raw.slice(8, 12);
		return formatted.toUpperCase();
	}

	function handleGiftCardInput(e: Event) {
		const input = e.target as HTMLInputElement;
		const formatted = formatAndPreserveCursor(input, formatGiftCardId, /[a-zA-Z0-9]/);
		giftCardId = formatted;
	}

	const giftCardValid = $derived(useAccountBalance || giftCardId.replace(/-/g, '').length === 12);

	async function handleGiftCardPayment() {
		if (!giftCardValid) {
			toast.error('Please enter a valid 12-character gift card code');
			return;
		}

		const giftDue = totalDue - loyaltyDiscount / 100;

		let payAmountCents = Math.round(giftDue * 100);
		if (useAccountBalance) {
			const parsedAmt = parseFloat(giftCardPaymentAmount);
			if (isNaN(parsedAmt) || parsedAmt <= 0) {
				toast.error('Please enter a valid payment amount');
				return;
			}
			if (parsedAmt > customerBalance) {
				toast.error('Payment amount exceeds available balance');
				return;
			}
			payAmountCents = Math.round(parsedAmt * 100);
		}

		status = 'gift-confirming';
		error = null;

		try {
			await applyLoyaltyRedemption();

			const body: {
				amount: number;
				payment_type: string;
				payment_method: string;
				gift_card_id?: string;
			} = {
				amount: payAmountCents,
				payment_type: 'full',
				payment_method: 'giftcard'
			};
			if (!useAccountBalance) {
				body.gift_card_id = giftCardId.replace(/-/g, '');
			}

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

			if (!response.ok) {
				const errData = await response.text();
				throw new Error(errData || 'Failed to process gift card');
			}

			const data = await response.json();
			status = 'success';
			paymentResult = {
				checkout_id: data.checkout_id || data.id || '',
				status: 'COMPLETED',
				amount: data.amount
			};
			toast.success('Gift card payment recorded');
			onComplete(paymentResult);
		} catch (_err) {
			status = 'error';
			error = _err instanceof Error ? _err.message : 'Failed to process gift card';
			toast.error(error ?? 'Unknown error');
		}
	}

	// Saved cards
	let savedCards = $state<
		Array<{
			id: string;
			card_brand: string;
			card_last4: string;
			card_expiry: string;
			cardholder_name?: string;
		}>
	>([]);
	let loadingSavedCards = $state(false);
	let selectedSavedCardId = $state<string | null>(null);

	async function fetchSavedCards() {
		const targetUserId = booking.user_id ?? booking.user?.id;
		if (!targetUserId) return;
		loadingSavedCards = true;
		savedCards = [];
		selectedSavedCardId = null;
		try {
			const res = await apiFetch(`/api/admin/users/${booking.user_id}/payment-methods`);
			if (res.ok) {
				savedCards = await res.json();
			}
		} catch {
			toast.error('Failed to load saved cards');
		} finally {
			loadingSavedCards = false;
		}
	}

	async function handleSavedCardPayment() {
		if (!selectedSavedCardId) {
			toast.error('Please select a saved card');
			return;
		}

		status = 'saved-card-processing';
		error = null;

		try {
			await applyLoyaltyRedemption();

			const response = await apiFetch(`/api/admin/bookings/${booking.id}/payment`, {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({
					amount: Math.round(totalDue * 100) - loyaltyDiscount,
					payment_type: 'full',
					payment_method: 'saved_card',
					saved_card_id: selectedSavedCardId
				})
			});

			if (!response.ok) {
				const errData = await response.text();
				throw new Error(errData || 'Failed to process saved card payment');
			}

			const data = await response.json();
			status = 'success';
			paymentResult = {
				checkout_id: data.checkout_id || data.id || '',
				status: 'COMPLETED',
				card_brand: data.card_brand,
				last4: data.card_last4,
				amount: data.amount
			};
			toast.success('Saved card payment successful');
			onComplete(paymentResult);
		} catch (_err) {
			status = 'error';
			error = _err instanceof Error ? _err.message : 'Failed to process saved card payment';
			toast.error(error ?? 'Unknown error');
		}
	}

	$effect(() => {
		if (selectedMethod === 'cash') {
			cashAmount = totalDue.toFixed(2);
			extraAsTip = false;
		}
		if (selectedMethod === 'giftcard') {
			giftCardId = '';
		}
		if (selectedMethod === 'savedcard') {
			fetchSavedCards();
		}
	});
</script>

<Dialog.Root open={true} onOpenChange={(open) => !open && handleClose()}>
	<Dialog.Content class="max-h-[90vh] max-w-lg overflow-y-auto">
		<Dialog.Header>
			<Dialog.Title class="text-xl font-semibold">Take Payment</Dialog.Title>
		</Dialog.Header>

		{#if status === 'idle'}
			<div class="space-y-4">
				<div class="rounded-md border border-gray-200 bg-gray-50 p-4">
					<div class="mb-3 text-sm font-semibold text-gray-700">Services</div>
					<div
						class="grid grid-cols-1 {(booking.services?.length ?? 0) > 1
							? 'sm:grid-cols-2'
							: ''} gap-3"
					>
						{#each booking.services ?? [] as service, i (service.service_id ?? `svc-${i}`)}
							<div class="rounded-lg border bg-white p-3">
								<div class="mb-2 text-sm font-medium">
									{service.service_name || 'Unknown Service'}
								</div>
								<div class="flex items-center gap-2">
									<span class="text-xs text-gray-500">£</span>
									<input
										type="text"
										inputmode="decimal"
										tabindex={-1}
										class="flex h-8 w-24 rounded-md border border-input bg-background px-2 py-1 text-sm ring-offset-background focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-none"
										value={serviceOverrides[service.service_id]?.price ??
											service.price?.toFixed(2) ??
											'0.00'}
										oninput={(e) => handlePriceInput(service.service_id, e.currentTarget.value)}
									/>
									{#if serviceOverrides[service.service_id] && Math.abs(parseFloat(serviceOverrides[service.service_id].price) - serviceOverrides[service.service_id].originalPrice) > 0.01}
										<span class="text-xs text-amber-600">
											(was £{serviceOverrides[service.service_id].originalPrice.toFixed(2)})
										</span>
									{/if}
								</div>
							</div>
						{/each}
					</div>
				</div>

				{#if loyaltyEligible}
					<div class="rounded-md border border-fuchsia-100 bg-fuchsia-50 p-4">
						<div class="flex items-start gap-3">
							<Checkbox
								id="use-loyalty-admin"
								bind:checked={useLoyalty}
								disabled={status !== 'idle'}
							/>
							<label for="use-loyalty-admin" class="cursor-pointer select-none">
								<div class="text-sm font-medium text-fuchsia-900">Use Loyalty Stamp Card</div>
								<div class="mt-0.5 text-xs text-fuchsia-700">
									{Math.floor(stamps / 10)} full card{Math.floor(stamps / 10) === 1 ? '' : 's'} available
									&middot; {Math.round(LOYALTY_DISCOUNT_RATE * 100)}% off ({formatCurrency(
										Math.round(booking.total_amount * 100 * LOYALTY_DISCOUNT_RATE)
									)})
								</div>
							</label>
						</div>
					</div>
				{/if}

				{#if booking.discounts && booking.discounts.length > 0}
					<div class="rounded-md border border-gray-100 bg-gray-50/50 p-4">
						<div class="mb-3 flex items-center justify-between">
							<div class="flex items-center gap-1.5 text-sm font-semibold text-gray-800">
								<svg
									class="h-4 w-4 text-gray-500"
									viewBox="0 0 24 24"
									fill="none"
									stroke="currentColor"
									stroke-width="2"
								>
									<path
										d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"
									></path>
									<line x1="7" y1="7" x2="7.01" y2="7"></line>
								</svg>
								Applied Discounts
							</div>
							<span
								class="rounded-full bg-fuchsia-50 px-2 py-0.5 text-xs font-medium text-fuchsia-600"
							>
								{((discountSum / subtotal) * 100).toFixed(0)}% Off Total
							</span>
						</div>
						<div class="space-y-2 text-sm">
							{#each booking.discounts as d (d.id)}
								<div class="flex items-center justify-between text-gray-600">
									<div class="flex items-center gap-1.5">
										<span class="h-1.5 w-1.5 rounded-full bg-fuchsia-400"></span>
										<span>
											{#if d.discount_source === 'loyalty'}
												Loyalty Stamp Card (10% Off)
											{:else if d.campaign_name}
												{d.campaign_name}
											{:else}
												Promo Campaign ({d.discount_percent}% Off)
											{/if}
										</span>
									</div>
									<span class="font-medium text-gray-900">-{formatCurrency(d.discount_amount)}</span
									>
								</div>
							{/each}
						</div>
					</div>
				{/if}

				<div
					class="flex items-center justify-between rounded-md border border-gray-200 bg-white p-4"
				>
					<span class="text-base font-semibold text-gray-700">Total</span>
					<div class="flex items-baseline gap-2.5">
						{#if discountSum > 0.01}
							<span class="text-sm font-medium text-gray-400 line-through"
								>{formatCurrency(subtotal)}</span
							>
						{/if}
						<span class="text-xl font-bold text-gray-900">{formatCurrency(totalDue)}</span>
					</div>
				</div>

				{#if tipEnabled}
					<div class="flex justify-between rounded-md border border-green-200 bg-green-50 p-3">
						<span class="text-sm font-medium text-green-800">
							Total with Tip ({tipDisplay})
						</span>
						<span class="text-lg font-bold text-green-800">
							{formatCurrency(totalWithTip)}
						</span>
					</div>
				{/if}

				<div
					class="grid grid-cols-2 gap-3 {savedCardList.length > 0
						? 'sm:grid-cols-4'
						: 'sm:grid-cols-3'}"
				>
					<button
						type="button"
						class="rounded-lg border py-6 text-center text-sm font-semibold transition-colors {selectedMethod ===
						'card'
							? 'border-input bg-fuchsia-100 text-foreground'
							: 'border-input hover:bg-fuchsia-50'}"
						onclick={() => {
							selectedMethod = 'card';
							status = 'selecting';
						}}
					>
						<svg
							class="mx-auto mb-2 h-8 w-8"
							viewBox="0 0 24 24"
							fill="none"
							stroke="currentColor"
							stroke-width="2"
						>
							<rect x="1" y="4" width="22" height="16" rx="2" ry="2" />
							<line x1="1" y1="10" x2="23" y2="10" />
						</svg>
						Card
					</button>
					<button
						type="button"
						class="rounded-lg border py-6 text-center text-sm font-semibold transition-colors {selectedMethod ===
						'cash'
							? 'border-input bg-fuchsia-100 text-foreground'
							: 'border-input hover:bg-fuchsia-50'}"
						onclick={() => {
							selectedMethod = 'cash';
							status = 'cash-entering';
						}}
					>
						<svg
							class="mx-auto mb-2 h-8 w-8"
							viewBox="0 0 24 24"
							fill="none"
							stroke="currentColor"
							stroke-width="2"
						>
							<line x1="12" y1="1" x2="12" y2="23" />
							<path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" />
						</svg>
						Cash
					</button>
					{#if savedCardList.length > 0}
						<button
							type="button"
							class="hidden rounded-lg border py-6 text-center text-sm font-semibold transition-colors sm:block {selectedMethod ===
							'savedcard'
								? 'border-input bg-fuchsia-100 text-foreground'
								: 'border-input hover:bg-fuchsia-50'}"
							onclick={() => {
								selectedMethod = 'savedcard';
								status = 'saved-card-selecting';
							}}
						>
							<svg
								class="mx-auto mb-2 h-8 w-8"
								viewBox="0 0 24 24"
								fill="none"
								stroke="currentColor"
								stroke-width="2"
							>
								<rect x="1" y="4" width="22" height="16" rx="2" ry="2" />
								<path d="M6 10h12" />
								<path d="M6 14h6" />
							</svg>
							Saved Card
						</button>
					{/if}
					<button
						type="button"
						class="hidden rounded-lg border py-6 text-center text-sm font-semibold transition-colors sm:block {selectedMethod ===
						'giftcard'
							? 'border-input bg-fuchsia-100 text-foreground'
							: 'border-input hover:bg-fuchsia-50'}"
						onclick={() => {
							selectedMethod = 'giftcard';
							status = 'gift-entering';
						}}
					>
						<svg
							class="mx-auto mb-2 h-8 w-8"
							viewBox="0 0 24 24"
							fill="none"
							stroke="currentColor"
							stroke-width="2"
						>
							<polyline points="20 12 20 22 4 22 4 12" />
							<rect x="2" y="7" width="20" height="5" />
							<line x1="12" y1="22" x2="12" y2="7" />
							<path d="M12 7H7.5a2.5 2.5 0 0 1 0-5C11 2 12 7 12 7z" />
							<path d="M12 7h4.5a2.5 2.5 0 0 0 0-5C13 2 12 7 12 7z" />
						</svg>
						Gift Card
					</button>
				</div>

				<div class="flex flex-wrap gap-3 sm:hidden">
					{#if savedCardList.length > 0}
						<button
							type="button"
							class="text-sm text-gray-600 underline hover:text-gray-900"
							onclick={() => {
								selectedMethod = 'savedcard';
								status = 'saved-card-selecting';
							}}
						>
							Pay with Saved Card
						</button>
					{/if}
					<button
						type="button"
						class="text-sm text-gray-600 underline hover:text-gray-900"
						onclick={() => {
							selectedMethod = 'giftcard';
							status = 'gift-entering';
						}}
					>
						Pay with Gift Card
					</button>
				</div>

				<div class="flex gap-3">
					<Button variant="ghost" onclick={handleClose} class="flex-1">Cancel</Button>
				</div>
			</div>
		{:else if status === 'selecting'}
			<div class="space-y-4">
				<div class="flex justify-between rounded-md border border-gray-200 bg-white p-4">
					<span class="text-base font-semibold text-gray-700">Total</span>
					<span class="text-xl font-bold text-gray-900">{formatCurrency(totalDue)}</span>
				</div>

				<div class="space-y-3">
					<span class="text-sm font-medium text-gray-700">Add a Tip</span>
					<div class="grid grid-cols-3 gap-2">
						{#each tipPercentages as tip (tip.pct)}
							<button
								type="button"
								class="rounded-lg border py-3 text-center text-sm font-semibold transition-colors hover:bg-fuchsia-50 {selectedTipPercent ===
								tip.pct
									? 'border-input bg-fuchsia-100 text-foreground'
									: 'border-input'}"
								onclick={() => selectTipPercent(tip.pct)}
							>
								<div>{tip.pct}%</div>
								<div class="text-xs font-normal text-gray-500">£{tip.amount.toFixed(2)}</div>
							</button>
						{/each}
					</div>
					<div class="relative">
						<span class="absolute top-1/2 left-3 -translate-y-1/2 text-gray-500">£</span>
						<Input
							type="text"
							inputmode="decimal"
							tabindex={-1}
							placeholder="Custom tip amount"
							value={customTipAmount}
							oninput={handleCustomTipInput}
							class="pl-7"
						/>
					</div>
				</div>

				{#if tipEnabled}
					<div class="flex justify-between rounded-md border border-green-200 bg-green-50 p-3">
						<span class="text-sm font-medium text-green-800">
							Total with Tip ({tipDisplay})
						</span>
						<span class="text-lg font-bold text-green-800">
							{formatCurrency(totalWithTip)}
						</span>
					</div>
				{/if}

				<div class="flex gap-3">
					<Button variant="ghost" onclick={resetToSelect} class="flex-1">Back</Button>
					<Button onclick={handleCardPayment} class="flex-1">Charge Card</Button>
				</div>
			</div>
		{:else if status === 'card-processing' || status === 'card-polling'}
			<div class="flex flex-col items-center justify-center py-8">
				<div
					class="mb-4 h-12 w-12 animate-spin rounded-full border-4 border-gray-200 border-t-primary"
				></div>
				<p class="text-lg font-medium text-gray-700">Waiting for customer to tap card...</p>
				<p class="mt-2 text-sm text-gray-500">This may take a few moments</p>
			</div>
		{:else if status === 'cash-entering'}
			<div class="space-y-4">
				<div class="flex justify-between rounded-md border border-gray-200 bg-white p-4">
					<span class="text-base font-semibold text-gray-700">Total Due</span>
					<span class="text-xl font-bold text-gray-900">{formatCurrency(totalDue)}</span>
				</div>

				<div>
					<label for="cash-amount" class="text-sm font-medium text-gray-700"> Cash Received </label>
					<div class="relative mt-1">
						<span class="absolute top-1/2 left-3 -translate-y-1/2 text-gray-500">£</span>
						<Input
							id="cash-amount"
							type="text"
							inputmode="decimal"
							tabindex={-1}
							value={cashAmount}
							oninput={handleCashInput}
							class="pl-7 text-lg font-semibold"
						/>
					</div>
				</div>

				{#if cashAmountNum >= totalDue}
					<div class="rounded-md border border-green-200 bg-green-50 p-4">
						<div class="flex justify-between">
							<span class="text-sm font-medium text-green-800">Change Due</span>
							<span class="text-lg font-bold text-green-800">{formatCurrency(changeDue)}</span>
						</div>
						{#if changeDue > 0}
							<div class="mt-2 flex items-center gap-2">
								<Checkbox id="keep-change" bind:checked={extraAsTip} />
								<label for="keep-change" class="text-sm text-green-700">
									Keep {formatCurrency(changeDue)} as tip
								</label>
							</div>
						{/if}
					</div>
				{/if}

				<div class="flex gap-3">
					<Button variant="ghost" onclick={resetToSelect} class="flex-1">Back</Button>
					<Button onclick={handleCashPayment} class="flex-1" disabled={cashAmountNum < totalDue}>
						Confirm Cash
					</Button>
				</div>
			</div>
		{:else if status === 'cash-confirming'}
			<div class="flex flex-col items-center justify-center py-8">
				<div
					class="mb-4 h-12 w-12 animate-spin rounded-full border-4 border-gray-200 border-t-primary"
				></div>
				<p class="text-lg font-medium text-gray-700">Processing cash payment...</p>
			</div>
		{:else if status === 'gift-entering'}
			<div class="space-y-4">
				<div class="flex justify-between rounded-md border border-gray-200 bg-white p-4">
					<span class="text-base font-semibold text-gray-700">Total Due</span>
					<span class="text-xl font-bold text-gray-900">{formatCurrency(totalDue)}</span>
				</div>

				{#if (booking.user_id ?? booking.user?.id) && customerBalance > 0}
					<div class="space-y-2">
						<span class="block text-xs font-semibold tracking-wider text-gray-500 uppercase"
							>Source</span
						>
						<div class="grid grid-cols-2 gap-2">
							<button
								type="button"
								class="rounded-lg border py-2 text-center text-xs font-medium transition-colors {useAccountBalance
									? 'border-input bg-fuchsia-100 text-foreground'
									: 'border-gray-200 hover:bg-gray-50'}"
								onclick={() => (useAccountBalance = true)}
							>
								Account Balance ({formatCurrency(customerBalance)})
							</button>
							<button
								type="button"
								class="rounded-lg border py-2 text-center text-xs font-medium transition-colors {!useAccountBalance
									? 'border-input bg-fuchsia-100 text-foreground'
									: 'border-gray-200 hover:bg-gray-50'}"
								onclick={() => (useAccountBalance = false)}
							>
								Physical Gift Card Code
							</button>
						</div>
					</div>
				{/if}

				{#if useAccountBalance}
					<div>
						<label for="giftcard-amount" class="text-sm font-medium text-gray-700"
							>Amount to pay with Balance (£)</label
						>
						<div class="mt-1 flex gap-2">
							<Input
								id="giftcard-amount"
								type="text"
								inputmode="decimal"
								value={giftCardPaymentAmount}
								oninput={(e) => (giftCardPaymentAmount = (e.target as HTMLInputElement).value)}
								class="flex-1 font-mono text-lg"
							/>
							<Button
								variant="outline"
								size="sm"
								onclick={() => {
									giftCardPaymentAmount = Math.min(customerBalance, totalDue).toFixed(2);
								}}
								class="shrink-0 text-xs"
							>
								Full Balance
							</Button>
						</div>
						<p class="mt-1 text-xs text-gray-500">
							Available balance: {formatCurrency(customerBalance)}. Maximum of total due or balance
							can be used.
						</p>
					</div>
				{:else}
					<div>
						<label for="gift-card-id" class="text-sm font-medium text-gray-700">
							Gift Card Code
						</label>
						<Input
							id="gift-card-id"
							type="text"
							inputmode="text"
							tabindex={-1}
							value={giftCardId}
							oninput={handleGiftCardInput}
							placeholder="XXXX-XXXX-XXXX"
							maxlength={14}
							class="mt-1 font-mono text-lg tracking-widest"
						/>
						<p class="mt-1 text-xs text-gray-500">
							Enter the 12-character code printed on the gift card
						</p>
					</div>
				{/if}

				<div class="flex gap-3">
					<Button variant="ghost" onclick={resetToSelect} class="flex-1">Back</Button>
					<Button onclick={handleGiftCardPayment} class="flex-1" disabled={!giftCardValid}>
						Apply Gift Card
					</Button>
				</div>
			</div>
		{:else if status === 'gift-confirming'}
			<div class="flex flex-col items-center justify-center py-8">
				<div
					class="mb-4 h-12 w-12 animate-spin rounded-full border-4 border-gray-200 border-t-primary"
				></div>
				<p class="text-lg font-medium text-gray-700">Processing gift card...</p>
			</div>
		{:else if status === 'saved-card-selecting'}
			<div class="space-y-4">
				<div class="flex justify-between rounded-md border border-gray-200 bg-white p-4">
					<span class="text-base font-semibold text-gray-700">Total Due</span>
					<span class="text-xl font-bold text-gray-900">{formatCurrency(totalDue)}</span>
				</div>

				{#if loadingSavedCards}
					<div class="flex justify-center py-8">
						<div
							class="h-8 w-8 animate-spin rounded-full border-4 border-gray-200 border-t-primary"
						></div>
					</div>
				{:else if savedCards.length === 0}
					<div class="rounded-md border border-gray-200 bg-gray-50 p-6 text-center">
						<p class="text-sm text-gray-600">No saved cards found for this customer.</p>
						<p class="mt-1 text-xs text-gray-500">
							Add a card via Square Dashboard or use another payment method.
						</p>
					</div>
				{:else}
					<div class="space-y-2">
						<span class="block text-xs font-semibold tracking-wider text-gray-500 uppercase"
							>Select a Saved Card</span
						>
						{#each savedCards as card (card.id)}
							<button
								type="button"
								class="w-full rounded-lg border p-3 text-left transition-colors {selectedSavedCardId ===
								card.id
									? 'border-input bg-fuchsia-100'
									: 'border-gray-200 hover:bg-gray-50'}"
								onclick={() => (selectedSavedCardId = card.id)}
							>
								<div class="flex items-center justify-between">
									<div class="flex items-center gap-2">
										<svg
											class="h-5 w-5 text-gray-500"
											viewBox="0 0 24 24"
											fill="none"
											stroke="currentColor"
											stroke-width="2"
										>
											<rect x="1" y="4" width="22" height="16" rx="2" ry="2" />
											<line x1="1" y1="10" x2="23" y2="10" />
										</svg>
										<span class="font-medium text-gray-900"
											>{card.card_brand} ••••{card.card_last4}</span
										>
									</div>
									<span class="text-xs text-gray-500">{card.card_expiry}</span>
								</div>
								{#if card.cardholder_name}
									<div class="mt-1 text-xs text-gray-500">{card.cardholder_name}</div>
								{/if}
							</button>
						{/each}
					</div>

					<div class="flex items-start gap-2 rounded-md border border-amber-200 bg-amber-50 p-3">
						<svg
							class="mt-0.5 h-4 w-4 shrink-0 text-amber-600"
							viewBox="0 0 24 24"
							fill="none"
							stroke="currentColor"
							stroke-width="2"
						>
							<circle cx="12" cy="12" r="10" />
							<line x1="12" y1="8" x2="12" y2="12" />
							<line x1="12" y1="16" x2="12.01" y2="16" />
						</svg>
						<p class="text-xs text-amber-800">
							This card may require bank app confirmation to complete. Ensure the customer has their
							phone ready.
						</p>
					</div>
				{/if}

				<div class="flex gap-3">
					<Button variant="ghost" onclick={resetToSelect} class="flex-1">Back</Button>
					<Button onclick={handleSavedCardPayment} class="flex-1" disabled={!selectedSavedCardId}>
						Charge Saved Card
					</Button>
				</div>
			</div>
		{:else if status === 'saved-card-processing'}
			<div class="flex flex-col items-center justify-center py-8">
				<div
					class="mb-4 h-12 w-12 animate-spin rounded-full border-4 border-gray-200 border-t-primary"
				></div>
				<p class="text-lg font-medium text-gray-700">Processing saved card payment...</p>
			</div>
		{:else if status === 'error' && error}
			<div class="space-y-4">
				<div class="rounded-md border border-red-200 bg-red-50 p-3">
					<p class="text-sm text-red-800">{error}</p>
				</div>
				<div class="flex gap-3">
					<Button variant="ghost" onclick={handleClose} class="flex-1">Close</Button>
					<Button onclick={resetToSelect} class="flex-1">Try Again</Button>
				</div>
			</div>
		{:else if status === 'success' && paymentResult}
			<div class="space-y-4">
				<div class="flex flex-col items-center justify-center py-4">
					<div class="mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-green-100">
						<svg
							xmlns="http://www.w3.org/2000/svg"
							class="h-8 w-8 text-green-600"
							viewBox="0 0 20 20"
							fill="currentColor"
						>
							<path
								fill-rule="evenodd"
								d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
								clip-rule="evenodd"
							/>
						</svg>
					</div>
					<h3 class="text-xl font-semibold text-gray-900">Payment Successful</h3>
				</div>

				<div class="rounded-md border border-gray-200 bg-gray-50 p-4">
					<div class="space-y-3">
						<div class="flex justify-between">
							<span class="text-sm text-gray-600">Amount</span>
							<span class="font-semibold text-gray-900">
								{formatCurrency(paymentResult.amount)}
							</span>
						</div>
						{#if paymentResult.card_brand}
							<div class="flex justify-between">
								<span class="text-sm text-gray-600">Card</span>
								<span class="font-medium text-gray-900">
									{paymentResult.card_brand} ****{paymentResult.last4}
								</span>
							</div>
						{/if}
						<div class="flex justify-between">
							<span class="text-sm text-gray-600">Status</span>
							<span class="font-medium text-green-600">Completed</span>
						</div>
					</div>
				</div>

				<Button onclick={handleClose} class="w-full">Done</Button>
			</div>
		{/if}
	</Dialog.Content>
</Dialog.Root>
