<script lang="ts">
	import { onMount, onDestroy } from 'svelte';
	import { SvelteDate } from 'svelte/reactivity';
	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 } from '$lib/types/booking';
	import type { UserSavedCard } from '$lib/types';
	import CardInput from '$lib/components/payments/CardInput.svelte';
	import PolicyPopover from '$lib/components/ui/policyPopover.svelte';
	import { authStore } from '$lib/stores/auth.svelte';
	import { apiFetch } from '$lib/utils/api';

	const LOYALTY_DISCOUNT_RATE = 0.1;

	interface Props {
		booking: Booking;
		onClose: () => void;
		onComplete: () => void;
		canSaveCards?: boolean;
		defaultPaymentType?: 'full' | 'partial' | 'deposit';
	}

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

	type PaymentStatus = 'idle' | 'processing' | 'polling' | 'success' | 'error';

	let status = $state<PaymentStatus>('idle');
	let error = $state<string | null>(null);
	let paymentResult = $state<{
		id: string;
		amount: number;
		card_brand?: string;
		card_last4?: string;
		payment_type: string;
	} | null>(null);

	// Card selection state
	let paymentMethods = $state<UserSavedCard[]>([]);
	let paymentMethodsLoading = $state(false);
	let selectedPaymentMethod = $state<string | null>(null);
	let showNewCardForm = $state(false);
	let showCardList = $state(false);

	let stamps = $state(0);
	let useLoyalty = $state(false);

	// Auto-select first saved card when methods load
	$effect(() => {
		if (paymentMethods.length > 0 && !selectedPaymentMethod && !showNewCardForm) {
			const defaultCard = paymentMethods.find((m) => m.is_default) ?? paymentMethods[0];
			selectedPaymentMethod = defaultCard.id;
		}
	});

	// New card form fields
	let newCardNumber = $state('');
	let newCardExpiry = $state('');
	let newCardCVC = $state('');
	let saveCardForFuture = $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 formatCardNumber(value: string): string {
		const digits = value.replace(/\D/g, '').substring(0, 16);
		const groups = digits.match(/.{1,4}/g);
		return groups ? groups.join(' ') : digits;
	}

	function _handleCardNumberInput(e: Event) {
		const input = e.target as HTMLInputElement;
		const formatted = formatAndPreserveCursor(input, formatCardNumber);
		newCardNumber = formatted;
	}

	function formatExpiryDate(value: string): string {
		const digits = value.replace(/\D/g, '').substring(0, 4);
		if (digits.length >= 3) {
			return digits.substring(0, 2) + '/' + digits.substring(2);
		}
		return digits;
	}

	function _handleExpiryInput(e: Event) {
		const input = e.target as HTMLInputElement;
		const formatted = formatAndPreserveCursor(input, formatExpiryDate);
		newCardExpiry = formatted;
	}

	function _handleCvcInput(e: Event) {
		const input = e.target as HTMLInputElement;
		const formatted = formatAndPreserveCursor(input, (val) =>
			val.replace(/\D/g, '').substring(0, 4)
		);
		newCardCVC = formatted;
	}

	function parseExpiryParts(value: string): { month: number; year: number } | null {
		if (!/^\d{2}\/\d{2}$/.test(value)) return null;
		const [monthStr, yearStr] = value.split('/');
		const month = parseInt(monthStr, 10);
		const year = 2000 + parseInt(yearStr, 10);
		if (month < 1 || month > 12) return null;
		return { month, year };
	}

	const expiryParts = $derived(parseExpiryParts(newCardExpiry));

	const isExpiryInPast = $derived(
		expiryParts !== null &&
			(() => {
				const expiryDate = new SvelteDate(expiryParts.year, expiryParts.month);
				return expiryDate < new SvelteDate();
			})()
	);

	const hasInvalidMonth = $derived(/^\d{2}\/\d{2}$/.test(newCardExpiry) && expiryParts === null);

	function isValidLuhn(cardNumber: string): boolean {
		const s = cardNumber.replace(/\D/g, '');
		let sum = 0;
		let alternate = false;
		for (let i = s.length - 1; i >= 0; i--) {
			let n = parseInt(s[i], 10);
			if (alternate) {
				n *= 2;
				if (n > 9) n -= 9;
			}
			sum += n;
			alternate = !alternate;
		}
		return sum % 10 === 0 && s.length >= 13 && s.length <= 19;
	}

	const cardFormValid = $derived(
		isValidLuhn(newCardNumber) && expiryParts !== null && newCardCVC.length >= 3 && !isExpiryInPast
	);

	const cardSelected = $derived(
		(selectedPaymentMethod !== null && paymentMethods.length > 0) ||
			(showNewCardForm && cardFormValid) ||
			(paymentMethods.length === 0 && cardFormValid)
	);

	const cardValidationError = $derived(
		!cardSelected
			? selectedPaymentMethod === null && paymentMethods.length > 0 && !showNewCardForm
				? 'Please select a card'
				: !isValidLuhn(newCardNumber) && newCardNumber.length > 0
					? 'Invalid card number'
					: hasInvalidMonth
						? 'Invalid expiry month'
						: isExpiryInPast
							? 'Expiry date in the past'
							: !/^\d{2}\/\d{2}$/.test(newCardExpiry) && newCardExpiry.length > 0
								? 'Enter expiry as MM/YY'
								: newCardCVC.length < 3 && newCardCVC.length > 0
									? 'Enter your CVC number'
									: paymentMethods.length === 0 && !showNewCardForm && newCardNumber.length === 0
										? 'Please enter card details'
										: 'Please complete all card fields'
			: null
	);

	// Partial payment amount (in pounds, user enters)
	let partialAmount = $state<string>('');
	let lastValidPartialAmount = $state<string>('');

	// Campaign discount preview — fetched on mount to show eligible discounts
	let discountPreview = $state<{
		eligible: boolean;
		discounts: Array<{ source: string; name: string; percent: number; amount: number }>;
		original_total: number;
		discounted_total: number;
	} | null>(null);

	// Derived values
	const depositOutstanding = $derived(booking.deposit_required && !booking.deposit_paid);

	// Auto-select a sensible default payment type based on the booking's deposit
	// state. The backend will split the charge into deposit + non-deposit records
	// when appropriate, so this choice mainly controls the button label and amount.
	const defaultType = $derived(defaultPaymentType ?? (depositOutstanding ? 'deposit' : 'full'));
	// eslint-disable-next-line svelte/prefer-writable-derived
	let paymentType = $state<'full' | 'partial' | 'deposit'>('full');
	$effect(() => {
		paymentType = defaultType as 'full' | 'partial' | 'deposit';
	});

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

	// Payment lock state
	let lockTimer = $state(-1);
	let lockAcquired = $state(false);
	let lockInterval: ReturnType<typeof setInterval> | null = null;
	let countdownInterval: ReturnType<typeof setInterval> | null = null;

	const servicesSubtotal = $derived(
		(booking.services ?? []).reduce((sum, s) => sum + (s.price || 0), 0)
	);
	const discountSum = $derived(
		(booking.discounts ?? []).reduce((sum, d) => sum + d.discount_amount, 0)
	);

	const totalPaid = $derived(
		booking.payments
			?.filter((p) => p.status === 'completed')
			.reduce((sum, p) => sum + p.amount, 0) || 0
	);

	const amountRemaining = $derived(booking.total_amount - totalPaid);

	const loyaltyEligible = $derived(
		stamps >= 10 &&
			!(booking.discounts ?? []).some((d) => 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
	);

	// Deposit policy warning text — dynamic based on booking state
	const expectedDepositPercent = $derived(booking.deposit_required ? 20 : 0);
	const depositPolicyWarning = $derived<string | null>(
		{
			get text(): string | null {
				if (!booking.deposit_required && totalPaid === 0 && booking.amount_due <= 0) return null;
				if (booking.deposit_required) {
					return `A ${expectedDepositPercent}% deposit (at least £${(booking.total_amount * 0.2).toFixed(2)}) is required. Any payments up to 50% of total (£${(booking.total_amount * 0.5).toFixed(2)}) are treated as deposit for cancellations.`;
				}
				if (totalPaid > 0 || booking.amount_due > 0) {
					return `Any payment up to 50% of total (£${(booking.total_amount * 0.5).toFixed(2)}) is treated as a protected deposit for cancellations. Paying early is at your own risk.`;
				}
				return null;
			}
		}.text
	);

	const isScenarioA = $derived(depositOutstanding);

	const isScenarioB = $derived(!depositOutstanding && totalPaid < booking.total_amount);

	const partialAmountNum = $derived(partialAmount === '' ? 0 : parseFloat(partialAmount));
	const partialAmountValid = $derived(
		paymentType === 'partial' &&
			partialAmount !== '' &&
			!isNaN(partialAmountNum) &&
			partialAmountNum > 0 &&
			partialAmountNum <= amountRemaining &&
			/^\d+(\.\d{0,2})?$/.test(partialAmount)
	);

	const partialValidationError = $derived(
		paymentType === 'partial' && !partialAmountValid
			? partialAmount === ''
				? 'Enter an amount'
				: !/^\d+(\.\d{0,2})?$/.test(partialAmount)
					? 'Invalid amount format'
					: partialAmountNum <= 0
						? 'Amount must be greater than 0'
						: partialAmountNum > amountRemaining
							? 'Amount exceeds balance'
							: 'Invalid amount'
			: null
	);

	const payButtonDisabled = $derived(
		status === 'processing' ||
			!cardSelected ||
			(paymentType === 'partial' && !partialAmountValid) ||
			(booking.status === 'pending_release' && (lockTimer <= 0 || !lockAcquired))
	);

	const _payButtonError = $derived(
		status === 'processing'
			? null
			: !cardSelected
				? cardValidationError
				: paymentType === 'partial'
					? partialValidationError
					: null
	);

	function campaignDiscountCents(): number {
		return discountPreview?.eligible
			? discountPreview.discounts.reduce((sum, d) => sum + Math.round(d.amount * 100), 0)
			: 0;
	}

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

	function formatTimer(seconds: number): string {
		const m = Math.floor(seconds / 60);
		const s = seconds % 60;
		return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
	}

	function clearLockIntervals() {
		if (countdownInterval) {
			clearInterval(countdownInterval);
			countdownInterval = null;
		}
		if (lockInterval) {
			clearInterval(lockInterval);
			lockInterval = null;
		}
	}

	async function acquireLock() {
		try {
			const response = await apiFetch(`/api/bookings/${booking.id}/payment-lock`, {
				method: 'POST'
			});
			if (response.ok) {
				lockAcquired = true;
				lockTimer = 300;
			}
		} catch (_err) {
			console.error('Failed to acquire payment lock:', _err);
		}
	}

	async function releaseLock() {
		lockAcquired = false;
		clearLockIntervals();
		try {
			await apiFetch(`/api/bookings/${booking.id}/payment-lock`, {
				method: 'DELETE'
			});
		} catch (_err) {
			console.error('Failed to release payment lock:', _err);
		}
	}

	function startCountdown() {
		countdownInterval = setInterval(() => {
			lockTimer = Math.max(0, lockTimer - 1);
		}, 1000);
	}

	function startRenewal() {
		lockInterval = setInterval(async () => {
			try {
				const response = await apiFetch(`/api/bookings/${booking.id}/payment-lock`, {
					method: 'POST'
				});
				if (response.ok) {
					lockTimer = 300;
					lockAcquired = true;
				}
			} catch (_err) {
				console.error('Failed to renew payment lock:', _err);
			}
		}, 60000);
	}

	function generateIdempotencyKey(): string {
		const array = new Uint8Array(16);
		if (typeof window !== 'undefined' && window.crypto) {
			window.crypto.getRandomValues(array);
		} else {
			for (let i = 0; i < 16; i++) array[i] = Math.floor(Math.random() * 256);
		}
		array[6] = (array[6] & 0x0f) | 0x40;
		array[8] = (array[8] & 0x3f) | 0x80;
		return [...array]
			.map((b, i) => {
				const hex = b.toString(16).padStart(2, '0');
				if (i === 4 || i === 6 || i === 8 || i === 10) return '-' + hex;
				return hex;
			})
			.join('');
	}

	async function fetchPaymentMethods() {
		if (!authStore.isAuthenticated) return;
		paymentMethodsLoading = true;
		try {
			const response = await apiFetch('/api/user/payment-methods');
			if (response.ok) {
				paymentMethods = await response.json();
			}
		} catch (_err) {
			console.error('Failed to fetch payment methods:', _err);
		} finally {
			paymentMethodsLoading = false;
		}
	}

	async function fetchLoyaltyData() {
		if (!authStore.isAuthenticated) return;
		try {
			const response = await apiFetch('/api/user/loyalty');
			if (response.ok) {
				const data = await response.json();
				stamps = data.stamps ?? 0;
			}
		} catch (_err) {
			console.error('Failed to fetch loyalty data:', _err);
		}
	}

	function formatCardExpiry(month: number, year: number): string {
		return `${String(month).padStart(2, '0')}/${year.toString().slice(-2)}`;
	}

	function sanitizeAmountInput(value: string): string {
		// Remove all non-numeric chars except .
		const cleaned = value.replace(/[^0-9.]/g, '');
		// Keep only the first .
		const firstDot = cleaned.indexOf('.');
		if (firstDot !== -1) {
			const integerPart = cleaned.substring(0, firstDot);
			const decimalPart = cleaned.substring(firstDot + 1).replace(/\./g, '');
			return integerPart + '.' + decimalPart;
		}
		return cleaned;
	}

	function handlePartialAmountInput(e: Event) {
		const input = e.target as HTMLInputElement;
		const sanitized = sanitizeAmountInput(input.value);
		// Only update if the sanitized value passes the regex (max 2 decimal places)
		if (sanitized === '' || /^\d+(\.\d{0,2})?$/.test(sanitized)) {
			partialAmount = sanitized;
			lastValidPartialAmount = sanitized;
		} else {
			// Reject input with more than 2 decimal places — revert to last valid
			partialAmount = lastValidPartialAmount;
			input.value = lastValidPartialAmount;
		}
	}

	async function makePayment(paymentType: string, amountCents: number) {
		status = 'processing';
		error = null;

		// Apply loyalty redemption before payment
		if (useLoyalty) {
			try {
				const redemptionResponse = await apiFetch(`/api/bookings/${booking.id}/apply-redemption`, {
					method: 'POST',
					headers: { 'Content-Type': 'application/json' }
				});
				if (!redemptionResponse.ok) {
					const errData = await redemptionResponse.text();
					throw new Error(errData || 'Failed to apply loyalty discount');
				}
			} catch (_err) {
				status = 'error';
				const msg = _err instanceof Error ? _err.message : 'Failed to apply loyalty discount';
				error = msg;
				toast.error(msg);
				return;
			}
		}

		let cardId: string | undefined;
		let newCardToken: string | undefined;
		let saveCard = false;

		if (selectedPaymentMethod) {
			cardId = selectedPaymentMethod;
		} else if (newCardNumber) {
			newCardToken = newCardNumber;
			saveCard = saveCardForFuture;
		} else {
			status = 'error';
			error = 'Please select or enter card details';
			toast.error('Please select or enter card details');
			return;
		}

		const idempotencyKey = generateIdempotencyKey();

		try {
			const response = await apiFetch(`/api/bookings/${booking.id}/payment`, {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({
					amount: amountCents,
					payment_type: paymentType,
					card_id: cardId,
					new_card_token: newCardToken,
					save_card: saveCard,
					idempotency_key: idempotencyKey
				})
			});

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

			const data = await response.json();
			// Payment is synchronous (completed immediately)
			status = 'success';
			paymentResult = {
				id: data.id,
				amount: data.amount,
				card_brand: data.card_brand,
				card_last4: data.card_last4,
				payment_type: data.payment_type
			};
			toast.success('Payment successful');
			fetchPaymentMethods();
			onComplete();
			releaseLock();
		} catch (_err) {
			status = 'error';
			const msg = _err instanceof Error ? _err.message : 'Payment declined';
			error = msg;
			toast.error(`${msg}. Please try again or use another card.`);
			releaseLock();
		}
	}

	function handlePayDeposit() {
		const depositCents = booking.deposit_amount
			? Math.round(booking.deposit_amount * 100)
			: Math.round(booking.total_amount * 0.2 * 100);
		makePayment('deposit', depositCents);
	}

	function handlePayFull() {
		const fullCents = Math.round(booking.amount_due * 100);
		const discountedCents = Math.max(0, fullCents - campaignDiscountCents() - loyaltyDiscount);
		const paymentType = booking.amount_paid > 0 ? 'balance' : 'full';
		makePayment(paymentType, discountedCents);
	}

	function handlePayPartial() {
		if (!partialAmountValid) {
			toast.error('Please enter a valid amount');
			return;
		}
		makePayment('partial', Math.round(partialAmountNum * 100));
	}

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

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

	// Fetch payment methods on mount if authenticated
	$effect(() => {
		if (authStore.isAuthenticated) {
			fetchPaymentMethods();
			fetchLoyaltyData();
		}
	});

	// Cleanup on unmount
	$effect(() => {
		return () => {
			stopPolling();
		};
	});

	onMount(async () => {
		if (booking.status === 'pending_release') {
			acquireLock();
			startCountdown();
			startRenewal();
		}

		// Fetch eligible campaign discounts
		try {
			const resp = await apiFetch(`/api/bookings/${booking.id}/discount-preview`);
			if (resp.ok) {
				discountPreview = await resp.json();
			}
		} catch (_err) {
			console.error('Failed to fetch discount preview:', _err);
		}
	});

	onDestroy(() => {
		if (booking.status === 'pending_release' && lockAcquired) {
			releaseLock();
		}
	});
</script>

<Dialog.Root open={true} onOpenChange={(open) => !open && handleClose()}>
	<Dialog.Content class="!z-[70] max-h-[90vh] max-w-[calc(100%-2rem)] overflow-y-auto sm:max-w-md">
		<Dialog.Header>
			<Dialog.Title class="text-xl font-semibold">Make a Payment</Dialog.Title>
			{#if booking.id}
				<div class="mt-1 text-sm text-gray-500">Booking ID: {booking.id}</div>
			{/if}
		</Dialog.Header>

		{#if status === 'idle' || status === 'processing' || status === 'error'}
			<div class="space-y-4">
				<!-- Payment lock countdown banner — only for pending_release (vulnerable slot) -->
				{#if booking.status === 'pending_release' && lockAcquired && lockTimer > 0}
					<div
						class="flex items-center gap-2 rounded-md border p-3 text-sm {lockTimer <= 60
							? 'border-amber-200 bg-amber-50 text-amber-800'
							: 'border-blue-200 bg-blue-50 text-blue-800'}"
					>
						<svg
							class="h-4 w-4 shrink-0"
							viewBox="0 0 24 24"
							fill="none"
							stroke="currentColor"
							stroke-width="2"
						>
							<rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
							<path d="M7 11V7a5 5 0 0110 0v4" />
						</svg>
						<span
							>Slot re-secured for <strong>{formatTimer(lockTimer)}</strong> to ensure smooth payment
							processing</span
						>
					</div>
				{:else if booking.status === 'pending_release' && (lockTimer === 0 || !lockAcquired)}
					<div
						class="flex items-center gap-2 rounded-md border border-red-200 bg-red-50 p-3 text-sm text-red-800"
					>
						<svg
							class="h-4 w-4 shrink-0"
							viewBox="0 0 24 24"
							fill="none"
							stroke="currentColor"
							stroke-width="2"
						>
							<rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
							<path d="M7 11V7a5 5 0 0110 0v4" />
						</svg>
						<span>Slot no longer secured — please close and retry</span>
					</div>
				{/if}
				<!-- Service Breakdown -->
				<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="space-y-2">
						{#each booking.services ?? [] as service, index (index)}
							<div class="flex justify-between text-sm">
								<span class="text-gray-600">{service.service_name || 'Unknown Service'}</span>
								<span class="font-medium">
									{service.override_price
										? formatCurrency(Math.round(service.override_price * 100))
										: service.price
											? formatCurrency(Math.round(service.price * 100))
											: '-'}
								</span>
							</div>
						{/each}
					</div>
				</div>

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

				<!-- Applied Discounts -->
				{#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>
							{#if servicesSubtotal > 0}
								<span
									class="rounded-full bg-fuchsia-50 px-2 py-0.5 text-xs font-medium text-fuchsia-600"
								>
									{((discountSum / servicesSubtotal) * 100).toFixed(0)}% Off Total
								</span>
							{/if}
						</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}

				<!-- Financial Summary -->
				<div class="space-y-2 rounded-md border border-gray-200 bg-white p-4">
					<div class="flex justify-between text-sm">
						<span class="text-gray-600">Total</span>
						<span class="font-medium">{formatCurrency(Math.round(booking.total_amount * 100))}</span
						>
					</div>
					{#if discountPreview?.eligible}
						{#each discountPreview.discounts as d (d.name)}
							<div class="flex justify-between text-sm">
								<span class="text-gray-600">{d.name}</span>
								<span class="font-medium text-green-700"
									>-{formatCurrency(Math.round(d.amount * 100))}</span
								>
							</div>
						{/each}
					{/if}
					<div class="flex justify-between text-sm">
						<span class="text-gray-600">Amount Paid</span>
						<span class="font-medium text-green-700">{formatCurrency(totalPaid)}</span>
					</div>
					{#if useLoyalty && loyaltyDiscount > 0}
						<div class="flex justify-between text-sm">
							<span class="text-gray-600">Loyalty Stamp Card (10% Off)</span>
							<span class="font-medium text-green-700">-{formatCurrency(loyaltyDiscount)}</span>
						</div>
					{/if}
					<div class="flex justify-between border-t border-gray-200 pt-2">
						<span class="font-semibold text-gray-900">Amount Remaining</span>
						<span class="text-lg font-bold text-red-600">
							{formatCurrency(
								Math.max(
									0,
									Math.round(amountRemaining * 100) - campaignDiscountCents() - loyaltyDiscount
								)
							)}
						</span>
					</div>
				</div>

				<!-- Card Selection (only when idle) -->
				{#if status === 'idle' && authStore.isAuthenticated}
					{#if paymentMethodsLoading}
						<div class="py-2 text-center text-sm text-gray-500">Loading payment methods...</div>
					{:else if paymentMethods.length > 0 && !showNewCardForm}
						<!-- Saved card selected -->
						<div class="space-y-3">
							{#if selectedPaymentMethod}
								{#each paymentMethods as method (method.id)}
									{#if method.id === selectedPaymentMethod}
										<div
											class="flex items-center justify-between rounded-lg border border-input bg-fuchsia-100 p-3"
										>
											<div class="flex items-center gap-3">
												<div
													class="flex h-10 min-w-14 items-center justify-center rounded bg-gray-100 px-2 text-xs font-medium"
												>
													{method.brand}
												</div>
												<div class="text-sm">
													<span class="font-mono">**** {method.last_4}</span>
													<span class="ml-2 text-gray-500">
														{formatCardExpiry(method.exp_month, method.exp_year)}
													</span>
												</div>
											</div>
											<span class="text-xs font-medium text-foreground">Selected</span>
										</div>
									{/if}
								{/each}
							{/if}
							{#if canSaveCards}
								<Button
									variant="ghost"
									size="sm"
									class="text-sm text-gray-600"
									onclick={() => (showCardList = !showCardList)}
								>
									{showCardList ? 'Hide other cards' : 'Use a different card'}
								</Button>
							{/if}

							{#if showCardList}
								<div class="space-y-2">
									{#if canSaveCards}
										<button
											type="button"
											class="flex w-full items-center justify-between rounded-lg border p-3 transition-colors hover:border-gray-300"
											onclick={() => {
												showNewCardForm = true;
												showCardList = false;
												selectedPaymentMethod = null;
											}}
										>
											<div class="text-sm font-medium text-gray-700">Enter card details</div>
											<svg
												class="h-4 w-4 text-gray-400"
												viewBox="0 0 24 24"
												fill="none"
												stroke="currentColor"
												stroke-width="2"
											>
												<path d="M9 18l6-6-6-6" />
											</svg>
										</button>
									{/if}
									{#each paymentMethods as method (method.id)}
										<button
											type="button"
											class="flex w-full items-center justify-between rounded-lg border p-3 {selectedPaymentMethod ===
											method.id
												? 'border-input bg-fuchsia-100'
												: 'border-input hover:bg-fuchsia-50'}"
											onclick={() => {
												selectedPaymentMethod = method.id;
												showNewCardForm = false;
												showCardList = false;
											}}
										>
											<div class="flex items-center gap-3">
												<div
													class="flex h-10 min-w-14 items-center justify-center rounded bg-gray-100 px-2 text-xs font-medium"
												>
													{method.brand}
												</div>
												<div class="text-sm">
													<span class="font-mono">**** {method.last_4}</span>
													<span class="ml-2 text-gray-500">
														{formatCardExpiry(method.exp_month, method.exp_year)}
													</span>
												</div>
											</div>
											{#if selectedPaymentMethod === method.id}
												<span class="text-xs font-medium text-foreground">Selected</span>
											{/if}
										</button>
									{/each}
								</div>
							{/if}
						</div>
					{:else}
						<CardInput
							bind:cardNumber={newCardNumber}
							bind:cardExpiry={newCardExpiry}
							bind:cardCVC={newCardCVC}
							bind:saveCard={saveCardForFuture}
							showSaveCard={canSaveCards}
							disabled={false}
						/>
					{/if}

					<!-- Card validation error shown inline near card input -->
					{#if cardValidationError}
						<p class="text-sm text-red-600">{cardValidationError}</p>
					{/if}
				{/if}

				{#if depositPolicyWarning}
					<div class="rounded-md border border-amber-200 bg-amber-50 p-3 text-xs text-amber-800">
						<p class="font-semibold text-amber-900">Cancellation &amp; Deposit Policy</p>
						<p class="mt-1">{depositPolicyWarning}</p>
						<PolicyPopover>
							{#snippet trigger()}
								<span class="mt-1 inline-block underline">Full cancellation policy →</span>
							{/snippet}
						</PolicyPopover>
					</div>
				{/if}

				<!-- Scenario A: Deposit needed -->
				{#if isScenarioA}
					<div class="space-y-3">
						<!-- Payment type radio buttons -->
						<div class="grid grid-cols-2 gap-3">
							<button
								type="button"
								class="rounded-lg border py-3 text-center text-sm font-semibold transition-colors {paymentType ===
								'deposit'
									? 'border-input bg-fuchsia-100 text-foreground'
									: 'border-input hover:bg-fuchsia-50'}"
								onclick={() => (paymentType = 'deposit')}
							>
								Pay Deposit
							</button>
							<button
								type="button"
								class="rounded-lg border py-3 text-center text-sm font-semibold transition-colors {paymentType ===
								'full'
									? 'border-input bg-fuchsia-100 text-foreground'
									: 'border-input hover:bg-fuchsia-50'}"
								onclick={() => (paymentType = 'full')}
							>
								Pay in Full
							</button>
						</div>

						<!-- Pay button -->
						<Button
							onclick={() => (paymentType === 'deposit' ? handlePayDeposit() : handlePayFull())}
							class="w-full"
							loading={status === 'processing'}
							disabled={payButtonDisabled}
						>
							{#if paymentType === 'deposit'}
								Pay Deposit ({formatCurrency(
									booking.deposit_amount
										? Math.round(booking.deposit_amount * 100)
										: Math.round(booking.total_amount * 0.2 * 100)
								)})
							{:else}
								Pay {formatCurrency(
									Math.max(
										0,
										Math.round(booking.amount_due * 100) -
											campaignDiscountCents() -
											(useLoyalty ? loyaltyDiscount : 0)
									)
								)}
							{/if}
						</Button>
					</div>
				{/if}

				<!-- Scenario B: Partial or full payment -->
				{#if isScenarioB}
					<div class="space-y-3">
						<!-- Payment type radio buttons -->
						<div class="grid grid-cols-2 gap-3">
							<button
								type="button"
								class="rounded-lg border py-3 text-center text-sm font-semibold transition-colors {paymentType ===
								'full'
									? 'border-input bg-fuchsia-100 text-foreground'
									: 'border-input hover:bg-fuchsia-50'}"
								onclick={() => (paymentType = 'full')}
							>
								Pay in Full
							</button>
							<button
								type="button"
								class="rounded-lg border py-3 text-center text-sm font-semibold transition-colors {paymentType ===
								'partial'
									? 'border-input bg-fuchsia-100 text-foreground'
									: 'border-input hover:bg-fuchsia-50'}"
								onclick={() => (paymentType = 'partial')}
							>
								Pay Part
							</button>
						</div>

						<!-- Partial amount input (only when partial selected) -->
						{#if paymentType === 'partial'}
							<div>
								<label for="partial-amount" class="text-sm font-medium text-gray-700">
									Partial Payment Amount
								</label>
								<div class="relative mt-1">
									<span class="absolute top-1/2 left-3 -translate-y-1/2 text-gray-500">£</span>
									<Input
										id="partial-amount"
										type="text"
										inputmode="decimal"
										step="0.01"
										placeholder="0.00"
										value={partialAmount}
										oninput={handlePartialAmountInput}
										class="pl-7"
										disabled={status !== 'idle'}
									/>
								</div>
								{#if partialValidationError}
									<p class="mt-1 text-sm text-red-600">{partialValidationError}</p>
								{/if}
							</div>
						{/if}

						<!-- Pay button -->
						<Button
							onclick={() => (paymentType === 'partial' ? handlePayPartial() : handlePayFull())}
							class="w-full"
							loading={status === 'processing'}
							disabled={payButtonDisabled}
						>
							{#if paymentType === 'partial'}
								Pay {partialAmountValid
									? formatCurrency(Math.round(partialAmountNum * 100))
									: 'Part'}
							{:else}
								Pay {formatCurrency(
									Math.max(
										0,
										Math.round(booking.amount_due * 100) -
											campaignDiscountCents() -
											(useLoyalty ? loyaltyDiscount : 0)
									)
								)}
							{/if}
						</Button>
					</div>
				{/if}

				{#if status === 'error' && error}
					<div class="rounded-md border border-red-200 bg-red-50 p-3">
						<p class="text-sm text-red-800">{error}</p>
					</div>
				{/if}

				<!-- Close button -->
				<Button
					variant="ghost"
					onclick={handleClose}
					class="w-full"
					disabled={status === 'processing'}
				>
					Close
				</Button>
			</div>
		{:else if status === 'polling'}
			<!-- Polling State -->
			<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-green-600"
				></div>
				<p class="text-lg font-medium text-gray-700">Processing payment...</p>
				<p class="mt-2 text-sm text-gray-500">This may take a few moments</p>
				<Button variant="ghost" onclick={handleClose} class="mt-6">Cancel</Button>
			</div>
		{:else if status === 'success' && paymentResult}
			<!-- Success State -->
			<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>

				<!-- Receipt -->
				<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>
						<div class="flex justify-between">
							<span class="text-sm text-gray-600">Type</span>
							<span class="font-medium text-gray-900 capitalize">
								{paymentResult.payment_type}
							</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.card_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>
