<script lang="ts">
  import {
    SkipBack, SkipForward, Play, Pause, Loader2,
    Shuffle, Repeat, Repeat1,
    Volume2, Volume1, VolumeX,
    ListMusic
  } from 'lucide-svelte';
  import {
    player,
    togglePlay, skipNext, skipPrev, seekTo, setVolume,
    toggleShuffle, cycleRepeat, playQueue,
    toggleQueueDrawer
  } from '$lib/player/store.svelte';
  import { formatDuration } from '$lib/media/duration';
  import { FALLBACK_COVER, coverUrl } from '$lib/media/covers';
  import { dominantColorFromUrl, rgbToCssString } from '$lib/media/dominantColor';
  import { useSmoothPosition } from '$lib/player/smoothPosition.svelte';
  import LikeButton from './LikeButton.svelte';
  import TrackMenu from './TrackMenu.svelte';

  const current = $derived(player.current);

  // Per-frame interpolated playhead so the scrubber bar moves
  // smoothly between server ticks instead of stepping every ~250ms.
  // Reset on track/play-state change via the helper's $effect.
  const smoothed = useSmoothPosition();

  const skipPrevDisabled = $derived(player.index === 0 && player.position < 3);
  const skipNextDisabled = $derived(
    player.index === player.queue.length - 1 && player.repeat === 'off'
  );

  const repeatLabel = $derived(
    player.repeat === 'off' ? 'Repeat off' :
    player.repeat === 'all' ? 'Repeat all' : 'Repeat one'
  );

  const VolumeIcon = $derived(
    player.volume === 0 ? VolumeX :
    player.volume < 0.5 ? Volume1 : Volume2
  );

  function onSeekInput(e: Event) {
    const v = Number((e.currentTarget as HTMLInputElement).value);
    seekTo(v);
  }
  function onVolumeInput(e: Event) {
    const v = Number((e.currentTarget as HTMLInputElement).value);
    setVolume(v);
  }
  function onCoverError(e: Event) {
    (e.currentTarget as HTMLImageElement).src = FALLBACK_COVER;
  }

  // #9 — dominant-color accent. Sample the current track's cover and
  // pipe it into a CSS custom property; a 2px strip above the bar
  // takes on the colour, so the page subtly tracks what's playing.
  // Cache-backed in dominantColorFromUrl so revisits are free.
  // Default ('') keeps the strip transparent until the first cover
  // resolves.
  let accentRgb = $state('');
  $effect(() => {
    const cover = current?.album_id ? coverUrl(current.album_id) : null;
    if (!cover) {
      accentRgb = '';
      return;
    }
    dominantColorFromUrl(cover).then((rgb) => {
      if (rgb) accentRgb = rgbToCssString(rgb);
    });
  });
</script>

{#if current}
  <!--
    COMPACT view (below md). Layout per operator design:
      ┌─────────┬───────────┬───────────────────┐
      │ art     │ ♥   ⋮     │ 🔀 🔁 ☰            │  ← short sub-row
      │ title   │           │                   │
      │ artist  │ ⏮  ⏯  ⏭   │ volume slider     │  ← play row at full size
      ├─────────┴───────────┴───────────────────┤
      │ 0:42 ━━━━━●━━━━━━━━━━━━━━━━━━━━━━ 3:21 │
      └─────────────────────────────────────────┘
    Play controls maintain 40/48/40 size; like+kebab and column-3 sub-rows
    are shorter so column 2's bottom edge aligns with column 3's bottom.
  -->
  <!-- Dominant-color accent strip — same colour for both compact
       and desktop variants, only one renders at a time due to the
       md: breakpoint switch below. Transparent until the first
       cover resolves; 300ms tween on colour change so track-skips
       fade rather than snap. -->
  <div
    aria-hidden="true"
    class="md:hidden h-[2px] w-full transition-colors duration-300"
    style={accentRgb ? `background-color: ${accentRgb};` : ''}
  ></div>
  <div
    data-testid="player-bar-compact"
    class="md:hidden flex flex-col gap-1.5 border-t border-border bg-surface px-3 py-2"
  >
    {#if player.state === 'error'}
      <div role="alert" class="flex items-center justify-center gap-3 text-sm text-text-primary">
        <span>{player.error ?? 'Playback failed.'}</span>
        <button
          type="button"
          class="rounded bg-accent px-3 py-1.5 text-sm text-text-primary"
          onclick={() => playQueue(player.queue, player.index)}
        >
          Try again
        </button>
      </div>
    {:else}
      <!-- Top row: 3 columns -->
      <div class="flex items-stretch gap-3">
        <!-- Column 1: art + title + artist. Tap target opens the
             full-screen NowPlaying view (Spotify/YouTube Music pattern).
             Album reachable via the album-name link inside NowPlaying. -->
        <a
          href="/now-playing"
          aria-label="Open now playing"
          class="flex min-w-0 items-center gap-2 focus-visible:outline focus-visible:outline-2 focus-visible:outline-accent"
          style="flex: 1 1 35%;"
        >
          <img
            src={coverUrl(current.album_id)}
            alt=""
            class="h-12 w-12 shrink-0 rounded-md object-cover"
            onerror={onCoverError}
          />
          <div class="min-w-0">
            <div class="truncate text-sm font-medium text-text-primary">{current.title}</div>
            <div class="truncate text-xs text-text-secondary">{current.artist_name}</div>
          </div>
        </a>

        <!-- Column 2: like+kebab (top), play controls (bottom) -->
        <div class="flex flex-col items-center justify-between gap-1 shrink-0">
          <div class="flex items-center gap-0.5">
            <LikeButton entityType="track" entityId={current.id} />
            <TrackMenu track={current} direction="up" hideQueueActions />
          </div>
          <div class="flex items-center gap-1.5">
            <button
              type="button"
              aria-label="Previous"
              disabled={skipPrevDisabled}
              onclick={skipPrev}
              class="flex h-10 w-10 items-center justify-center rounded-full text-text-secondary transition-colors hover:bg-surface-hover hover:text-text-primary disabled:opacity-40 disabled:hover:bg-transparent"
            >
              <SkipBack size={18} strokeWidth={1.5} fill="currentColor" />
            </button>
            <button
              type="button"
              aria-label={player.isPlaying ? 'Pause' : 'Play'}
              onclick={togglePlay}
              class="flex h-12 w-12 items-center justify-center rounded-full bg-accent text-text-primary shadow transition-transform hover:scale-105 focus-visible:ring-2 focus-visible:ring-accent"
            >
              {#if player.state === 'loading' || player.state === 'idle'}
                <Loader2 data-testid="play-spinner" size={22} strokeWidth={1.5} class="animate-spin" />
              {:else if player.isPlaying}
                <Pause size={22} strokeWidth={1.5} fill="currentColor" />
              {:else}
                <Play size={22} strokeWidth={1.5} fill="currentColor" class="ml-0.5" />
              {/if}
            </button>
            <button
              type="button"
              aria-label="Next"
              disabled={skipNextDisabled}
              onclick={skipNext}
              class="flex h-10 w-10 items-center justify-center rounded-full text-text-secondary transition-colors hover:bg-surface-hover hover:text-text-primary disabled:opacity-40 disabled:hover:bg-transparent"
            >
              <SkipForward size={18} strokeWidth={1.5} fill="currentColor" />
            </button>
          </div>
        </div>

        <!-- Column 3: shuffle/repeat/queue (top), volume slider (bottom) -->
        <div class="flex min-w-0 flex-col items-stretch justify-between gap-1" style="flex: 1 1 30%;">
          <div class="flex items-center justify-end gap-0.5">
            <button
              type="button"
              aria-label="Shuffle"
              aria-pressed={player.shuffle}
              onclick={toggleShuffle}
              class="flex h-8 w-8 items-center justify-center rounded-full transition-colors {player.shuffle
                ? 'bg-accent-tint text-accent'
                : 'text-text-secondary hover:bg-surface-hover hover:text-text-primary'}"
            >
              <Shuffle size={16} strokeWidth={1.5} />
            </button>
            <button
              type="button"
              aria-label={repeatLabel}
              onclick={cycleRepeat}
              class="flex h-8 w-8 items-center justify-center rounded-full transition-colors {player.repeat !== 'off'
                ? 'bg-accent-tint text-accent'
                : 'text-text-secondary hover:bg-surface-hover hover:text-text-primary'}"
            >
              {#if player.repeat === 'one'}
                <Repeat1 size={16} strokeWidth={1.5} />
              {:else}
                <Repeat size={16} strokeWidth={1.5} />
              {/if}
            </button>
            <button
              type="button"
              onclick={() => toggleQueueDrawer()}
              aria-label={player.queueDrawerOpen ? 'Close queue' : 'Open queue'}
              aria-pressed={player.queueDrawerOpen}
              class="flex h-8 w-8 items-center justify-center rounded-full transition-colors {player.queueDrawerOpen
                ? 'bg-accent-tint text-accent'
                : 'text-text-secondary hover:bg-surface-hover hover:text-text-primary'}"
            >
              <ListMusic size={16} strokeWidth={1.5} />
            </button>
          </div>
          <label class="flex items-center gap-1">
            <span class="sr-only">Volume</span>
            <VolumeIcon size={14} strokeWidth={1.5} class="shrink-0 text-text-secondary" />
            <input
              type="range"
              aria-label="Volume"
              min="0"
              max="1"
              step="0.01"
              value={player.volume}
              oninput={onVolumeInput}
              class="min-w-0 flex-1 accent-accent"
            />
          </label>
        </div>
      </div>

      <!-- Bottom row: full-width seek slider + time labels.
           Reads the smoothed position so the slider thumb glides
           between server ticks at playback rate. -->
      <div class="flex items-center gap-2">
        <span class="w-9 shrink-0 text-right text-[10px] tabular-nums text-text-secondary">
          {formatDuration(smoothed.value)}
        </span>
        <input
          type="range"
          aria-label="Seek"
          min="0"
          max={player.duration || 0}
          step="0.1"
          value={smoothed.value}
          oninput={onSeekInput}
          class="flex-1 accent-accent"
        />
        <span class="w-9 shrink-0 text-[10px] tabular-nums text-text-secondary">
          {formatDuration(player.duration)}
        </span>
      </div>
    {/if}
  </div>

  <!--
    DESKTOP view (md+). Original 3-column layout — unchanged except that
    the redundant PlayerOverflowMenu kebab is no longer mounted (volume,
    shuffle, repeat, queue all live inline in the right cluster).
  -->
  <!-- See compact-variant accent strip above; desktop has its own
       so both responsive sizes get the same treatment. -->
  <div
    aria-hidden="true"
    class="hidden md:block h-[2px] w-full transition-colors duration-300"
    style={accentRgb ? `background-color: ${accentRgb};` : ''}
  ></div>
  <div
    data-testid="player-bar-desktop"
    class="hidden md:flex md:flex-row md:min-h-[108px] md:items-center md:gap-4 border-t border-border bg-surface md:px-4 md:py-1.5"
  >
    <!-- Left: cover + title + artist + like + menu.
         basis-72 grow max-w-md: holds its 288px floor at the md breakpoint
         (where the seek column is the flex-1 that absorbs the remainder), but
         on wider screens it grows up to 448px instead of leaving the title
         truncated while the seek bar hogs the slack. -->
    <div class="flex basis-72 grow max-w-md min-w-0 items-center gap-3">
      <a
        href="/now-playing"
        aria-label="Open now playing"
        class="shrink-0 focus-visible:outline focus-visible:outline-2 focus-visible:outline-accent"
      >
        <img
          src={coverUrl(current.album_id)}
          alt=""
          class="h-24 w-24 rounded-md object-cover"
          onerror={onCoverError}
        />
      </a>
      <div class="min-w-0 flex-1">
        <div class="truncate text-sm font-medium text-text-primary">{current.title}</div>
        <a
          href={`/artists/${current.artist_id}`}
          class="block truncate text-xs text-text-secondary hover:text-text-primary"
        >
          {current.artist_name}
        </a>
        {#if player.queue.length > player.index + 1}
          {@const nextTrack = player.queue[player.index + 1]}
          <span class="block truncate text-xs text-text-secondary">
            Next · {nextTrack.title} — {nextTrack.artist_name}
          </span>
        {/if}
      </div>
      <LikeButton entityType="track" entityId={current.id} />
      <TrackMenu track={current} direction="up" hideQueueActions />
    </div>

    <!-- Center: seek row + transport row -->
    {#if player.state === 'error'}
      <div role="alert" class="flex flex-1 items-center justify-center gap-3 text-sm text-text-primary">
        <span>{player.error ?? 'Playback failed.'}</span>
        <button
          type="button"
          class="rounded bg-accent px-3 py-1.5 text-sm text-text-primary"
          onclick={() => playQueue(player.queue, player.index)}
        >
          Try again
        </button>
      </div>
    {:else}
      <!-- max-w-xl + mx-auto caps the seek bar (and the transport row) at
           576px and centres it, so on wide screens the extra width flows to
           the title column on the left rather than stretching the scrubber. -->
      <div class="flex flex-1 flex-col items-stretch gap-2 mx-auto w-full max-w-xl">
        <!-- Transport row -->
        <div class="flex items-center justify-center gap-3">
          <button
            type="button"
            aria-label="Previous"
            disabled={skipPrevDisabled}
            onclick={skipPrev}
            class="flex h-10 w-10 items-center justify-center rounded-full text-text-secondary transition-colors hover:bg-surface-hover hover:text-text-primary disabled:opacity-40 disabled:hover:bg-transparent"
          >
            <SkipBack size={20} strokeWidth={1.5} fill="currentColor" />
          </button>
          <button
            type="button"
            aria-label={player.isPlaying ? 'Pause' : 'Play'}
            onclick={togglePlay}
            class="flex h-12 w-12 items-center justify-center rounded-full bg-accent text-text-primary shadow transition-transform hover:scale-105 focus-visible:ring-2 focus-visible:ring-accent"
          >
            {#if player.state === 'loading' || player.state === 'idle'}
              <Loader2 size={24} strokeWidth={1.5} class="animate-spin" />
            {:else if player.isPlaying}
              <Pause size={24} strokeWidth={1.5} fill="currentColor" />
            {:else}
              <Play size={24} strokeWidth={1.5} fill="currentColor" class="ml-0.5" />
            {/if}
          </button>
          <button
            type="button"
            aria-label="Next"
            disabled={skipNextDisabled}
            onclick={skipNext}
            class="flex h-10 w-10 items-center justify-center rounded-full text-text-secondary transition-colors hover:bg-surface-hover hover:text-text-primary disabled:opacity-40 disabled:hover:bg-transparent"
          >
            <SkipForward size={20} strokeWidth={1.5} fill="currentColor" />
          </button>
        </div>
        <!-- Seek row — reads smoothed position so the thumb glides
             between server ticks. See useSmoothPosition. -->
        <div class="flex items-center gap-3">
          <span class="w-12 shrink-0 text-right text-xs tabular-nums text-text-secondary">
            {formatDuration(smoothed.value)}
          </span>
          <input
            type="range"
            aria-label="Seek"
            min="0"
            max={player.duration || 0}
            step="0.1"
            value={smoothed.value}
            oninput={onSeekInput}
            class="flex-1 accent-accent"
          />
          <span class="w-12 shrink-0 text-xs tabular-nums text-text-secondary">
            {formatDuration(player.duration)}
          </span>
        </div>
      </div>
    {/if}

    <!-- Right: shuffle + repeat + queue + volume -->
    <div class="flex w-60 items-center justify-end gap-2">
      <button
        type="button"
        aria-label="Shuffle"
        aria-pressed={player.shuffle}
        onclick={toggleShuffle}
        class="flex h-9 w-9 items-center justify-center rounded-full transition-colors {player.shuffle
          ? 'bg-accent-tint text-accent'
          : 'text-text-secondary hover:bg-surface-hover hover:text-text-primary'}"
      >
        <Shuffle size={18} strokeWidth={1.5} />
      </button>
      <button
        type="button"
        aria-label={repeatLabel}
        onclick={cycleRepeat}
        class="flex h-9 w-9 items-center justify-center rounded-full transition-colors {player.repeat !== 'off'
          ? 'bg-accent-tint text-accent'
          : 'text-text-secondary hover:bg-surface-hover hover:text-text-primary'}"
      >
        {#if player.repeat === 'one'}
          <Repeat1 size={18} strokeWidth={1.5} />
        {:else}
          <Repeat size={18} strokeWidth={1.5} />
        {/if}
      </button>
      <button
        type="button"
        onclick={() => toggleQueueDrawer()}
        aria-label={player.queueDrawerOpen ? 'Close queue' : 'Open queue'}
        aria-pressed={player.queueDrawerOpen}
        class="flex h-9 w-9 items-center justify-center rounded-full transition-colors {player.queueDrawerOpen
          ? 'bg-accent-tint text-accent'
          : 'text-text-secondary hover:bg-surface-hover hover:text-text-primary'}"
      >
        <ListMusic size={18} strokeWidth={1.5} />
      </button>
      <label class="flex items-center gap-1.5">
        <span class="sr-only">Volume</span>
        <VolumeIcon size={18} strokeWidth={1.5} class="shrink-0 text-text-secondary" />
        <input
          type="range"
          aria-label="Volume"
          min="0"
          max="1"
          step="0.01"
          value={player.volume}
          oninput={onVolumeInput}
          class="w-20 accent-accent"
        />
      </label>
    </div>
  </div>
{/if}
