<script lang="ts">
  import { page } from '$app/state';
  import { pageTitle } from '$lib/branding';
  import { ChevronLeft } from 'lucide-svelte';
  import {
    createAlbumYearsQuery,
    listAlbumsByYear,
    BROWSE_PAGE_SIZE,
    type YearCount
  } from '$lib/api/browse';
  import AlbumCard from '$lib/components/AlbumCard.svelte';
  import ApiErrorBanner from '$lib/components/ApiErrorBanner.svelte';
  import EmptyState from '$lib/components/EmptyState.svelte';
  import type { AlbumRef } from '$lib/api/types';

  const indexStore = createAlbumYearsQuery();
  const index = $derived($indexStore);
  const years = $derived(index.data ?? []);

  const selected = $derived.by(() => {
    const raw = page.url.searchParams.get('y');
    if (!raw) return null;
    const n = Number.parseInt(raw, 10);
    return Number.isFinite(n) ? n : null;
  });

  // Grouped by decade so the index stays scannable — a flat list of every year
  // in a decades-deep library is a wall of numbers, and the decade is usually
  // how someone actually thinks about it.
  const decades = $derived.by(() => {
    const buckets = new Map<number, YearCount[]>();
    for (const y of years) {
      const decade = Math.floor(y.year / 10) * 10;
      const list = buckets.get(decade);
      if (list) list.push(y);
      else buckets.set(decade, [y]);
    }
    return [...buckets.entries()]
      .sort((a, b) => b[0] - a[0])
      .map(([decade, entries]) => ({
        decade,
        entries: entries.slice().sort((a, b) => b.year - a.year),
        albumCount: entries.reduce((sum, e) => sum + e.album_count, 0)
      }));
  });

  let albums = $state<AlbumRef[]>([]);
  let total = $state(0);
  let loading = $state(false);
  let failed = $state(false);

  // Plain `let`, not $state — see the note in the genres page: as reactive
  // state, reading it in the fetch path would make the effect below depend on
  // its own writes. It exists so a late response for a previously selected
  // year is discarded instead of painted over the current one.
  let requestToken = 0;

  $effect(() => {
    const y = selected; // only tracked read
    void reload(y);
  });

  async function reload(year: number | null) {
    requestToken += 1;
    albums = [];
    total = 0;
    failed = false;
    if (year === null) return;
    await fetchPage(year, 0, requestToken);
  }

  async function fetchPage(year: number, offset: number, token: number) {
    loading = true;
    try {
      const p = await listAlbumsByYear(year, BROWSE_PAGE_SIZE, offset);
      if (token !== requestToken) return;
      albums = offset === 0 ? p.items : [...albums, ...p.items];
      total = p.total;
    } catch {
      if (token === requestToken) failed = true;
    } finally {
      if (token === requestToken) loading = false;
    }
  }

  function loadMore() {
    if (selected !== null) void fetchPage(selected, albums.length, requestToken);
  }
</script>

<svelte:head>
  <title>{pageTitle(selected !== null ? `Library · ${selected}` : 'Library · Years')}</title>
</svelte:head>

{#if selected !== null}
  <div class="space-y-4">
    <header class="space-y-2">
      <a
        href="/library/years"
        class="inline-flex items-center gap-1 text-sm text-accent hover:underline"
      >
        <ChevronLeft size={14} aria-hidden="true" />
        All years
      </a>
      <div>
        <h1 class="font-display text-2xl font-medium text-text-primary">{selected}</h1>
        {#if !loading || albums.length > 0}
          <p class="text-sm text-text-secondary">
            {total} {total === 1 ? 'album' : 'albums'}
          </p>
        {/if}
      </div>
    </header>

    {#if failed}
      <p class="text-sm text-action-destructive">
        Couldn't load albums for {selected}.
        <button
          type="button"
          class="underline hover:no-underline"
          onclick={() => reload(selected)}>Try again</button
        >
      </p>
    {:else if loading && albums.length === 0}
      <p class="text-text-secondary">Loading…</p>
    {:else if albums.length === 0}
      <EmptyState
        title="No albums from {selected}"
        hint="The library may have been rescanned since this list was built."
      />
    {:else}
      <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 albums as album (album.id)}
          <AlbumCard {album} />
        {/each}
      </div>
      {#if albums.length < total}
        <div class="flex justify-center py-2">
          <button
            type="button"
            class="rounded-md border border-border px-4 py-2 text-sm hover:bg-surface-hover
                   focus-visible:ring-2 focus-visible:ring-accent disabled:opacity-50"
            disabled={loading}
            onclick={loadMore}
          >
            {loading ? 'Loading…' : `Load more (${total - albums.length} left)`}
          </button>
        </div>
      {:else}
        <p class="py-2 text-center text-sm text-text-secondary">End of year</p>
      {/if}
    {/if}
  </div>
{:else}
  <div class="space-y-4">
    <header>
      <h1 class="font-display text-2xl font-medium text-text-primary">Years</h1>
      {#if !index.isPending && !index.isError}
        <p class="text-sm text-text-secondary">
          {years.length} {years.length === 1 ? 'year' : 'years'} with dated releases
        </p>
      {/if}
    </header>

    {#if index.isError}
      <ApiErrorBanner error={index.error} onRetry={index.refetch} />
    {:else if index.isPending}
      <p class="text-text-secondary">Loading…</p>
    {:else if years.length === 0}
      <!-- Albums with no release date are absent by design rather than bucketed
           under a fake year, so an untagged library lands here legitimately. -->
      <EmptyState
        title="No release years found"
        hint="Years come from the release date on your albums. Albums without one don't appear on this axis."
      />
    {:else}
      <ul class="space-y-4">
        {#each decades as d (d.decade)}
          <li>
            <h2 class="mb-2 text-sm font-medium text-text-secondary">
              {d.decade}s
              <span class="font-normal">· {d.albumCount}</span>
            </h2>
            <ul class="flex flex-wrap gap-2">
              {#each d.entries as y (y.year)}
                <li>
                  <a
                    href={`/library/years?y=${y.year}`}
                    class="inline-flex items-baseline gap-1.5 rounded-md border border-border
                           bg-surface px-3 py-1.5 hover:bg-surface-hover
                           focus-visible:ring-2 focus-visible:ring-accent"
                  >
                    <span class="text-text-primary">{y.year}</span>
                    <span class="text-xs text-text-secondary">{y.album_count}</span>
                  </a>
                </li>
              {/each}
            </ul>
          </li>
        {/each}
      </ul>
    {/if}
  </div>
{/if}
