<!-- #region MultiSelect [C:2] [TYPE Component] [SEMANTICS ui, multi-select, checkbox, language] -->
<!-- @BRIEF Multi-select component with checkboxes and optional search filter. -->
<!-- @UX_STATE default -> Normal state with checkbox list -->
<!-- @UX_STATE empty -> No options match the search filter -->
<!-- @UX_STATE search_active -> Search input is focused/filled -->
<script lang="ts">
  /**
   * Multi-select dropdown/checkbox list component.
   * @prop {Array<{code: string, name: string}>} options - Available options to select from
   * @prop {string[]} selected - Currently selected values (code array)
   * @prop {string} label - Label for the field
   * @prop {boolean} searchable - Whether to show a search filter input
   * @prop {string} placeholder - Placeholder text for search input
   * @prop {number} maxHeight - Max height of the options container before scrolling
   */
  let {
    options = [],
    selected = $bindable([]),
    label = '',
    searchable = false,
    placeholder = 'Search...',
    maxHeight = 200,
    required = false,
    error = '',
  } = $props();

  let searchQuery = $state('');

  let filteredOptions = $derived(
    searchQuery
      ? options.filter(o => o.name.toLowerCase().includes(searchQuery.toLowerCase()) || o.code.toLowerCase().includes(searchQuery.toLowerCase()))
      : options
  );

  function toggle(code) {
    if (selected.includes(code)) {
      selected = selected.filter(c => c !== code);
    } else {
      selected = [...selected, code];
    }
  }

  function handleSearchInput(e) {
    searchQuery = e.target.value;
  }
</script>

<div class="multi-select-wrapper">
  {#if label}
    <label class="block text-sm font-medium text-gray-700 mb-1">
      {label}
      {#if required}
        <span class="text-red-500">*</span>
      {/if}
    </label>
  {/if}

  {#if searchable}
    <input
      type="text"
      value={searchQuery}
      oninput={handleSearchInput}
      placeholder={placeholder}
      class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm mb-2 focus-visible:ring-2 focus-visible:ring-primary-ring focus-visible:border-primary-ring"
    />
  {/if}

  <div
    class="border border-gray-200 rounded-lg divide-y divide-gray-100 overflow-y-auto"
    style="max-height: {maxHeight}px;"
    role="listbox"
    aria-label={label}
  >
    {#if filteredOptions.length === 0}
      <div class="px-3 py-2 text-sm text-gray-400 italic">
        No matching options
      </div>
    {:else}
      {#each filteredOptions as opt}
        <label
          class="flex items-center gap-2 px-3 py-2 text-sm hover:bg-blue-50 cursor-pointer transition-colors {selected.includes(opt.code) ? 'bg-primary-light' : ''}"
          role="option"
          aria-selected={selected.includes(opt.code)}
        >
          <input
            type="checkbox"
            checked={selected.includes(opt.code)}
            onchange={() => toggle(opt.code)}
            class="rounded border-gray-300 text-primary focus-visible:ring-primary-ring"
          />
          <span class="flex-1">{opt.name}</span>
          <span class="text-xs text-gray-400 font-mono">{opt.code}</span>
        </label>
      {/each}
    {/if}
  </div>

  {#if selected.length > 0}
    <div class="flex flex-wrap gap-1 mt-2">
      {#each selected as code}
        {@const opt = options.find(o => o.code === code)}
        <span class="inline-flex items-center gap-1 px-2 py-0.5 bg-blue-100 text-blue-700 rounded-full text-xs font-medium">
          {opt?.name || code}
          <button
            onclick={() => toggle(code)}
            class="hover:text-blue-900"
            aria-label="Remove {opt?.name || code}"
          >
            <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
            </svg>
          </button>
        </span>
      {/each}
    </div>
  {/if}

  {#if error}
    <p class="text-xs text-red-600 mt-1">{error}</p>
  {/if}
</div>
<!-- #endregion MultiSelect -->
