<script lang="ts">
  import { untrack } from 'svelte';
  import { X, Trash2, ArrowDown } from 'lucide-svelte';
  import { player, clearQueue } from '$lib/player/store.svelte';
  import QueueTrackRow from './QueueTrackRow.svelte';

  // onClose: when provided, renders an X button in the header so the
  //   slide-in drawer can dismiss itself. The embedded panel on the
  //   now-playing route (visible at lg+ widths) omits it.
  // closeButtonRef: bind:this hook so the drawer can focus the X for
  //   keyboard users on open.
  // active: true when the queue is on-screen (drawer open, or the always-
  //   visible now-playing panel). Gates the scroll-to-current behavior.
  type Props = {
    onClose?: () => void;
    closeButtonRef?: HTMLButtonElement;
    active?: boolean;
  };

  let { onClose, closeButtonRef = $bindable(), active = true }: Props = $props();

  let scrollBody: HTMLElement | undefined = $state();
  // Whether the now-playing row is (at least partly) within the scroll
  // viewport. Drives auto-follow (only follow while the user is watching the
  // current track) and the "Jump to current" pill (shown when it's off-screen).
  let currentInView = $state(true);
  let sawFirstIndex = false;

  function scrollToCurrent(block: ScrollLogicalPosition, behavior: ScrollBehavior = 'auto') {
    (scrollBody?.children[player.index] as HTMLElement | undefined)?.scrollIntoView({
      block,
      behavior,
    });
    currentInView = true;
  }

  function recomputeInView() {
    const row = scrollBody?.children[player.index] as HTMLElement | undefined;
    if (!scrollBody || !row) {
      currentInView = true;
      return;
    }
    const b = scrollBody.getBoundingClientRect();
    const r = row.getBoundingClientRect();
    currentInView = r.bottom > b.top && r.top < b.bottom;
  }

  // On open (active flips true, or on mount for the always-visible panel),
  // center the now-playing row — parity with the Android queue.
  $effect(() => {
    if (!active) return;
    if (untrack(() => player.queue.length) === 0) return;
    requestAnimationFrame(() => scrollToCurrent('center'));
  });

  // Follow the current track as it auto-advances, but only while the user is
  // still watching it — if they've scrolled away, leave them there (the pill
  // offers the way back). block:'nearest' keeps it minimal (no yank when the
  // row is already visible). Index is tracked; currentInView is read untracked
  // so a scroll that hides the row doesn't itself re-trigger a scroll.
  $effect(() => {
    player.index; // subscribe: follow on advance
    if (!sawFirstIndex) {
      sawFirstIndex = true;
      return; // the open effect already handled the initial position
    }
    if (!active) return;
    if (untrack(() => player.queue.length) === 0) return;
    if (!untrack(() => currentInView)) return;
    requestAnimationFrame(() => scrollToCurrent('nearest'));
  });

  function totalDurationLabel(tracks: { duration_sec: number }[]): string {
    const totalSec = tracks.reduce((s, tr) => s + (tr.duration_sec ?? 0), 0);
    const m = Math.floor(totalSec / 60);
    const h = Math.floor(m / 60);
    return h > 0 ? `${h}h ${m % 60}m` : `${m} min`;
  }
</script>

<div class="relative flex h-full flex-col">
  <div class="flex items-center justify-between border-b border-border px-4 py-3">
    <div>
      <h2 class="text-lg font-semibold">Queue</h2>
      <p class="text-xs text-text-secondary">
        {player.queue.length} {player.queue.length === 1 ? 'track' : 'tracks'}
        {#if player.queue.length > 0} · {totalDurationLabel(player.queue)}{/if}
      </p>
    </div>
    <div class="flex items-center gap-1">
      {#if player.queue.length > 0}
        <button
          type="button"
          aria-label="Clear queue"
          title="Clear queue"
          onclick={() => clearQueue()}
          class="rounded p-1 text-text-secondary hover:text-text-primary"
        >
          <Trash2 size={18} />
        </button>
      {/if}
      {#if onClose}
        <button
          type="button"
          bind:this={closeButtonRef}
          aria-label="Close queue"
          onclick={onClose}
          class="rounded p-1 text-text-secondary hover:text-text-primary"
        >
          <X size={20} />
        </button>
      {/if}
    </div>
  </div>

  <div bind:this={scrollBody} onscroll={recomputeInView} class="flex-1 overflow-y-auto">
    {#if player.queue.length === 0}
      <p class="text-text-secondary text-center p-8">No tracks queued.</p>
    {:else}
      {#each player.queue as track, i (track.id)}
        <QueueTrackRow {track} index={i} isCurrent={i === player.index} />
      {/each}
    {/if}
  </div>

  {#if active && player.queue.length > 0 && !currentInView}
    <button
      type="button"
      onclick={() => scrollToCurrent('center', 'smooth')}
      class="absolute bottom-4 left-1/2 flex -translate-x-1/2 items-center gap-1.5
             rounded-full bg-action-secondary px-3 py-1.5 text-xs font-medium
             text-action-fg shadow-lg"
    >
      <ArrowDown size={14} />
      Jump to current
    </button>
  {/if}
</div>
