<script lang="ts">
import { untrack } from 'svelte';
import { isoToGerman, handleGermanDateInput, germanToIso } from '$lib/shared/utils/date';
import { m } from '$lib/paraglide/messages.js';

interface Props {
	value?: string;
	errorMessage?: string | null;
	name?: string;
	id?: string;
	placeholder?: string;
	class?: string;
	onchange?: () => void;
	ariaLabel?: string;
	ariaDescribedby?: string;
	// Escape hatch for callers that need the raw element, e.g. to set a custom
	// validity and block native form submission while the date is partial.
	inputEl?: HTMLInputElement;
}

let {
	value = $bindable(''),
	errorMessage = $bindable<string | null>(null),
	name,
	id,
	placeholder,
	class: className = '',
	onchange,
	ariaLabel,
	ariaDescribedby,
	inputEl = $bindable()
}: Props = $props();

let display = $state(isoToGerman(value ?? ''));

// Re-derive display when value changes externally (e.g. timeline drag, reset nav).
// Guard prevents overwriting while the user is mid-typing a partial date:
// germanToIso returns '' for partial input, matching value '' → no re-derive.
$effect(() => {
	const externalIso = value ?? '';
	if (germanToIso(untrack(() => display)) !== externalIso) {
		display = isoToGerman(externalIso);
	}
});

// ─── Validation helper ────────────────────────────────────────────────────
function isCalendarValid(iso: string): boolean {
	if (!iso) return false;
	const [, mm, dd] = iso.match(/^\d{4}-(\d{2})-(\d{2})$/) ?? [];
	const month = parseInt(mm, 10);
	const day = parseInt(dd, 10);
	return month >= 1 && month <= 12 && day >= 1 && day <= 31;
}

// ─── Input handler ────────────────────────────────────────────────────────
function handleInput(e: Event) {
	const result = handleGermanDateInput(e);
	display = result.display;

	if (result.display === '') {
		value = '';
		errorMessage = null;
		onchange?.();
		return;
	}

	if (result.display.length < 10) {
		value = '';
		errorMessage = m.form_date_error();
		return;
	}

	const iso = germanToIso(result.display);
	if (!iso || !isCalendarValid(iso)) {
		value = '';
		errorMessage = m.form_date_error();
		return;
	}

	value = iso;
	errorMessage = null;
	onchange?.();
}
</script>

<input
	bind:this={inputEl}
	type="text"
	inputmode="numeric"
	maxlength="10"
	id={id}
	aria-label={ariaLabel}
	aria-describedby={ariaDescribedby}
	value={display}
	placeholder={placeholder ?? m.form_placeholder_date()}
	oninput={handleInput}
	class={className}
/>
{#if name}
	<input type="hidden" name={name} value={value} />
{/if}
