<!-- TRACES: UR-017, UR-068 | DR-021, DR-119 -->
<script lang="ts">
  import { toggleFavorite } from "$lib/services/favorites";
  import { haptics } from "$lib/utils/haptics";
  import { toast } from "$lib/stores/toast";
  import { favoriteOverrides } from "$lib/stores/favorites";
  import { createLogger } from "$lib/utils/logger";

  const log = createLogger("FavoriteButton");

  interface Props {
    itemId: string;
    isFavorite?: boolean;
    size?: "sm" | "md" | "lg";
    className?: string;
    /**
     * "button" (default) is the standalone control used in header/hero rows;
     * "overlay" is the artwork corner variant used on cards, which needs its
     * own scrim to stay legible over any poster.
     */
    variant?: "button" | "overlay";
    /** Stop the click reaching a parent card/row that would navigate or play. */
    stopPropagation?: boolean;
  }

  let {
    itemId,
    isFavorite = $bindable(false),
    size = "md",
    className = "",
    variant = "button",
    stopPropagation = false,
  }: Props = $props();

  let isLoading = $state(false);
  let isAnimating = $state(false);

  // A toggle from any other surface (or the backend's `favorites-changed`
  // refresh) wins over the prop we were mounted with — otherwise a heart tapped
  // on a card would still read empty on the detail page behind it.
  $effect(() => {
    const override = $favoriteOverrides.get(itemId);
    if (override !== undefined && override !== isFavorite) {
      isFavorite = override;
    }
  });

  const sizeClasses = {
    sm: "w-4 h-4",
    md: "w-5 h-5",
    lg: "w-6 h-6",
  };

  async function handleToggle(event: MouseEvent) {
    // On a card the heart sits inside a clickable tile; without this, hearting
    // an item would also open (or play) it.
    if (stopPropagation) {
      event.stopPropagation();
      event.preventDefault();
    }
    if (isLoading) return;

    isLoading = true;
    isAnimating = true;

    try {
      const newValue = await toggleFavorite(itemId, isFavorite);
      isFavorite = newValue;

      // Haptic feedback
      if (newValue) {
        haptics.success();
        toast.show("Added to favorites", "success", 1500);
      } else {
        haptics.tap();
        toast.show("Removed from favorites", "info", 1500);
      }

      // Reset animation after it completes
      setTimeout(() => {
        isAnimating = false;
      }, 600);
    } catch (error) {
      log.error("Failed to toggle favorite:", error);
      toast.show("Failed to update favorites", "error");
      isAnimating = false;
    } finally {
      isLoading = false;
    }
  }

  // Compute button classes
  const buttonClass = $derived.by(() => {
    const baseClasses =
      variant === "overlay"
        ? "p-1.5 rounded-full transition-all bg-black/50 backdrop-blur-sm hover:bg-black/70"
        : "p-2 rounded-full transition-all";
    const colorClasses = isFavorite
      ? "text-red-500 hover:text-red-400"
      : variant === "overlay"
        ? "text-white/80 hover:text-white"
        : "text-gray-400 hover:text-white";
    const loadingClasses = isLoading ? "opacity-50 cursor-wait" : "";
    return `${baseClasses} ${colorClasses} ${loadingClasses} ${className}`.trim();
  });

  // Compute SVG classes
  const svgClass = $derived.by(() => {
    const sizeClass = sizeClasses[size];
    return sizeClass;
  });

  // Inline animation styles
  const buttonStyle = $derived(isAnimating ? "animation: bounce-once 0.6s ease-in-out;" : "");
  const svgStyle = $derived(
    isAnimating && isFavorite ? "animation: heart-pop 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);" : "",
  );
</script>

<button
  onclick={handleToggle}
  disabled={isLoading}
  class={buttonClass}
  style={buttonStyle}
  title={isFavorite ? "Remove from favorites" : "Add to favorites"}
  aria-label={isFavorite ? "Remove from favorites" : "Add to favorites"}
>
  {#if isFavorite}
    <!-- Filled heart with scale animation -->
    <svg class={svgClass} style={svgStyle} fill="currentColor" viewBox="0 0 24 24">
      <path
        d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"
      />
    </svg>
  {:else}
    <!-- Outline heart -->
    <svg
      class={sizeClasses[size]}
      fill="none"
      stroke="currentColor"
      viewBox="0 0 24 24"
      stroke-width="2"
    >
      <path
        stroke-linecap="round"
        stroke-linejoin="round"
        d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"
      />
    </svg>
  {/if}
</button>

<style>
  @keyframes heart-pop {
    0% {
      transform: scale(1);
    }
    50% {
      transform: scale(1.3);
    }
    100% {
      transform: scale(1);
    }
  }

  @keyframes bounce-once {
    0%,
    100% {
      transform: translateY(0);
    }
    25% {
      transform: translateY(-8px);
    }
    50% {
      transform: translateY(0);
    }
    75% {
      transform: translateY(-4px);
    }
  }
</style>
