<script lang="ts">
  import { GripVertical, X } from 'lucide-svelte';
  import { draggable, type DragEventData } from '@neodrag/svelte';
  import LikeButton from './LikeButton.svelte';
  import TrackMenu from './TrackMenu.svelte';
  import type { PlaylistTrack } from '$lib/api/types';
  import { playlistTrackToRef } from '$lib/playlists/playlistTrackToRef';
  import { player } from '$lib/player/store.svelte';
  import { offsetToDelta } from './queue-row-math';

  let {
    row,
    isOwner,
    onRemove,
    onPlay,
    onMove
  }: {
    row: PlaylistTrack;
    isOwner: boolean;
    onRemove: (position: number) => void;
    onPlay: (position: number) => void;
    onMove?: (fromPos: number, toPos: number) => void;
  } = $props();

  const isUnavailable = $derived(row.track_id === null);

  // Reconstruct a minimal TrackRef for the kebab menu when the
  // upstream track still exists. When unavailable, the menu is hidden.
  const liveTrack = $derived(playlistTrackToRef(row));

  let measuredRowHeight = 56; // sensible default; replaced on dragStart

  function handleDragStart(data: DragEventData) {
    const rect = data.rootNode.getBoundingClientRect();
    if (rect.height > 0) measuredRowHeight = rect.height;
  }

  function handleDragEnd(data: DragEventData) {
    const delta = offsetToDelta(data.offsetY, measuredRowHeight);
    if (delta === 0) return;
    onMove?.(row.position, row.position + delta);
  }

  function handleHandleKeydown(e: KeyboardEvent) {
    if (e.key === 'ArrowUp') {
      e.preventDefault();
      onMove?.(row.position, row.position - 1);
    } else if (e.key === 'ArrowDown') {
      e.preventDefault();
      onMove?.(row.position, row.position + 1);
    } else if (e.key === ' ' || e.key === 'Enter') {
      // Reorder activates via arrow keys, not Space/Enter. Prevent
      // default so Space doesn't scroll the list and Enter doesn't
      // fire the button's no-op click.
      e.preventDefault();
    }
  }

  function format(sec: number): string {
    const m = Math.floor(sec / 60);
    const s = sec % 60;
    return `${m}:${s.toString().padStart(2, '0')}`;
  }

  // Drag is gated on owner+available. When neither, the action runs but
  // the dragEnd handler skips by returning before onMove fires; visually
  // the user never sees the row move.
  const canDrag = $derived(isOwner && !isUnavailable);

  // "Now playing" highlight: matches QueueTrackRow's treatment so the
  // user can see which row is current without reading the player bar.
  // Unavailable rows (trackId === null) never match.
  const isCurrent = $derived(
    !isUnavailable && player.current?.id === row.track_id,
  );
</script>

<div
  role="listitem"
  class="flex items-center gap-3 px-3 py-2 text-sm transition-colors hover:bg-surface-hover
         {isUnavailable ? 'text-text-muted' : 'text-text-primary'}
         {isCurrent ? 'border-l-2 border-l-accent bg-surface-hover' : ''}"
  use:draggable={{
    axis: 'y',
    bounds: 'parent',
    disabled: !canDrag,
    onDragStart: handleDragStart,
    onDragEnd: handleDragEnd
  }}
>
  {#if isOwner}
    <button
      type="button"
      disabled={!canDrag}
      aria-label="Reorder track (drag or use arrow keys)"
      aria-keyshortcuts="ArrowUp ArrowDown"
      onkeydown={handleHandleKeydown}
      class="flex-shrink-0 cursor-grab text-text-muted hover:text-text-primary
             active:cursor-grabbing focus-visible:outline focus-visible:outline-2
             focus-visible:outline-accent disabled:cursor-not-allowed disabled:opacity-50"
    >
      <GripVertical size={14} strokeWidth={1} />
    </button>
  {/if}

  <button
    type="button"
    class="min-w-0 flex-1 text-left"
    onclick={() => !isUnavailable && onPlay(row.position)}
    disabled={isUnavailable}
  >
    <div class="truncate {isUnavailable ? 'line-through' : ''}">{row.title}</div>
    <div class="truncate text-xs text-text-muted">
      {row.artist_name} · {row.album_title}
    </div>
  </button>

  <span class="flex-shrink-0 text-xs text-text-muted">{format(row.duration_sec)}</span>

  {#if !isUnavailable && liveTrack}
    <LikeButton entityType="track" entityId={liveTrack.id} />
    <TrackMenu track={liveTrack} />
  {/if}

  {#if isOwner}
    <button
      type="button"
      onclick={() => onRemove(row.position)}
      aria-label={`Remove ${row.title} from playlist`}
      class="flex-shrink-0 rounded p-1 text-text-muted hover:bg-surface hover:text-action-destructive"
    >
      <X size={14} strokeWidth={1} />
    </button>
  {/if}
</div>
