<script lang="ts">
  import { Play, Shuffle } from 'lucide-svelte';
  import { page } from '$app/state';
  import { createAlbumQuery } from '$lib/api/queries';
  import { qk } from '$lib/api/queries';
  import { pageTitle } from '$lib/branding';
  import TrackRow from '$lib/components/TrackRow.svelte';
  import LibrarySkeleton from '$lib/components/LibrarySkeleton.svelte';
  import ApiErrorBanner from '$lib/components/ApiErrorBanner.svelte';
  import LikeButton from '$lib/components/LikeButton.svelte';
  import { useDelayed } from '$lib/utils/useDelayed.svelte';
  import { formatDuration } from '$lib/media/duration';
  import { FALLBACK_COVER } from '$lib/media/covers';
  import type { ApiError } from '$lib/api/client';
  import { playQueue } from '$lib/player/store.svelte';
  import { user } from '$lib/auth/store.svelte';
  import { refetchAlbumCover } from '$lib/api/admin';
  import { errCode } from '$lib/api/errors';
  import { useQueryClient } from '@tanstack/svelte-query';

  const id = $derived(page.params.id ?? '');
  const queryStore = $derived(createAlbumQuery(id));
  const query = $derived($queryStore);
  const showSkeleton = useDelayed(() => query.isPending);

  const notFound = $derived(
    query.isError && (query.error as unknown as ApiError | undefined)?.code === 'not_found'
  );

  function onCoverError(e: Event) {
    (e.currentTarget as HTMLImageElement).src = FALLBACK_COVER;
  }

  let isStartingPlay = $state(false);

  function shuffleArr<T>(items: T[]): T[] {
    const arr = items.slice();
    for (let i = arr.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [arr[i], arr[j]] = [arr[j], arr[i]];
    }
    return arr;
  }

  function onPlay() {
    const data = query.data;
    if (isStartingPlay || !data || data.tracks.length === 0) return;
    isStartingPlay = true;
    try {
      playQueue(data.tracks, 0);
    } finally {
      isStartingPlay = false;
    }
  }

  function onShuffle() {
    const data = query.data;
    if (isStartingPlay || !data || data.tracks.length === 0) return;
    isStartingPlay = true;
    try {
      playQueue(shuffleArr(data.tracks), 0);
    } finally {
      isStartingPlay = false;
    }
  }

  const queryClient = useQueryClient();
  let refetching = $state(false);
  let refetchError = $state<string | null>(null);

  const isAdmin = $derived(user.value?.is_admin === true);

  async function onRefetchCover() {
    const data = query.data;
    if (!data || refetching) return;
    refetching = true;
    refetchError = null;
    try {
      await refetchAlbumCover(data.id);
      await queryClient.invalidateQueries({ queryKey: qk.album(data.id) });
    } catch (e) {
      const code = errCode(e);
      refetchError = code === 'unknown' ? 'refetch failed' : code;
    } finally {
      refetching = false;
    }
  }
</script>

<svelte:head>
  <title>{pageTitle(query.data?.title ? `Album · ${query.data.title}` : 'Album')}</title>
</svelte:head>

<div class="space-y-6">
  {#if notFound}
    <div role="alert" class="rounded border border-border bg-surface p-4">
      <p>Album not found.</p>
      <a href="/" class="mt-2 inline-block text-sm text-accent">Back to Library</a>
    </div>
  {:else if query.isError}
    <ApiErrorBanner error={query.error} onRetry={query.refetch} />
  {:else if showSkeleton.value && !query.data}
    <LibrarySkeleton variant="album" />
  {:else if query.data}
    {@const album = query.data}
    <a
      href={`/artists/${album.artist_id}`}
      class="text-sm text-text-secondary hover:text-text-primary"
    >
      ← {album.artist_name}
    </a>

    <header class="flex flex-col gap-4 md:flex-row md:items-end">
      <img
        src={album.cover_url}
        alt={album.title}
        class="h-60 w-60 rounded object-cover"
        loading="lazy"
        onerror={onCoverError}
      />
      <div class="flex-1 space-y-2">
        <div class="flex items-center gap-3">
          <h1 class="font-display text-2xl font-medium text-text-primary">{album.title}</h1>
          <LikeButton entityType="album" entityId={album.id} size="lg" />
        </div>
        <p>
          <a href={`/artists/${album.artist_id}`} class="hover:underline">{album.artist_name}</a>
        </p>
        <!-- Year and genre are quick-jumps into the browse axes (#367): from
             an album you like, one click to everything else from that year or
             in that genre. -->
        {#if album.year}
          <p class="text-sm">
            <a href={`/library/years?y=${album.year}`} class="text-accent hover:underline">
              {album.year}
            </a>
          </p>
        {/if}
        {#if album.genres?.length}
          <ul class="flex flex-wrap gap-1.5">
            {#each album.genres as genre (genre)}
              <li>
                <a
                  href={`/library/genres?g=${encodeURIComponent(genre)}`}
                  class="inline-block rounded-full border border-border px-2.5 py-0.5 text-xs
                         text-text-secondary hover:bg-surface-hover hover:text-text-primary
                         focus-visible:ring-2 focus-visible:ring-accent"
                >
                  {genre}
                </a>
              </li>
            {/each}
          </ul>
        {/if}
        <p class="text-sm text-text-secondary">
          {album.track_count} {album.track_count === 1 ? 'track' : 'tracks'}
          · {formatDuration(album.duration_sec)}
        </p>
        <div class="flex items-center gap-2 pt-2">
          <button
            type="button"
            aria-label={`Play ${album.title}`}
            onclick={onPlay}
            disabled={isStartingPlay || album.tracks.length === 0}
            class="flex items-center gap-2 rounded-md bg-accent px-4 py-2 text-sm font-medium text-text-primary hover:opacity-90 focus-visible:ring-2 focus-visible:ring-accent disabled:opacity-50"
          >
            <Play size={16} strokeWidth={1.5} fill="currentColor" />
            Play
          </button>
          <button
            type="button"
            aria-label={`Shuffle ${album.title}`}
            onclick={onShuffle}
            disabled={isStartingPlay || album.tracks.length === 0}
            class="flex items-center gap-2 rounded-md border border-border bg-surface px-4 py-2 text-sm font-medium text-text-primary hover:border-accent focus-visible:ring-2 focus-visible:ring-accent disabled:opacity-50"
          >
            <Shuffle size={16} strokeWidth={1.5} />
            Shuffle
          </button>
          {#if isAdmin}
            <button
              type="button"
              onclick={onRefetchCover}
              disabled={refetching}
              aria-label={`Refetch cover for ${album.title}`}
              title={album.cover_art_source === 'none' ? 'No cover found previously — try again' : 'Refetch from MusicBrainz'}
              class="flex items-center gap-2 rounded-md border border-border bg-surface px-3 py-2 text-sm font-medium text-text-secondary hover:border-accent disabled:opacity-50"
            >
              Refetch cover
            </button>
          {/if}
          {#if refetchError}
            <span class="text-sm text-oxblood">{refetchError}</span>
          {/if}
        </div>
      </div>
    </header>

    {#if album.tracks.length === 0}
      <p class="text-text-secondary">This album has no tracks.</p>
    {:else}
      <div class="overflow-hidden rounded border border-border">
        {#each album.tracks as track, i (track.id)}
          <TrackRow tracks={album.tracks} index={i} />
        {/each}
      </div>
    {/if}
  {/if}
</div>
