<script lang="ts">
  import { playerController } from "$lib/player";
  import { truncateMiddle } from "$lib/utils/truncateMiddle";
  import { dndzone, SOURCES, TRIGGERS } from "svelte-dnd-action";
  import type { MediaItem } from "$lib/api/types";
  import { auth } from "$lib/stores/auth";
  import { queue } from "$lib/stores/queue";
  import CachedImage from "../common/CachedImage.svelte";
  import { createLogger } from "$lib/utils/logger";

  const log = createLogger("QueueView");

  interface Props {
    items: MediaItem[];
    currentIndex?: number | null;
    onItemClick?: (index: number) => void;
    onClose?: () => void;
  }

  let {
    items,
    currentIndex = null,
    onItemClick,
    onClose,
  }: Props = $props();

  // Add unique IDs for dnd-zone (required)
  interface DndItem extends MediaItem {
    dndId: string;
  }

  let dndItems = $derived<DndItem[]>(
    items.map((item, index) => ({
      ...item,
      dndId: `${item.id}-${index}`,
    }))
  );

  let dragDisabled = $state(true);
  const flipDurationMs = 200;

  function formatDuration(ms?: number | null): string {
    if (!ms) return "";
    const seconds = Math.floor(ms / 1000);
    const mins = Math.floor(seconds / 60);
    const secs = seconds % 60;
    return `${mins}:${secs.toString().padStart(2, "0")}`;
  }

  function handleConsider(e: CustomEvent<{ items: DndItem[]; info: { source: string; trigger: string } }>) {
    const { items: newItems, info } = e.detail;
    // Update local state during drag
    if (info.source === SOURCES.KEYBOARD && info.trigger === TRIGGERS.DRAG_STOPPED) {
      dragDisabled = true;
    }
  }

  async function handleFinalize(e: CustomEvent<{ items: DndItem[]; info: { source: string } }>) {
    const { items: newItems, info } = e.detail;

    // Find the moved item by comparing old and new positions
    const oldIds = dndItems.map(i => i.dndId);
    const newIds = newItems.map(i => i.dndId);

    // Find indices that changed
    let fromIndex = -1;
    let toIndex = -1;

    for (let i = 0; i < oldIds.length; i++) {
      if (oldIds[i] !== newIds[i]) {
        if (fromIndex === -1) {
          // Find where the item at this position came from
          fromIndex = oldIds.indexOf(newIds[i]);
          toIndex = i;
        }
        break;
      }
    }

    if (fromIndex !== -1 && toIndex !== -1 && fromIndex !== toIndex) {
      try {
        // Optimistic update
        queue.moveInQueue(fromIndex, toIndex);

        // Sync with backend
        await playerController.moveInQueue(fromIndex, toIndex);
      } catch (e) {
        log.error("Failed to move queue item:", e);
        // The store already updated optimistically, refresh if needed
      }
    }

    if (info.source === SOURCES.POINTER) {
      dragDisabled = true;
    }
  }

  function startDrag(e: Event) {
    e.preventDefault();
    dragDisabled = false;
  }

  function handleKeyDown(e: KeyboardEvent) {
    if ((e.key === "Enter" || e.key === " ") && dragDisabled) {
      dragDisabled = false;
    }
  }

  async function handleRemove(e: Event, index: number) {
    e.stopPropagation();
    try {
      queue.removeFromQueue(index);
      await playerController.removeFromQueue(index);
    } catch (err) {
      log.error("Failed to remove from queue:", err);
    }
  }
</script>

<div class="bg-[var(--color-surface)] rounded-lg overflow-hidden">
  <div class="flex items-center justify-between p-4 border-b border-gray-700">
    <h2 class="text-lg font-semibold text-white">Queue ({items.length})</h2>
    <button
      onclick={onClose}
      class="p-1 rounded hover:bg-white/10 text-gray-400 hover:text-white transition-colors"
      aria-label="Close queue"
    >
      <svg class="w-5 h-5" 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>
  </div>

  <div class="max-h-96 overflow-y-auto">
    {#if items.length === 0}
      <div class="p-8 text-center text-gray-400">
        <p>Queue is empty</p>
      </div>
    {:else}
      <ul
        use:dndzone={{
          items: dndItems,
          flipDurationMs,
          dragDisabled,
          dropTargetStyle: {},
        }}
        onconsider={handleConsider}
        onfinalize={handleFinalize}
        class="list-none p-0 m-0"
      >
        {#each dndItems as item, index (item.dndId)}
          <li class="outline-none">
            <div
              class="w-full flex items-center gap-2 p-3 hover:bg-white/5 transition-colors {currentIndex === index ? 'bg-white/10' : ''}"
            >
              <!-- Drag handle -->
              <button
                type="button"
                aria-label="Drag to reorder"
                class="p-1 cursor-grab touch-none text-gray-500 hover:text-white transition-colors"
                onmousedown={startDrag}
                ontouchstart={startDrag}
                onkeydown={handleKeyDown}
              >
                <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
                  <path d="M8 6h2v2H8V6zm6 0h2v2h-2V6zM8 11h2v2H8v-2zm6 0h2v2h-2v-2zm-6 5h2v2H8v-2zm6 0h2v2h-2v-2z"/>
                </svg>
              </button>

              <!-- Clickable area for track selection -->
              <button
                type="button"
                onclick={() => onItemClick?.(index)}
                class="flex-1 flex items-center gap-3 text-left min-w-0"
                aria-label="Play {item.name}"
              >
                <!-- Index or playing indicator -->
                <div class="w-6 text-center flex-shrink-0">
                  {#if currentIndex === index}
                    <svg class="w-4 h-4 mx-auto text-[var(--color-jellyfin)]" fill="currentColor" viewBox="0 0 24 24">
                      <path d="M8 5v14l11-7z" />
                    </svg>
                  {:else}
                    <span class="text-sm text-gray-500">{index + 1}</span>
                  {/if}
                </div>

                <!-- Artwork -->
                <div class="w-10 h-10 rounded bg-gray-800 flex-shrink-0 overflow-hidden">
                  {#if item.imageId}
                    <CachedImage
                      itemId={item.id}
                      imageType="Primary"
                      tag={item.imageId}
                      maxWidth={80}
                      alt={item.name}
                      class="w-full h-full object-cover"
                    />
                  {/if}
                </div>

                <!-- Info -->
                <div class="flex-1 min-w-0">
                  <p class="text-sm font-medium truncate {currentIndex === index ? 'text-[var(--color-jellyfin)]' : 'text-white'}">
                    {truncateMiddle(item.name, 48)}
                  </p>
                  {#if item.artists?.length}
                    <p class="text-xs text-gray-400 truncate">
                      {item.artists.join(", ")}
                    </p>
                  {/if}
                </div>

                <!-- Duration -->
                <span class="text-xs text-gray-500 flex-shrink-0">
                  {formatDuration(item.durationMs)}
                </span>
              </button>

              <!-- Remove button -->
              <button
                type="button"
                onclick={(e) => handleRemove(e, index)}
                class="p-1 rounded text-gray-500 hover:text-red-400 hover:bg-white/5 transition-colors"
                aria-label="Remove from queue"
              >
                <svg class="w-4 h-4" 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>
            </div>
          </li>
        {/each}
      </ul>
    {/if}
  </div>
</div>
