<script lang="ts">
	import { Plus, Check } from 'lucide-svelte';
	import TagChip from './TagChip.svelte';
	import { filterTagOptions } from './tag-picker-filter';
	import type { ItemTag, ItemTagColor } from '@colectivo/types';
	import * as m from '$lib/paraglide/messages';

	/**
	 * Combobox-style picker for collective tags.
	 *
	 *   - filters `availableTags` by substring on `query`
	 *   - shows a "Create `query`" affordance when no exact match exists
	 *   - calls `onToggle(tag)` for an existing tag click (caller decides
	 *     attach vs detach by reading whether `selectedIds` already has it)
	 *   - calls `onCreate(name)` for a brand-new tag
	 *
	 * Pure UI — does not call the network itself. Re-usable from the item
	 * modal (single-item attach/detach) and the list-filter bar (toggle
	 * filter chips).
	 */
	interface Props {
		availableTags: ItemTag[];
		selectedIds: string[];
		onToggle: (tag: ItemTag) => void | Promise<void>;
		onCreate?: (name: string) => void | Promise<void>;
		placeholder?: string;
		showSelected?: boolean;
	}

	const {
		availableTags,
		selectedIds,
		onToggle,
		onCreate,
		placeholder,
		showSelected = true
	}: Props = $props();

	let query = $state('');
	let inputEl: HTMLInputElement | undefined = $state();

	const result = $derived(filterTagOptions(availableTags, query, selectedIds));
	const selectedTags = $derived(availableTags.filter((t) => selectedIds.includes(t.id)));

	async function handleCreate() {
		if (!onCreate || !result.canCreate) return;
		const name = result.createName;
		await onCreate(name);
		query = '';
		inputEl?.focus();
	}

	async function handleToggle(tag: ItemTag) {
		await onToggle(tag);
		query = '';
		inputEl?.focus();
	}

	function handleKeydown(e: KeyboardEvent) {
		if (e.key === 'Enter') {
			e.preventDefault();
			// Prefer toggling the first match (mirrors typical combobox behaviour);
			// fall back to creating a new tag when nothing matches.
			if (result.matches.length > 0) {
				void handleToggle(result.matches[0]);
			} else if (result.canCreate) {
				void handleCreate();
			}
		}
	}
</script>

<div data-testid="tag-picker" class="space-y-2">
	{#if showSelected && selectedTags.length > 0}
		<div class="flex flex-wrap gap-1.5">
			{#each selectedTags as tag (tag.id)}
				<TagChip
					name={tag.name}
					color={tag.color as ItemTagColor}
					onRemove={() => handleToggle(tag)}
					testid="tag-picker-selected"
				/>
			{/each}
		</div>
	{/if}

	<input
		bind:this={inputEl}
		bind:value={query}
		onkeydown={handleKeydown}
		type="text"
		placeholder={placeholder ?? m.tag_picker_placeholder()}
		data-testid="tag-picker-input"
		class="w-full rounded-md bg-background px-3 py-2 text-sm text-text-primary outline-none ring-1 ring-black/10 focus:ring-slate-900 dark:ring-white/10 dark:focus:ring-slate-100"
	/>

	<div class="flex max-h-48 flex-col gap-1 overflow-y-auto" data-testid="tag-picker-options">
		{#each result.matches as tag (tag.id)}
			{@const isSelected = selectedIds.includes(tag.id)}
			<button
				type="button"
				onclick={() => handleToggle(tag)}
				data-testid="tag-picker-option"
				data-tag={tag.name}
				class="flex items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm hover:bg-black/5 dark:hover:bg-white/5"
			>
				<TagChip name={tag.name} color={tag.color as ItemTagColor} />
				{#if isSelected}
					<Check size={14} strokeWidth={2} class="ml-auto text-text-secondary" />
				{/if}
			</button>
		{/each}

		{#if result.canCreate && onCreate}
			<button
				type="button"
				onclick={handleCreate}
				data-testid="tag-picker-create"
				class="flex items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm text-text-secondary hover:bg-black/5 dark:hover:bg-white/5"
			>
				<Plus size={14} strokeWidth={2} />
				<span>{m.tag_picker_create({ name: result.createName })}</span>
			</button>
		{/if}

		{#if result.matches.length === 0 && !result.canCreate}
			<p class="px-2 py-1.5 text-xs text-text-muted">{m.tag_picker_empty()}</p>
		{/if}
	</div>
</div>
