<!-- TRACES: UR-005, UR-017, UR-028 | DR-009 -->
<script lang="ts">
  /**
   * MiniPlayer component - Always-visible bottom bar audio player
   *
   * Shows current track, playback controls, and progress for audio content.
   * Automatically hides for video content (Movie/Episode).
   * Supports both local and remote playback modes.
   *
   * @req: UR-005 - Control media playback (pause, play, skip, scrub)
   * @req: DR-009 - Audio player UI (mini player)
   * @req: UR-028 - Navigate to artist/album by tapping names in now playing view
   * @req: UR-017 - Like or unlike audio, albums, movies, etc.
   * @req: UR-010 - Control playback of Jellyfin remote sessions
   */

  import { playerController } from "$lib/player";
  import { truncateMiddle } from "$lib/utils/truncateMiddle";
  import { goto } from "$app/navigation";
  import type { MediaItem } from "$lib/api/types";
  import { auth } from "$lib/stores/auth";
  import { commands } from "$lib/api/bindings";
  import {
    mergedMedia,
    mergedIsPlaying,
    mergedPosition,
    mergedDuration,
    shouldShowAudioMiniPlayer
  } from "$lib/stores/player";
  import { currentQueueItem } from "$lib/stores/queue";
  import { isRemoteMode } from "$lib/stores/playbackMode";
  import { selectedSession } from "$lib/stores/sessions";
  import { formatTime, calculateProgress } from "$lib/utils/playbackUnits";
  import { haptics } from "$lib/utils/haptics";
  import { toast } from "$lib/stores/toast";
  import Controls from "./Controls.svelte";
  import FavoriteButton from "$lib/components/FavoriteButton.svelte";
  import CastButton from "$lib/components/sessions/CastButton.svelte";
  import VolumeControl from "./VolumeControl.svelte";
  import CachedImage from "../common/CachedImage.svelte";

  interface Props {
    media: MediaItem | null;
    isPlaying?: boolean;
    position?: number;
    duration?: number;
    shuffle?: boolean;
    repeat?: "off" | "all" | "one";
    hasNext?: boolean;
    hasPrevious?: boolean;
    onExpand?: () => void;
    onSleepTimerClick?: () => void;
    className?: string;
  }

  let {
    media,
    isPlaying = false,
    position = 0,
    duration = 0,
    shuffle = false,
    repeat = "off",
    hasNext = false,
    hasPrevious = false,
    onExpand,
    onSleepTimerClick,
    className = "",
  }: Props = $props();

  // Use merged media store for audio player display (handles both local and remote playback)
  // In remote mode, this automatically uses the remote session's nowPlayingItem
  const displayMedia = $derived($mergedMedia || $currentQueueItem);
  const displayIsPlaying = $derived($mergedIsPlaying);

  // The player's MediaItem doesn't carry favorite state, so read it from the
  // local user_data cache (offline-safe — same source the optimistic toggle
  // writes to). Re-runs whenever the current track changes.
  let isFavorite = $state(false);
  let favoriteLoadedFor = "";
  $effect(() => {
    const id = displayMedia?.id;
    if (!id || id === favoriteLoadedFor) return;
    favoriteLoadedFor = id;
    isFavorite = false;
    const userId = auth.getUserId();
    if (!userId) return;
    commands
      .storageGetPlaybackProgress(userId, id)
      .then((p) => {
        // Guard against a race if the track changed while awaiting.
        if (displayMedia?.id === id) isFavorite = p?.isFavorite ?? false;
      })
      .catch(() => {});
  });
  const displayPosition = $derived($mergedPosition);
  const displayDuration = $derived($mergedDuration);

  // State machine gated visibility - only show when player is playing/paused AND media is audio
  const shouldShow = $derived($shouldShowAudioMiniPlayer);

  const progress = $derived(
    calculateProgress(displayPosition, displayDuration)
  );

  function navigateToArtist(event: MouseEvent, artistId: string) {
    event.stopPropagation();
    goto(`/library/${artistId}`);
  }

  function navigateToAlbum(event: MouseEvent) {
    const currentMedia = displayMedia;
    if (currentMedia?.albumId) {
      event.stopPropagation();
      goto(`/library/${currentMedia.albumId}`);
    }
  }

  // Swipe gesture state
  let touchStartX = $state(0);
  let touchStartY = $state(0);
  let touchEndX = $state(0);
  let touchEndY = $state(0);
  let isSwiping = $state(false);
  let swipeTransform = $state(0);

  // Overflow menu state
  let showOverflowMenu = $state(false);

  // Control handlers for Controls component
  async function handlePlayPause() {
    await playerController.toggle();
  }

  async function handlePrevious() {
    await playerController.previous();
  }

  async function handleNext() {
    await playerController.next();
  }

  async function handleToggleShuffle() {
    await playerController.toggleShuffle();
  }

  async function handleCycleRepeat() {
    await playerController.cycleRepeat();
  }

  // Scrubbing (seek) handler
  async function handleSeek(e: MouseEvent) {
    const target = e.currentTarget as HTMLElement;
    const rect = target.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const percent = x / rect.width;
    const newPosition = percent * displayDuration;

    try {
      await playerController.seek(newPosition);
      haptics.tap();
    } catch (err) {
      console.error("Failed to seek:", err);
      toast.show("Failed to seek", "error");
    }
  }

  // Swipe gesture handlers
  function handleTouchStart(e: TouchEvent) {
    touchStartX = e.touches[0].clientX;
    touchStartY = e.touches[0].clientY;
    touchEndX = touchStartX;
    touchEndY = touchStartY;
    isSwiping = true;
  }

  function handleTouchMove(e: TouchEvent) {
    if (!isSwiping) return;
    touchEndX = e.touches[0].clientX;
    touchEndY = e.touches[0].clientY;

    const diffX = touchStartX - touchEndX;
    const diffY = touchStartY - touchEndY;

    // Only transform if horizontal swipe is dominant
    if (Math.abs(diffX) > Math.abs(diffY)) {
      swipeTransform = -diffX;
      // Prevent default to stop scrolling
      e.preventDefault();
    }
  }

  function handleTouchEnd() {
    if (!isSwiping) return;
    isSwiping = false;

    const diffX = touchStartX - touchEndX;
    const diffY = touchStartY - touchEndY;
    const swipeThreshold = 80;
    const minSwipeDistance = 20; // Minimum distance to be considered a swipe (not a tap)

    // Only process if there was meaningful movement
    const totalDistance = Math.sqrt(diffX * diffX + diffY * diffY);
    if (totalDistance < minSwipeDistance) {
      // This was a tap, not a swipe - ignore it
      swipeTransform = 0;
      touchStartX = 0;
      touchStartY = 0;
      touchEndX = 0;
      touchEndY = 0;
      return;
    }

    // Determine swipe direction
    if (Math.abs(diffX) > Math.abs(diffY)) {
      // Horizontal swipe
      if (Math.abs(diffX) > swipeThreshold) {
        if (diffX > 0) {
          // Swiped left - Next track
          haptics.tap();
          handleNext();
          toast.show("Next track", "info", 1000);
        } else {
          // Swiped right - Previous track
          haptics.tap();
          handlePrevious();
          toast.show("Previous track", "info", 1000);
        }
      }
    } else {
      // Vertical swipe
      if (Math.abs(diffY) > swipeThreshold && diffY > 0) {
        // Swiped up - Open full player
        console.log("[MiniPlayer] Swipe-up detected, expanding player");
        haptics.tap();
        onExpand?.();
      }
    }

    // Reset transform
    swipeTransform = 0;
    touchStartX = 0;
    touchStartY = 0;
    touchEndX = 0;
    touchEndY = 0;
  }

  // Overflow menu actions
  function handleAddToPlaylist() {
    showOverflowMenu = false;
    haptics.tap();
    toast.show("Add to playlist coming soon!", "info");
  }

  function handleGoToAlbum() {
    showOverflowMenu = false;
    if (displayMedia?.albumId) {
      haptics.tap();
      goto(`/library/${displayMedia.albumId}`);
    }
  }

  function handleGoToArtist() {
    showOverflowMenu = false;
    if (displayMedia?.artistItems?.[0]?.id) {
      haptics.tap();
      goto(`/library/${displayMedia.artistItems[0].id}`);
    }
  }

  function handleShare() {
    showOverflowMenu = false;
    haptics.tap();
    toast.show("Share coming soon!", "info");
  }

  function handleViewQueue() {
    showOverflowMenu = false;
    haptics.tap();
    toast.show("Queue view coming soon!", "info");
  }
</script>

{#if shouldShow && displayMedia}
  <div class="{className || 'md:fixed md:bottom-0 fixed bottom-16 left-0 right-0'} bg-[var(--color-surface)] border-t border-gray-800 z-[60]">
    <!-- Remote Mode Indicator -->
    {#if $isRemoteMode && $selectedSession}
      <div class="px-4 py-2 bg-[var(--color-jellyfin)]/20 border-b border-[var(--color-jellyfin)]/30 flex items-center gap-2">
        <svg class="w-4 h-4 text-[var(--color-jellyfin)] flex-shrink-0" fill="currentColor" viewBox="0 0 24 24">
          <path d="M1 18v3h3c0-1.66-1.34-3-3-3zm0-4v2c2.76 0 5 2.24 5 5h2c0-3.87-3.13-7-7-7zm0-4v2c4.97 0 9 4.03 9 9h2c0-6.08-4.93-11-11-11zM21 3H3c-1.1 0-2 .9-2 2v3h2V5h18v14h-7v2h7c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z" />
        </svg>
        <span class="text-xs text-[var(--color-jellyfin)] font-medium">
          Playing on {$selectedSession.deviceName}
        </span>
      </div>
    {/if}

    <!-- Progress bar (clickable for scrubbing) -->
    <button
      onclick={handleSeek}
      class="h-1 bg-gray-700 w-full cursor-pointer hover:h-2 transition-all relative group"
      aria-label="Seek"
    >
      <div
        class="h-full bg-[var(--color-jellyfin)] transition-all duration-100 pointer-events-none"
        style="width: {progress}%"
      ></div>
      <!-- Hover indicator -->
      <div class="absolute inset-0 bg-white/10 opacity-0 group-hover:opacity-100 transition-opacity"></div>
    </button>

    <div
      role="region"
      class="px-4 py-2 touch-pan-y relative"
      ontouchstart={handleTouchStart}
      ontouchmove={handleTouchMove}
      ontouchend={handleTouchEnd}
      style="transform: translateX({swipeTransform}px); transition: {isSwiping ? 'none' : 'transform 0.3s ease-out'}"
    >
      <!-- Row 1: Media info, like, cast, overflow -->
      <div class="flex items-center gap-3">
        <!-- Artwork -->
        <div
          class="w-12 h-12 rounded bg-gray-800 flex-shrink-0 overflow-hidden"
        >
          {#if displayMedia}
            <CachedImage
              itemId={displayMedia.albumId || displayMedia.id}
              imageType="Primary"
              tag={displayMedia.primaryImageTag}
              maxWidth={100}
              alt={displayMedia?.name}
              class="w-full h-full object-cover"
            />
          {:else}
            <div class="w-full h-full flex items-center justify-center text-gray-600">
              <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
                <path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z" />
              </svg>
            </div>
          {/if}
        </div>

        <!-- Title & Artist -->
        <div class="flex-1 min-w-0">
          <div
            class="text-sm font-medium text-white truncate block w-full text-left"
          >
            {truncateMiddle(displayMedia?.name, 40)}
          </div>
          <div class="text-xs text-gray-400 truncate flex items-center gap-1">
            {#if displayMedia?.artistItems?.length}
              {#each displayMedia?.artistItems as artist, i}
                <button
                  onclick={(e) => navigateToArtist(e, artist.id)}
                  class="hover:text-white hover:underline transition-colors"
                >
                  {artist.name}
                </button>{#if i < (displayMedia?.artistItems?.length ?? 0) - 1}<span>,</span>{/if}
              {/each}
            {:else if displayMedia?.artists?.length}
              <span>{displayMedia?.artists.join(", ")}</span>
            {/if}
            {#if displayMedia?.albumId && displayMedia?.albumName}
              {#if displayMedia?.artistItems?.length || displayMedia?.artists?.length}
                <span class="text-gray-500">•</span>
              {/if}
              <button
                onclick={navigateToAlbum}
                class="hover:text-white hover:underline transition-colors"
              >
                {displayMedia?.albumName}
              </button>
            {:else if displayMedia?.albumName}
              <span>{displayMedia?.albumName}</span>
            {/if}
          </div>
        </div>

        <!-- Like Button -->
        {#if displayMedia}
          <FavoriteButton
            itemId={displayMedia?.id ?? ""}
            bind:isFavorite
            size="sm"
          />
        {/if}

        <!-- Cast Button -->
        <CastButton size="sm" />

        <!-- Overflow Menu Button -->
        <div class="relative">
          <button
            onclick={() => {
              showOverflowMenu = !showOverflowMenu;
              haptics.tap();
            }}
            class="p-2 hover:bg-white/10 rounded-full transition-colors"
            aria-label="More options"
          >
            <svg class="w-5 h-5 text-gray-400" fill="currentColor" viewBox="0 0 24 24">
              <path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
            </svg>
          </button>

          <!-- Overflow Menu Dropdown -->
          {#if showOverflowMenu}
            <div
              class="absolute bottom-full right-0 mb-2 w-56 bg-[var(--color-surface)] border border-gray-700 rounded-lg shadow-2xl overflow-hidden z-[70]"
              role="menu"
            >
              <button
                onclick={handleViewQueue}
                class="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/10 transition-colors flex items-center gap-3"
              >
                <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="M4 6h16M4 10h16M4 14h16M4 18h16" />
                </svg>
                View Queue
              </button>

              {#if displayMedia?.albumId}
                <button
                  onclick={handleGoToAlbum}
                  class="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/10 transition-colors flex items-center gap-3"
                >
                  <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
                    <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 14.5v-9l6 4.5-6 4.5z"/>
                  </svg>
                  Go to Album
                </button>
              {/if}

              {#if displayMedia?.artistItems?.length}
                <button
                  onclick={handleGoToArtist}
                  class="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/10 transition-colors flex items-center gap-3"
                >
                  <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
                    <path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
                  </svg>
                  Go to Artist
                </button>
              {/if}

              <button
                onclick={handleAddToPlaylist}
                class="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/10 transition-colors flex items-center gap-3"
              >
                <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="M12 4v16m8-8H4" />
                </svg>
                Add to Playlist
              </button>

              <button
                onclick={handleShare}
                class="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/10 transition-colors flex items-center gap-3"
              >
                <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="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z" />
                </svg>
                Share
              </button>
            </div>
          {/if}
        </div>
      </div>

      <!-- Row 2: Playback controls (play/pause centered) -->
      <div class="flex items-center mt-1">
        <div class="flex-1"></div>

        <Controls
          isPlaying={displayIsPlaying}
          {hasPrevious}
          {hasNext}
          {shuffle}
          {repeat}
          onPlayPause={handlePlayPause}
          onPrevious={handlePrevious}
          onNext={handleNext}
          onToggleShuffle={handleToggleShuffle}
          onCycleRepeat={handleCycleRepeat}
          {onSleepTimerClick}
        />

        <div class="flex-1 flex items-center justify-end gap-2">
          <!-- Volume Control (desktop only) -->
          <div class="hidden sm:block">
            <VolumeControl size="sm" />
          </div>

          <!-- Time (desktop only) -->
          <div class="text-xs text-gray-400 hidden sm:block">
            {formatTime(displayPosition)} / {formatTime(displayDuration)}
          </div>
        </div>
      </div>
    </div>
  </div>
{/if}

<!-- Click outside to close overflow menu -->
{#if showOverflowMenu}
  <button
    class="fixed inset-0 z-[65]"
    onclick={() => showOverflowMenu = false}
    aria-label="Close menu"
  ></button>
{/if}
