<!-- TRACES: UR-004, UR-005, UR-028 | DR-009 -->
<script lang="ts">
  import { playerController } from "$lib/player";
  import { truncateMiddle } from "$lib/utils/truncateMiddle";
  import { goto } from "$app/navigation";
  import type { MediaItem } from "$lib/api/types";
  import { sleepTimerActive } from "$lib/stores/sleepTimer";
  import { queue, queueItems, currentQueueIndex } from "$lib/stores/queue";
  import {
    mergedMedia,
    mergedIsPlaying,
    mergedPosition,
    mergedDuration
  } from "$lib/stores/player";
  import { isRemoteMode } from "$lib/stores/playbackMode";
  import { selectedSession } from "$lib/stores/sessions";
  import { formatTime } from "$lib/utils/playbackUnits";
  import Controls from "./Controls.svelte";
  import Queue from "./Queue.svelte";
  import CastButton from "$lib/components/sessions/CastButton.svelte";
  import SleepTimerModal from "./SleepTimerModal.svelte";
  import VolumeControl from "./VolumeControl.svelte";
  import CachedImage from "../common/CachedImage.svelte";
  import { currentQueueItem } from "$lib/stores/queue";
  import { createLogger } from "$lib/utils/logger";

  const log = createLogger("AudioPlayer");

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

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

  let seeking = $state(false);
  let seekValue = $state(0);
  let seekPending = $state(false); // True while waiting for backend to confirm seek
  let showSleepTimerModal = $state(false);
  let showQueue = $state(false);

  // 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
  // In local mode, falls back to queue item for complete metadata
  const displayMedia = $derived($mergedMedia || $currentQueueItem);
  const displayIsPlaying = $derived($mergedIsPlaying);
  const rawPosition = $derived($mergedPosition);
  const displayDuration = $derived($mergedDuration);

  function handleSeekStart() {
    seeking = true;
    seekValue = rawPosition;
  }

  function handleSeekInput(e: Event) {
    const target = e.target as HTMLInputElement;
    seekValue = parseFloat(target.value);
  }

  async function handleSeekEnd() {
    seeking = false;
    seekPending = true; // Keep showing target position until backend catches up
    await playerController.seek(seekValue);
  }

  // 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();
  }

  // Prefer album ID for artwork (all tracks in an album share the same cover)
  // Falls back to track ID if no album ID available
  const artworkItemId = $derived(displayMedia?.albumId || displayMedia?.id);

  // Show optimistic position while seeking or waiting for backend confirmation
  const displayPosition = $derived(seeking || seekPending ? seekValue : rawPosition);

  // Clear pending state when backend position catches up to our seek target
  $effect(() => {
    if (seekPending && Math.abs(rawPosition - seekValue) < 2) {
      seekPending = false;
    }
  });

  function navigateToArtist(artistId: string) {
    onClose?.();
    goto(`/library/${artistId}`);
  }

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

  async function handleQueueItemClick(index: number) {
    try {
      queue.skipTo(index);
      await playerController.skipTo(index);
    } catch (e) {
      log.error("Failed to skip to queue item:", e);
    }
  }
</script>

{#if displayMedia}
  <div class="fixed inset-0 z-50 flex flex-col overflow-y-auto">
    <!-- Background image (blurred) -->
    {#if artworkItemId}
      <div class="fixed inset-0 z-0">
        <CachedImage
          itemId={artworkItemId}
          imageType="Primary"
          tag={displayMedia?.imageId}
          maxWidth={800}
          alt=""
          class="w-full h-full object-cover blur-3xl opacity-30"
        />
        <div class="absolute inset-0 bg-gradient-to-b from-black/60 via-black/80 to-black"></div>
      </div>
    {:else}
      <div class="fixed inset-0 z-0 bg-[var(--color-background)]"></div>
    {/if}

    <!-- Content overlay. The blurred artwork behind it stays edge-to-edge; only
         this layer is inset, so the close button clears the status bar and the
         transport controls clear the Android gesture bar. (UR-066) -->
    <div
      class="relative z-10 flex flex-col h-full"
      style:padding-top="var(--safe-top)"
      style:padding-bottom="var(--safe-bottom)"
      style:padding-left="var(--safe-left)"
      style:padding-right="var(--safe-right)"
    >
    <!-- Header -->
    <div class="flex items-center justify-between p-4 flex-shrink-0">
      <button
        onclick={onClose}
        class="p-2 rounded-full hover:bg-white/10 transition-colors"
        aria-label="Close player"
      >
        <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
        </svg>
      </button>

      <div class="flex flex-col items-center">
        <p class="text-sm text-gray-400">Now Playing</p>
        {#if $isRemoteMode && $selectedSession}
          <p class="text-xs text-[var(--color-jellyfin)] flex items-center gap-1">
            <svg class="w-3 h-3" 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>
            {$selectedSession.deviceName}
          </p>
        {/if}
      </div>

      <div class="flex items-center gap-2">
        <!-- Cast Button -->
        <CastButton size="md" />

        <!-- Queue Button -->
        <button
          onclick={() => (showQueue = !showQueue)}
          class="p-2 rounded-full hover:bg-white/10 transition-colors {showQueue ? 'bg-white/10 text-[var(--color-jellyfin)]' : ''}"
          title="Queue"
          aria-label="Open queue"
        >
          <svg class="w-6 h-6" 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>
        </button>

        <button
          onclick={() => (showSleepTimerModal = true)}
          class="p-2 rounded-full hover:bg-white/10 transition-colors relative"
          title="Sleep timer"
          aria-label="Sleep timer"
        >
          <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
              d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
          </svg>
          {#if $sleepTimerActive}
            <span class="absolute top-1 right-1 w-2 h-2 bg-[var(--color-jellyfin)] rounded-full"></span>
          {/if}
        </button>

        <!-- Volume Control (Linux only) -->
        <VolumeControl size="md" />
      </div>
    </div>

    <!-- Artwork -->
    <div class="flex-1 flex items-center justify-center p-8 min-h-0">
      <div class="w-full max-w-md aspect-square rounded-lg overflow-hidden shadow-2xl flex-shrink-0">
        {#if artworkItemId}
          <CachedImage
            itemId={artworkItemId}
            imageType="Primary"
            tag={displayMedia?.imageId}
            maxWidth={500}
            alt={displayMedia?.name}
            class="w-full h-full object-cover"
          />
        {:else}
          <div class="w-full h-full bg-[var(--color-surface)] flex items-center justify-center">
            <svg class="w-32 h-32 text-gray-600" 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>
    </div>

    <!-- Info & Controls -->
    <div class="p-6 space-y-6 flex-shrink-0">
      <!-- Title & Artist -->
      <div class="text-center">
        <h1 class="text-2xl font-bold text-white truncate">{truncateMiddle(displayMedia?.name, 48)}</h1>
        <div class="text-lg text-gray-400 mt-1 flex items-center justify-center gap-1 flex-wrap">
          {#if displayMedia?.artistItems?.length}
            {#each displayMedia?.artistItems as artist, i}
              <button
                onclick={() => navigateToArtist(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>

      <!-- Progress bar -->
      <div class="space-y-2">
        <input
          type="range"
          min="0"
          max={displayDuration}
          value={displayPosition}
          oninput={handleSeekInput}
          onmousedown={handleSeekStart}
          ontouchstart={handleSeekStart}
          onmouseup={handleSeekEnd}
          ontouchend={handleSeekEnd}
          class="w-full h-1 accent-[var(--color-jellyfin)] cursor-pointer"
        />
        <div class="flex justify-between text-xs text-gray-400">
          <span>{formatTime(displayPosition)}</span>
          <span>{formatTime(displayDuration)}</span>
        </div>
      </div>

      <!-- Controls -->
      <div class="flex justify-center">
        <Controls
          isPlaying={displayIsPlaying}
          {hasPrevious}
          {hasNext}
          {shuffle}
          {repeat}
          onPlayPause={handlePlayPause}
          onPrevious={handlePrevious}
          onNext={handleNext}
          onToggleShuffle={handleToggleShuffle}
          onCycleRepeat={handleCycleRepeat}
          onSleepTimerClick={() => (showSleepTimerModal = true)}
        />
      </div>
    </div>
    </div> <!-- Close content overlay -->
  </div>
{/if}

<SleepTimerModal
  isOpen={showSleepTimerModal}
  onClose={() => (showSleepTimerModal = false)}
/>

<!-- Queue Panel (slide up from bottom) -->
{#if showQueue}
  <div class="fixed inset-0 z-[60]">
    <!-- Backdrop -->
    <button
      type="button"
      class="absolute inset-0 bg-black/50"
      onclick={() => (showQueue = false)}
      aria-label="Close queue"
    ></button>

    <!-- Queue Panel. Slides up from the very bottom, so it owns the bottom
         inset — its last row would otherwise sit under the gesture bar. -->
    <div
      class="absolute bottom-0 left-0 right-0 max-h-[70vh] animate-slide-up"
      style:padding-bottom="var(--safe-bottom)"
    >
      <Queue
        items={$queueItems}
        currentIndex={$currentQueueIndex}
        onItemClick={handleQueueItemClick}
        onClose={() => (showQueue = false)}
      />
    </div>
  </div>
{/if}

<style>
  @keyframes slide-up {
    from {
      transform: translateY(100%);
    }
    to {
      transform: translateY(0);
    }
  }

  .animate-slide-up {
    animation: slide-up 0.2s ease-out;
  }
</style>
