<script lang="ts">
	import { SvelteDate } from 'svelte/reactivity';
	import CardInput from './CardInput.svelte';
	import CardBrandIcon from './CardBrandIcon.svelte';

	export interface SelectableCard {
		id: string;
		brand: string;
		last_4: string;
		exp_month: number;
		exp_year: number;
		is_default?: boolean;
	}

	let {
		cards = [],
		canSaveCards = false,
		selectedCardId = $bindable(''),
		newCardNumber = $bindable(''),
		newCardExpiry = $bindable(''),
		newCardCVC = $bindable(''),
		saveCard = $bindable(false),
		onValidityChange = (_valid: boolean) => {}
	}: {
		cards?: SelectableCard[];
		canSaveCards?: boolean;
		selectedCardId?: string;
		newCardNumber?: string;
		newCardExpiry?: string;
		newCardCVC?: string;
		saveCard?: boolean;
		onValidityChange?: (valid: boolean) => void;
	} = $props();

	// Internal — whether the "use a new card" form is shown.
	// When no saved cards exist the form shows by default.
	let showNewCardForm = $state(false);

	// Blur-based validation state (matches the pattern used across all card flows)
	let cardNumberTouched = $state(false);
	let cardExpiryTouched = $state(false);
	let cardCVCTouched = $state(false);

	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 expiryYearMonth = expiryParts.year * 12 + expiryParts.month;
				const now = new SvelteDate();
				const currentYearMonth = now.getFullYear() * 12 + now.getMonth() + 1;
				return expiryYearMonth < currentYearMonth;
			})()
	);

	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;
	}

	function handleFieldBlur(field: string) {
		if (field === 'cardNumber') cardNumberTouched = true;
		else if (field === 'cardExpiry') cardExpiryTouched = true;
		else if (field === 'cardCVC') cardCVCTouched = true;
	}

	function handleFieldInput(field: string) {
		if (field === 'cardNumber') cardNumberTouched = false;
		else if (field === 'cardExpiry') cardExpiryTouched = false;
		else if (field === 'cardCVC') cardCVCTouched = false;
	}

	// Exposed derived state — same semantics as the other card flows.
	const cardError = $derived(
		showNewCardForm || cards.length === 0
			? cardNumberTouched && !isValidLuhn(newCardNumber) && newCardNumber.length > 0
				? 'Invalid card number'
				: cardExpiryTouched && hasInvalidMonth
					? 'Invalid expiry month'
					: cardExpiryTouched && isExpiryInPast
						? 'This card has expired'
						: cardExpiryTouched && newCardExpiry.length > 0 && !/^\d{2}\/\d{2}$/.test(newCardExpiry)
							? 'Enter expiry as MM/YY'
							: cardCVCTouched && newCardCVC.length < 3 && newCardCVC.length > 0
								? 'Enter your CVC number'
								: isValidLuhn(newCardNumber) &&
									  /^\d{2}\/\d{2}$/.test(newCardExpiry) &&
									  newCardCVC.length >= 3
									? null
									: newCardNumber.length === 0 &&
										  newCardExpiry.length === 0 &&
										  newCardCVC.length === 0
										? null
										: 'Please complete all card fields'
			: null
	);

	const isCardValid = $derived(
		(selectedCardId !== '' && cards.length > 0) ||
			(isValidLuhn(newCardNumber) &&
				expiryParts !== null &&
				!isExpiryInPast &&
				newCardCVC.length >= 3)
	);

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

{#if cards.length > 0}
	<div class="space-y-2">
		{#each cards as card (card.id)}
			<button
				type="button"
				class="flex w-full items-center justify-between rounded-lg border p-3 text-left {selectedCardId ===
					card.id && !showNewCardForm
					? 'border-input bg-accent'
					: 'border-gray-200 hover:bg-gray-50'}"
				onclick={() => {
					selectedCardId = card.id;
					showNewCardForm = false;
				}}
			>
				<div class="flex items-center gap-3">
					<CardBrandIcon brand={card.brand} />
					<div class="text-sm">
						<span class="font-mono">**** {card.last_4}</span>
						<span class="ml-2 text-xs text-gray-400"
							>Exp {String(card.exp_month).padStart(2, '0')}/{card.exp_year}</span
						>
					</div>
				</div>
				{#if selectedCardId === card.id && !showNewCardForm}
					<span class="text-xs font-semibold text-primary">Selected</span>
				{/if}
			</button>
		{/each}

		<button
			type="button"
			class="flex w-full items-center justify-between rounded-lg border p-3 text-left {showNewCardForm
				? 'border-input bg-accent'
				: 'border-gray-200 hover:bg-gray-50'}"
			onclick={() => {
				selectedCardId = '';
				showNewCardForm = true;
			}}
		>
			<div class="flex items-center gap-3">
				<div
					class="flex h-8 min-w-12 items-center justify-center rounded border border-dashed border-gray-300 text-xs font-medium text-gray-400"
				>
					NEW
				</div>
				<span class="animate-pulse text-sm font-medium text-gray-700">Use a new card</span>
			</div>
			{#if showNewCardForm}
				<span class="text-xs font-semibold text-primary">Selected</span>
			{/if}
		</button>
	</div>
{/if}

{#if showNewCardForm || cards.length === 0}
	<div class="space-y-3 rounded-lg border bg-gray-50 p-3">
		<CardInput
			bind:cardNumber={newCardNumber}
			bind:cardExpiry={newCardExpiry}
			bind:cardCVC={newCardCVC}
			bind:saveCard
			showSaveCard={canSaveCards}
			onfieldblur={handleFieldBlur}
			onfieldinput={handleFieldInput}
		/>
		{#if cardError}
			<p class="mt-1 text-xs font-semibold text-red-500">{cardError}</p>
		{/if}
	</div>
{/if}
