<!--
  Downloaded browse surface: the library, filtered to what's on the device.

  Reuses the library's own grid/cards. The top level lists only libraries with
  downloaded content; drilling into a library shows its downloaded items in the
  same grid used online. Clicking a leaf/detail item navigates to the shared
  `/library/[id]` detail page, where Play uses the local file. Per-item and
  device disk usage ride along via the size labels and the top bar.

  TRACES: UR-055, UR-056 | DR-081, DR-082, DR-083, DR-085
-->
<script lang="ts">
  import { onMount } from "svelte";
  import { goto } from "$app/navigation";
  import type { Library, MediaItem } from "$lib/api/types";
  import LibraryGrid from "$lib/components/library/LibraryGrid.svelte";
  import { seasonRedirectTarget, episodeFocusHref } from "$lib/components/library/seriesNavigation";
  import { formatBytes } from "$lib/utils/formatBytes";
  import {
    downloadedCatalog,
    downloadedLibraries,
    downloadedDeviceTotal,
    downloadedItemCount,
  } from "$lib/services/downloadedCatalog";

  // Drill state: null = library list; otherwise the library we're inside.
  let currentLibrary = $state<Library | null>(null);
  let items = $state<MediaItem[]>([]);
  let loadingItems = $state(false);
  let loadError = $state<string | null>(null);

  const loading = $derived($downloadedCatalog.loading);

  onMount(() => {
    void downloadedCatalog.refresh();
  });

  async function openLibrary(library: Library) {
    currentLibrary = library;
    loadingItems = true;
    loadError = null;
    try {
      items = await downloadedCatalog.loadItems(library.id);
    } catch (err) {
      loadError = err instanceof Error ? err.message : "Failed to load downloads";
      items = [];
    } finally {
      loadingItems = false;
    }
  }

  function backToLibraries() {
    currentLibrary = null;
    items = [];
    loadError = null;
  }

  // Containers (album/season/series/box set) drill via the shared detail page,
  // which is offline-aware; leaves open their detail/play surface there too.
  function onItemClick(item: MediaItem | Library) {
    if ("collectionType" in item) {
      // A Library (top level) — drill in place.
      void openLibrary(item as Library);
      return;
    }
    // Seasons and episodes resolve inside their series (DR-103): a season has
    // no page of its own and an episode is never browsed bare.
    if (item.kind === "season") {
      goto(seasonRedirectTarget(item) ?? `/library/${item.id}`);
      return;
    }
    if (item.kind === "episode") {
      goto(episodeFocusHref(item));
      return;
    }
    goto(`/library/${item.id}`);
  }

  // A size label for a card, if we have a byte figure for it.
  function sizeLabelFor(item: MediaItem | Library): string | undefined {
    const bytes = $downloadedCatalog.sizes[item.id];
    return bytes && bytes > 0 ? formatBytes(bytes) : undefined;
  }

  // Remove a downloaded item/container, stating the reclaim amount first.
  async function removeItem(item: MediaItem | Library) {
    if (!("type" in item)) return;
    const bytes = $downloadedCatalog.sizes[item.id] ?? 0;
    const freed = bytes > 0 ? ` This frees ${formatBytes(bytes)}.` : "";
    if (!confirm(`Remove “${item.name}” from this device?${freed}`)) return;
    try {
      await downloadedCatalog.remove(item.id);
      // Reload the current library so removed items (and now-empty containers)
      // drop out of the browse.
      if (currentLibrary) {
        items = await downloadedCatalog.loadItems(currentLibrary.id);
      }
    } catch (err) {
      loadError = err instanceof Error ? err.message : "Failed to remove download";
    }
  }

  // Full vs partial container badge (leaves get no container badge here).
  function downloadedBadgeFor(item: MediaItem | Library): "full" | "partial" | undefined {
    if (!("type" in item)) return undefined;
    const isContainer = ["MusicAlbum", "Series", "Season", "BoxSet"].includes(item.type);
    if (!isContainer) return undefined;
    return $downloadedCatalog.partialContainers[item.id] ? "partial" : "full";
  }
</script>

<div class="space-y-5">
  <!-- Device total: the headline figure, reconciles with the listed sum. -->
  <div
    class="flex items-center justify-between rounded-lg border border-gray-700 bg-[var(--color-surface)] px-4 py-3"
  >
    <div class="flex items-center gap-3">
      <svg class="h-5 w-5 text-[var(--color-jellyfin)]" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.8">
        <path stroke-linecap="round" stroke-linejoin="round" d="M4 7v10a2 2 0 002 2h12a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H6a2 2 0 00-2 2z" />
      </svg>
      <p class="text-sm text-gray-200">
        <span class="font-semibold text-white">{formatBytes($downloadedDeviceTotal)}</span>
        on device
        <span class="text-gray-500">·</span>
        {$downloadedItemCount}
        {$downloadedItemCount === 1 ? "item" : "items"}
      </p>
    </div>
  </div>

  {#if currentLibrary}
    <!-- Inside a library: breadcrumb back to the library list. -->
    <div class="flex items-center gap-2 text-sm">
      <button
        onclick={backToLibraries}
        class="text-gray-400 hover:text-white transition-colors"
      >
        Downloaded
      </button>
      <span class="text-gray-600">/</span>
      <span class="text-white font-medium">{currentLibrary.name}</span>
    </div>

    {#if loadError}
      <p class="text-sm text-red-400">{loadError}</p>
    {/if}

    <LibraryGrid
      items={items.map((i) => i)}
      loading={loadingItems}
      showViewToggle={true}
      musicContent={currentLibrary.collectionType === "music"}
      {sizeLabelFor}
      {downloadedBadgeFor}
      onItemRemove={removeItem}
      {onItemClick}
    />
    {#if !loadingItems && items.length === 0 && !loadError}
      <p class="text-center py-8 text-gray-500 text-sm">Nothing downloaded in this library.</p>
    {/if}
  {:else if loading}
    <p class="text-center py-12 text-gray-400">Loading your downloads…</p>
  {:else if $downloadedLibraries.length === 0}
    <!-- Empty Downloaded state: authoritative "nothing downloaded", not a server miss. -->
    <div class="rounded-lg border border-gray-700 bg-[var(--color-surface)] p-10 text-center">
      <svg class="mx-auto mb-4 h-14 w-14 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.4">
        <path stroke-linecap="round" stroke-linejoin="round" d="M12 4v12m0 0l-4-4m4 4l4-4m-9 7h10" />
      </svg>
      <p class="text-lg font-medium text-gray-300">Nothing downloaded yet</p>
      <p class="mt-2 text-sm text-gray-500">
        Browse your library and tap download to save media for offline.
      </p>
      <button
        onclick={() => goto("/library")}
        class="mt-5 rounded-lg bg-[var(--color-jellyfin)] px-4 py-2 text-sm font-medium text-white hover:opacity-90 transition"
      >
        Go to library
      </button>
    </div>
  {:else}
    <!-- Library list — only libraries with downloaded content. -->
    <div class="grid grid-cols-2 gap-4 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6">
      {#each $downloadedLibraries as lib (lib.id)}
        <button
          onclick={() => openLibrary(lib)}
          class="group/card flex flex-col text-left transition-transform duration-200 hover:scale-105"
        >
          <div class="relative aspect-video w-full overflow-hidden rounded-lg bg-[var(--color-surface)] shadow-md flex items-center justify-center">
            <svg class="h-10 w-10 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.4">
              <path stroke-linecap="round" stroke-linejoin="round" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-7l-2-2H5a2 2 0 00-2 2z" />
            </svg>
          </div>
          <p class="mt-2 truncate text-sm font-medium text-white group-hover/card:text-[var(--color-jellyfin)] transition-colors">
            {lib.name}
          </p>
        </button>
      {/each}
    </div>
  {/if}
</div>
