<script lang="ts">
  import { FALLBACK_COVER } from '$lib/media/covers';
  import { Disc3 } from 'lucide-svelte';

  // Shared cover-artwork renderer. The web counterpart of Android's
  // CoverTile/ServerImage: one place that owns the loading placeholder and
  // the error fallback so no card sits blank while art loads or 404s (the
  // "You might like" row surfaces unplayed items whose art is often not yet
  // backfilled). Replaces the three hand-rolled <img> tags that previously
  // disagreed on fallback handling.
  let {
    src,
    alt = '',
    shape = 'square',
    fallback = 'image',
    class: klass = ''
  }: {
    src: string | undefined;
    alt?: string;
    // 'round' clips to a circle (artist avatars); 'square' leaves clipping
    // to the parent so existing rounded-md / rounded corners still apply.
    shape?: 'square' | 'round';
    // 'artist' degrades to a Disc3 icon; 'image' to the static placeholder
    // cover. A null/empty src is treated the same as a failed load.
    fallback?: 'image' | 'artist';
    class?: string;
  } = $props();

  // Per-image lifecycle. Reset when src changes so a reused card (virtualized
  // list, client-side nav) never keeps a stale 'loaded'/'failed'.
  let loaded = $state(false);
  let failed = $state(false);
  $effect(() => {
    void src;
    loaded = false;
    failed = false;
  });

  const useIcon = $derived(fallback === 'artist' && (failed || !src));
  // On failure for the image fallback, swap to the static placeholder asset.
  // src doesn't change on the second error, so there's no reload loop.
  const imgSrc = $derived(failed ? FALLBACK_COVER : src);
</script>

<div
  class="relative h-full w-full overflow-hidden bg-surface-hover {shape === 'round'
    ? 'rounded-full'
    : ''}"
>
  {#if useIcon}
    <div class="flex h-full w-full items-center justify-center">
      <Disc3 strokeWidth={1} class="h-4/5 w-4/5 text-text-muted" />
    </div>
  {:else if imgSrc}
    <img
      src={imgSrc}
      {alt}
      class="h-full w-full object-cover transition-opacity duration-200 {loaded
        ? 'opacity-100'
        : 'opacity-0'} {klass}"
      loading="lazy"
      onload={() => (loaded = true)}
      onerror={() => (failed = true)}
    />
  {/if}
</div>
