<script lang="ts">
import PersonTypeahead from '$lib/person/PersonTypeahead.svelte';
import TagInput from '$lib/tag/TagInput.svelte';
import DateInput from '$lib/shared/primitives/DateInput.svelte';
import SortDropdown from '$lib/shared/primitives/SortDropdown.svelte';
import { slide } from 'svelte/transition';
import { m } from '$lib/paraglide/messages.js';

let {
	q = $bindable(''),
	from = $bindable(''),
	to = $bindable(''),
	senderId = $bindable(''),
	receiverId = $bindable(''),
	tagNames = $bindable<{ name: string; id?: string; color?: string; parentId?: string }[]>([]),
	tagQ = $bindable(''),
	tagOperator = $bindable<'AND' | 'OR'>('AND'),
	undated = $bindable(false),
	undatedCount = 0,
	sort = $bindable('DATE'),
	dir = $bindable('desc'),
	showAdvanced = $bindable(false),
	initialSenderName = '',
	initialReceiverName = '',
	navKey = 0,
	isLoading = false,
	onSearch,
	onSearchImmediate,
	onfocus,
	onblur
}: {
	q?: string;
	from?: string;
	to?: string;
	senderId?: string;
	receiverId?: string;
	tagNames?: { name: string; id?: string; color?: string; parentId?: string }[];
	tagQ?: string;
	tagOperator?: 'AND' | 'OR';
	undated?: boolean;
	undatedCount?: number;
	sort?: string;
	dir?: string;
	showAdvanced?: boolean;
	initialSenderName?: string;
	initialReceiverName?: string;
	navKey?: number;
	isLoading?: boolean;
	onSearch: () => void;
	onSearchImmediate?: () => void;
	onfocus?: () => void;
	onblur?: () => void;
} = $props();

// Plain (non-reactive) flag — not $state, so no reactive assignment inside $effect
let sortDirMounted = false;

$effect(() => {
	// Read sort and dir so Svelte tracks them as dependencies of this effect.
	// `void` suppresses the ESLint no-unused-expressions rule for bare variable reads.
	void sort;
	void dir;
	if (!sortDirMounted) {
		sortDirMounted = true;
		return;
	}
	onSearch();
});
</script>

<div class="mb-8 rounded-sm border border-line bg-surface p-6 shadow-sm">
	<!-- ROW 1: Main Search (One Line) -->
	<div class="flex items-center gap-4">
		<!-- Full Text Search -->
		<div class="relative flex-1">
			<input
				type="text"
				bind:value={q}
				oninput={onSearch}
				onfocus={onfocus}
				onblur={onblur}
				aria-label={m.docs_search_placeholder()}
				placeholder={m.docs_search_placeholder()}
				class="block w-full border-line py-2.5 pr-4 pl-10 placeholder-ink-3 shadow-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
			/>
			<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
				{#if isLoading}
					<svg
						role="status"
						aria-label="Suche läuft…"
						class="h-4 w-4 animate-spin text-ink-3"
						xmlns="http://www.w3.org/2000/svg"
						fill="none"
						viewBox="0 0 24 24"
					>
						<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"
						></circle>
						<path
							class="opacity-75"
							fill="currentColor"
							d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
						></path>
					</svg>
				{:else}
					<img
						src="/degruyter-icons/Simple/Medium-24px/SVG/Action/Mag-Glass-MD.svg"
						alt=""
						aria-hidden="true"
						class="h-4 w-4 opacity-40"
					/>
				{/if}
			</div>
		</div>

		<!-- Sort Dropdown -->
		<SortDropdown bind:sort={sort} bind:dir={dir} />

		<!-- Toggle Advanced Button -->
		<button
			onclick={() => (showAdvanced = !showAdvanced)}
			class="flex items-center gap-2 border border-line bg-muted px-4 py-2.5 text-sm font-bold tracking-wide text-ink-2 uppercase transition hover:bg-muted hover:text-ink"
		>
			<img
				src="/degruyter-icons/Simple/Small-16px/SVG/Action/Chevron/Chevron-Down-SM.svg"
				alt=""
				aria-hidden="true"
				class="h-4 w-4 transform transition-transform duration-200 {showAdvanced ? 'rotate-180' : ''}"
			/>
			{m.docs_btn_filter()}
		</button>

		<!-- Reset Button -->
		<a
			href="/documents"
			class="flex items-center justify-center border border-transparent px-3 py-2.5 text-ink-3 transition hover:text-red-500"
			title={m.docs_btn_reset_title()}
		>
			<img
				src="/degruyter-icons/Simple/Medium-24px/SVG/Action/Close-MD.svg"
				alt=""
				aria-hidden="true"
				class="h-5 w-5 opacity-40"
			/>
		</a>
	</div>

	<!-- ROW 2: Advanced Filters (Collapsible) -->
	{#if showAdvanced}
		<div
			transition:slide
			class="mt-6 grid grid-cols-1 gap-6 border-t border-line-2 pt-6 md:grid-cols-12"
		>
			<!-- Tag Filter -->
			<div class="md:col-span-12">
				<p class="mb-2 block text-xs font-bold tracking-widest text-ink-2 uppercase">
					{m.docs_filter_label_tags()}
				</p>
				<TagInput
					bind:tags={tagNames}
					allowCreation={false}
					onTextInput={(text) => {
						tagQ = text;
						onSearch();
					}}
				/>
				{#if tagNames.length >= 2}
					<div data-testid="and-or-toggle" class="mt-2 flex items-center gap-1">
						<button
							type="button"
							data-testid="operator-and"
							aria-label={m.filter_operator_and_label()}
							aria-pressed={tagOperator === 'AND'}
							class="rounded px-2 py-0.5 text-xs font-bold tracking-widest uppercase transition-colors {tagOperator === 'AND' ? 'bg-primary text-primary-fg' : 'bg-muted text-ink-2 hover:bg-line'}"
							onclick={() => {
								tagOperator = 'AND';
								(onSearchImmediate ?? onSearch)();
							}}
							>{m.filter_operator_and()}</button
						>
						<button
							type="button"
							data-testid="operator-or"
							aria-label={m.filter_operator_or_label()}
							aria-pressed={tagOperator === 'OR'}
							class="rounded px-2 py-0.5 text-xs font-bold tracking-widest uppercase transition-colors {tagOperator === 'OR' ? 'bg-primary text-primary-fg' : 'bg-muted text-ink-2 hover:bg-line'}"
							onclick={() => {
								tagOperator = 'OR';
								(onSearchImmediate ?? onSearch)();
							}}
							>{m.filter_operator_or()}</button
						>
					</div>
				{/if}
			</div>

			<!-- Sender -->
			<div class="md:col-span-3">
				<div
					class="[&_input]:border-line [&_input]:py-2.5 [&_label]:mb-2 [&_label]:text-xs [&_label]:font-bold [&_label]:tracking-widest [&_label]:text-ink-2 [&_label]:uppercase"
				>
					<PersonTypeahead
						name="senderId"
						label={m.docs_filter_label_sender()}
						bind:value={senderId}
						initialName={initialSenderName}
						resetKey={navKey}
						onchange={onSearch}
					/>
				</div>
			</div>

			<!-- Receiver -->
			<div class="md:col-span-3">
				<div
					class="[&_input]:border-line [&_input]:py-2.5 [&_label]:mb-2 [&_label]:text-xs [&_label]:font-bold [&_label]:tracking-widest [&_label]:text-ink-2 [&_label]:uppercase"
				>
					<PersonTypeahead
						name="receiverId"
						label={m.docs_filter_label_receivers()}
						bind:value={receiverId}
						initialName={initialReceiverName}
						resetKey={navKey}
						onchange={onSearch}
					/>
				</div>
			</div>

			<!-- Dates -->
			<div class="grid grid-cols-2 gap-4 md:col-span-6">
				<div>
					<label
						for="from"
						class="mb-2 block text-xs font-bold tracking-widest text-ink-2 uppercase"
						>{m.docs_filter_label_from()}</label
					>
					<DateInput
						id="from"
						bind:value={from}
						onchange={onSearch}
						class="block w-full rounded-md border border-line bg-surface px-3 py-2.5 text-sm text-ink shadow-sm placeholder:text-ink-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
					/>
				</div>
				<div>
					<label for="to" class="mb-2 block text-xs font-bold tracking-widest text-ink-2 uppercase"
						>{m.docs_filter_label_to()}</label
					>
					<DateInput
						id="to"
						bind:value={to}
						onchange={onSearch}
						class="block w-full rounded-md border border-line bg-surface px-3 py-2.5 text-sm text-ink shadow-sm placeholder:text-ink-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
					/>
				</div>
			</div>

			<!-- Undated-only triage toggle (#668). aria-pressed states the toggle, not a
			     colour; min-h-[44px] meets the senior-audience touch target (WCAG 2.5.5). -->
			<div class="md:col-span-12">
				<button
					type="button"
					data-testid="undated-only-toggle"
					aria-pressed={undated}
					onclick={() => {
						undated = !undated;
						(onSearchImmediate ?? onSearch)();
					}}
					class="inline-flex min-h-[44px] items-center gap-2 rounded border px-3 text-xs font-bold tracking-widest uppercase transition-colors {undated
						? 'border-primary bg-primary text-primary-fg'
						: 'border-line bg-muted text-ink-2 hover:bg-line'}"
				>
					<span
						aria-hidden="true"
						class="inline-flex h-4 w-4 items-center justify-center rounded-sm border {undated
							? 'border-primary-fg bg-primary-fg/20'
							: 'border-ink-3'}"
					>
						{#if undated}✓{/if}
					</span>
					{m.docs_filter_undated_only()}
					<!-- Global count of undated docs matching the current filter across ALL
					     pages (not the page slice). Stays visible regardless of the toggle
					     state so it advertises the triage backlog size (issue #668). -->
					{#if undatedCount > 0}
						<!-- The bare number "42" reads as meaningless next to the toggle label
						     (a screen reader would announce "Nur undatierte 42"). The chip carries
						     a self-describing accessible name ("42 undatierte Dokumente") and its
						     purely-visual digit is hidden from assistive tech (issue #668, Leonie). -->
						<span
							data-testid="undated-count"
							aria-label={m.docs_filter_undated_count_label({ count: undatedCount })}
							class="inline-flex min-w-[1.5rem] items-center justify-center rounded-full px-1.5 py-0.5 text-[0.65rem] leading-none tabular-nums {undated
								? 'bg-primary-fg/20 text-primary-fg'
								: 'bg-line text-ink-2'}"
							><span aria-hidden="true">{undatedCount}</span></span
						>
					{/if}
				</button>
			</div>
		</div>
	{/if}
</div>
