<script lang="ts">
	import { Combobox } from 'bits-ui';
	import { phoneCountries, type PhoneCountryCode } from '$lib/utils/phoneCountries';
	import CountryFlag from './CountryFlag.svelte';
	import { cn } from '$lib/utils';
	import { ChevronDown, Search } from 'lucide-svelte';
	import { AsYouType, type CountryCode } from 'libphonenumber-js';

	interface Props {
		/** The full phone number value (E.164 format for form submission) */
		value?: string;
		/** The display value (formatted for the user) */
		displayValue?: string;
		/** Selected country code */
		countryCode?: PhoneCountryCode;
		/** Callback when value changes */
		onValueChange?: (fullNumber: string, nationalNumber: string, countryCode: string) => void;
		/** Placeholder text */
		placeholder?: string;
		/** Whether the input is disabled */
		disabled?: boolean;
		/** Additional classes */
		class?: string;
		/** Name for form submission */
		name?: string;
		/** Whether field is required */
		required?: boolean;
	}

	let {
		value = $bindable(''),
		displayValue = $bindable(''),
		countryCode = $bindable<PhoneCountryCode>('US'),
		onValueChange,
		placeholder = 'Phone number',
		disabled = false,
		class: className = '',
		name,
		required = false
	}: Props = $props();

	let open = $state(false);
	let searchValue = $state('');
	let inputValue = $state('');
	let anchorEl = $state<HTMLElement>(null!);

	// Get selected country
	const selectedCountry = $derived(phoneCountries.find((c) => c.code === countryCode) || phoneCountries[0]);

	// Filter countries based on search
	const filteredCountries = $derived(
		searchValue === ''
			? phoneCountries
			: phoneCountries.filter(
					(c) =>
						c.name.toLowerCase().includes(searchValue.toLowerCase()) ||
						c.code.toLowerCase().includes(searchValue.toLowerCase()) ||
						c.dialCode.includes(searchValue)
				)
	);

	// Format phone number as user types
	function formatPhoneNumber(input: string, country: string): string {
		if (!input) return '';

		// Remove all non-digit characters for processing
		const digitsOnly = input.replace(/\D/g, '');
		if (!digitsOnly) return '';

		try {
			const formatter = new AsYouType(country as CountryCode);
			return formatter.input(digitsOnly);
		} catch {
			// If formatting fails, return digits with basic spacing
			return digitsOnly;
		}
	}

	// Get E.164 format for form submission
	function getE164Number(input: string, country: string): string {
		if (!input) return '';

		const digitsOnly = input.replace(/\D/g, '');
		if (!digitsOnly) return '';

		try {
			const formatter = new AsYouType(country as CountryCode);
			formatter.input(digitsOnly);
			const number = formatter.getNumber();
			return number?.format('E.164') || `${selectedCountry.dialCode}${digitsOnly}`;
		} catch {
			return `${selectedCountry.dialCode}${digitsOnly}`;
		}
	}

	function handleInput(event: Event) {
		const target = event.target as HTMLInputElement;
		const rawValue = target.value;

		// Format the display value
		const formatted = formatPhoneNumber(rawValue, countryCode);
		inputValue = formatted;
		displayValue = formatted;

		// Get E.164 for storage
		const e164 = getE164Number(rawValue, countryCode);
		value = e164;

		// Notify parent
		const digitsOnly = rawValue.replace(/\D/g, '');
		onValueChange?.(e164, digitsOnly, countryCode);
	}

	function handleCountryChange(newCode: string) {
		countryCode = newCode as PhoneCountryCode;
		open = false;
		searchValue = '';

		// Reformat existing number with new country
		if (inputValue) {
			const formatted = formatPhoneNumber(inputValue, newCode);
			inputValue = formatted;
			displayValue = formatted;

			const e164 = getE164Number(inputValue, newCode);
			value = e164;

			const digitsOnly = inputValue.replace(/\D/g, '');
			onValueChange?.(e164, digitsOnly, newCode);
		}
	}

	function handleOpenChange(newOpen: boolean) {
		open = newOpen;
		if (!newOpen) {
			searchValue = '';
		}
	}

	// Initialize display value from value prop
	$effect(() => {
		if (value && !inputValue) {
			// Try to extract national number from E.164
			const digitsOnly = value.replace(/\D/g, '');
			if (digitsOnly) {
				inputValue = formatPhoneNumber(digitsOnly, countryCode);
				displayValue = inputValue;
			}
		}
	});
</script>

<div class={cn('flex gap-2', className)}>
	<!-- Country Code Dropdown -->
	<Combobox.Root
		type="single"
		bind:open
		onOpenChange={handleOpenChange}
		items={phoneCountries.map((c) => ({ value: c.code, label: c.name }))}
		bind:value={countryCode}
		onValueChange={(v) => v && handleCountryChange(v)}
	>
		<div class="relative" bind:this={anchorEl}>
			<Combobox.Trigger
				class={cn(
					'flex h-10 items-center gap-1.5 rounded-lg border border-slate-200 bg-white px-2 text-sm',
					'ring-offset-white transition-colors',
					'focus:outline-none focus:ring-2 focus:ring-monaco-500 focus:ring-offset-2',
					'hover:border-slate-300',
					disabled && 'cursor-not-allowed opacity-50'
				)}
				{disabled}
			>
				<CountryFlag code={countryCode} size="md" />
				<span class="text-slate-600">{selectedCountry.dialCode}</span>
				<ChevronDown
					class={cn('h-3.5 w-3.5 text-slate-400 transition-transform', open && 'rotate-180')}
				/>
			</Combobox.Trigger>

			</div>
		<Combobox.Portal>
			<Combobox.Content
				customAnchor={anchorEl}
				sideOffset={8}
				class={cn(
					'z-[9999] w-72 overflow-hidden rounded-xl border border-slate-200 bg-white shadow-xl',
					'data-[state=open]:animate-in data-[state=closed]:animate-out',
					'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
					'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95'
				)}
			>
				<!-- Search Input -->
				<div class="border-b border-slate-100 p-2">
					<div class="relative">
						<Search class="pointer-events-none absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400" />
						<Combobox.Input
							class="h-9 w-full rounded-md border border-slate-200 bg-white pl-8 pr-3 text-sm placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-monaco-500"
							placeholder="Search countries..."
							oninput={(e) => {
								searchValue = e.currentTarget.value;
							}}
						/>
					</div>
				</div>

				<Combobox.Viewport class="max-h-[220px] overflow-y-auto p-1">
					{#if filteredCountries.length === 0}
						<div class="px-3 py-6 text-center text-sm text-slate-500">
							No countries found
						</div>
					{:else}
						{#each filteredCountries as country (country.code)}
							{@const isSelected = countryCode === country.code}
							<Combobox.Item
								value={country.code}
								label={country.name}
								class={cn(
									'flex cursor-pointer select-none items-center gap-3 rounded-lg px-3 py-2.5 text-sm outline-none transition-colors min-h-[44px]',
									'data-[highlighted]:bg-slate-100',
									isSelected && 'bg-monaco-50'
								)}
							>
								{#snippet children({ selected })}
									<CountryFlag code={country.code} size="md" />
									<span class="flex-1 truncate">{country.name}</span>
									<span class="text-xs font-medium text-slate-500">{country.dialCode}</span>
								{/snippet}
							</Combobox.Item>
						{/each}
					{/if}
				</Combobox.Viewport>
			</Combobox.Content>
		</Combobox.Portal>
	</Combobox.Root>

	<!-- Phone Number Input -->
	<input
		type="tel"
		class={cn(
			'flex h-10 flex-1 rounded-lg border border-slate-200 bg-white px-3 text-sm',
			'ring-offset-white transition-colors',
			'placeholder:text-slate-400',
			'focus:outline-none focus:ring-2 focus:ring-monaco-500 focus:ring-offset-2',
			'hover:border-slate-300',
			disabled && 'cursor-not-allowed opacity-50'
		)}
		{placeholder}
		{disabled}
		{required}
		value={inputValue}
		oninput={handleInput}
		autocomplete="tel-national"
	/>

	<!-- Hidden input for form submission with E.164 format -->
	{#if name}
		<input type="hidden" {name} value={value} />
	{/if}
</div>
