<script lang="ts">
  // Reorderable list of search result groups.
  //
  // Drag-and-drop alone would leave this unusable with a screen reader or any
  // pointerless input, so every row also carries labelled move up/down buttons
  // which are the primary, always-available mechanism.
  //
  // TRACES: UR-050 | DR-066
  import { searchGroupOrder } from "$lib/stores/searchGroupOrder";
  import { GROUP_LABELS, type SearchGroupId } from "$lib/utils/searchScope";

  let dragIndex = $state<number | null>(null);
  let overIndex = $state<number | null>(null);
  // Announced to assistive tech after a move, since the list itself reorders
  // silently.
  let announcement = $state("");

  function announce(id: SearchGroupId) {
    const position = $searchGroupOrder.indexOf(id) + 1;
    announcement = `${GROUP_LABELS[id]} moved to position ${position} of ${$searchGroupOrder.length}`;
  }

  function move(id: SearchGroupId, delta: number) {
    searchGroupOrder.move(id, delta);
    announce(id);
  }

  function onDragStart(event: DragEvent, index: number) {
    dragIndex = index;
    event.dataTransfer?.setData("text/plain", String(index));
    if (event.dataTransfer) event.dataTransfer.effectAllowed = "move";
  }

  function onDragOver(event: DragEvent, index: number) {
    if (dragIndex === null) return;
    event.preventDefault();
    overIndex = index;
    if (event.dataTransfer) event.dataTransfer.dropEffect = "move";
  }

  function onDrop(event: DragEvent, index: number) {
    event.preventDefault();
    if (dragIndex !== null && dragIndex !== index) {
      const id = $searchGroupOrder[dragIndex];
      searchGroupOrder.reorder(dragIndex, index);
      if (id) announce(id);
    }
    dragIndex = null;
    overIndex = null;
  }

  function onDragEnd() {
    dragIndex = null;
    overIndex = null;
  }
</script>

<ul class="space-y-2">
  {#each $searchGroupOrder as id, i (id)}
    <li
      draggable="true"
      ondragstart={(e) => onDragStart(e, i)}
      ondragover={(e) => onDragOver(e, i)}
      ondrop={(e) => onDrop(e, i)}
      ondragend={onDragEnd}
      class="flex items-center gap-3 px-3 py-2 rounded-lg bg-gray-800 border transition-colors {overIndex ===
      i && dragIndex !== i
        ? 'border-[var(--color-jellyfin)]'
        : 'border-gray-700'} {dragIndex === i ? 'opacity-50' : ''}"
    >
      <!-- Decorative: dragging is the mouse affordance, the buttons below are
           the accessible path. -->
      <svg
        class="w-4 h-4 text-gray-500 flex-shrink-0 cursor-grab"
        fill="currentColor"
        viewBox="0 0 24 24"
        aria-hidden="true"
      >
        <path d="M9 4h2v2H9V4zm4 0h2v2h-2V4zM9 9h2v2H9V9zm4 0h2v2h-2V9zm-4 5h2v2H9v-2zm4 0h2v2h-2v-2zm-4 5h2v2H9v-2zm4 0h2v2h-2v-2z" />
      </svg>

      <span class="text-sm text-gray-400 w-5 flex-shrink-0">{i + 1}</span>
      <span class="flex-1 text-white">{GROUP_LABELS[id]}</span>

      <button
        type="button"
        onclick={() => move(id, -1)}
        disabled={i === 0}
        aria-label="Move {GROUP_LABELS[id]} up"
        class="p-2 rounded text-gray-300 hover:bg-gray-700 hover:text-white transition-colors disabled:opacity-30 disabled:hover:bg-transparent"
      >
        <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7" />
        </svg>
      </button>
      <button
        type="button"
        onclick={() => move(id, 1)}
        disabled={i === $searchGroupOrder.length - 1}
        aria-label="Move {GROUP_LABELS[id]} down"
        class="p-2 rounded text-gray-300 hover:bg-gray-700 hover:text-white transition-colors disabled:opacity-30 disabled:hover:bg-transparent"
      >
        <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
        </svg>
      </button>
    </li>
  {/each}
</ul>

<div class="sr-only" role="status" aria-live="polite">{announcement}</div>

<div class="flex justify-end pt-3">
  <button
    type="button"
    onclick={() => {
      searchGroupOrder.reset();
      announcement = "Search group order reset to default";
    }}
    class="text-sm text-gray-400 hover:text-white transition-colors"
  >
    Reset to default
  </button>
</div>

<style>
  .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border-width: 0;
  }
</style>
