"use client";

import { useEffect, useRef, useState } from "react";
import { addToCart } from "../lib/cart";
import { useCartFly } from "./CartFly";

const FEEDBACK_MS = 2000;

/**
 * Shared by /todo-cards's Hero + pricing panel and Home's product
 * spotlight. Used to navigate straight to /cart on click; now stays on the
 * page instead (matching AddToCartInlineButton's behavior everywhere else)
 * — adds to the cart, plays the fly-to-navbar-icon animation, and shows a
 * brief inline success state instead of leaving the page.
 */
export function AddToCartButton({
  label,
  className,
  productId = "todo-karten",
  outOfStock = false,
  variants = [],
}: {
  label: string;
  className?: string;
  /** Defaults to "todo-karten" for /todo-cards' own hardcoded usage — Home's
   * ProductSpotlight passes the actual CMS-selected spotlight product's id
   * explicitly, since that can now be a different product. */
  productId?: string;
  /** Product-level — only meaningful when `variants` is empty, same split as
   * AddToCartInlineButton. */
  outOfStock?: boolean;
  /** Optional — same shape/semantics as AddToCartInlineButton's own
   * `variants` prop; all three callers already fetch the full product
   * server-side, so this is just threaded straight through. */
  variants?: { name: string; priceOverride: number | null; outOfStock: boolean }[];
}) {
  const [added, setAdded] = useState(false);
  const [selectedVariant, setSelectedVariant] = useState(variants.find((v) => !v.outOfStock)?.name ?? variants[0]?.name);
  const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
  const buttonRef = useRef<HTMLButtonElement>(null);
  const { fly } = useCartFly();

  useEffect(() => () => clearTimeout(timeoutRef.current), []);

  const currentlyOutOfStock = variants.length > 0 ? (variants.find((v) => v.name === selectedVariant)?.outOfStock ?? false) : outOfStock;

  function handleClick() {
    if (currentlyOutOfStock) return;
    addToCart(productId, 1, selectedVariant);
    if (buttonRef.current) fly(buttonRef.current);
    setAdded(true);
    clearTimeout(timeoutRef.current);
    timeoutRef.current = setTimeout(() => setAdded(false), FEEDBACK_MS);
  }

  const base =
    className ??
    "inline-flex items-center justify-center px-6 py-[0.8125rem] rounded-sm bg-brand hover:bg-brand-hover active:scale-[0.97] transition-all font-bold text-body text-text-primary whitespace-nowrap focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base";
  // Trailing `!` — Tailwind v4's important-modifier syntax moved from a
  // leading `!` to this trailing suffix — forces the success color to win
  // over whatever bg-brand/text-text-primary each caller already baked
  // into `base`, since appending on top can't rely on CSS source order
  // the way branching a whole className (AddToCartInlineButton's
  // approach) can when the base itself varies per caller.
  // Pale success-subtle fill + success text + a success-colored border, not
  // a solid success-green fill with white text — same restrained pairing
  // AddToCartInlineButton already uses (border-success + bg-success-subtle),
  // a solid bright-green button read as too loud here. `border` (width) is
  // added here too since `base` has none by default, unlike
  // AddToCartInlineButton's own base which already carries a plain border.
  const stateClasses = currentlyOutOfStock
    ? "opacity-60 cursor-not-allowed"
    : added
      ? "border border-success! bg-success-subtle! hover:bg-success-subtle! text-success!"
      : "";
  const displayLabel = currentlyOutOfStock ? "Ausverkauft" : label;

  return (
    <div className="flex flex-col gap-2">
      {variants.length > 0 && (
        <select
          value={selectedVariant}
          onChange={(e) => setSelectedVariant(e.target.value)}
          className="w-full rounded-sm border border-border px-3 py-2 text-body-sm text-text-primary bg-bg-base focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand"
          aria-label="Variante auswählen"
        >
          {variants.map((v) => (
            <option key={v.name} value={v.name}>
              {v.name}
              {v.outOfStock ? " (ausverkauft)" : ""}
            </option>
          ))}
        </select>
      )}
      <button
        ref={buttonRef}
        type="button"
        onClick={handleClick}
        disabled={currentlyOutOfStock}
        className={`${base} ${stateClasses}`}
      >
        {/* CSS-grid text-stack, not just swapping the button's text node
            directly — this button is inline-flex/content-sized (no w-full),
            so "Hinzugefügt ✓" being shorter than most labels made the whole
            button visibly shrink while showing the success state. Stacking
            both possible texts in the same grid cell (both invisible ones
            still contribute to sizing) reserves width for whichever is
            wider, so the button's box never changes size either way. Now
            also reserves space for "Ausverkauft" — the widest of the three
            wins regardless of which is showing. */}
        <span className="relative grid">
          <span className="invisible [grid-area:1/1]" aria-hidden="true">
            {label}
          </span>
          <span className="invisible [grid-area:1/1]" aria-hidden="true">
            Hinzugefügt ✓
          </span>
          <span className="invisible [grid-area:1/1]" aria-hidden="true">
            Ausverkauft
          </span>
          <span className="[grid-area:1/1]">{added ? "Hinzugefügt ✓" : displayLabel}</span>
        </span>
      </button>
    </div>
  );
}
