import Link from "next/link";
import Image from "next/image";
import type { ReactNode } from "react";
import { formatPrice, discountPercent } from "../lib/format";
import { effectiveTaxRate } from "../lib/cartTotals";
import { AddToCartInlineButton } from "./AddToCartInlineButton";
import { WishlistButton } from "./WishlistButton";
import type { Product } from "../lib/payload";

// Single shared card markup for every product grid (ProductGrid,
// RelatedProducts, MerklisteGrid) — these three used to each duplicate
// this JSX independently and had drifted (different image aspect ratios,
// a "Mehr erfahren" link present on some but not others, purchased/
// out-of-stock badges only on some). The title itself is now the card's
// only link (product.href, when set) — no separate "Mehr erfahren" CTA
// line, which is also what makes the card more compact than before.
// No "use client" — plain enough (no hooks/browser APIs of its own) to
// render from both ProductGrid's Server Component and RelatedProducts'/
// MerklisteGrid's Client Components.
export function ProductCard({
  product,
  defaultTaxRate,
  kleinunternehmer,
  wishlistEnabled,
  wishlistRevealOnHover = false,
  topLeftBadge,
  belowPrice,
  className = "",
}: {
  product: Product;
  defaultTaxRate: number;
  kleinunternehmer: boolean;
  wishlistEnabled: boolean;
  /** See WishlistButton's own doc: true for any grid where an unprompted
   * heart on every card would read as noise (ProductGrid, RelatedProducts);
   * false (default) for /konto/merkliste, where every card is already
   * wishlisted. */
  wishlistRevealOnHover?: boolean;
  /** Overrides the default Ausverkauft/discount pill — used by
   * MerklisteGrid for its "Gekauft am ..." badge. Pass `null` to render
   * no badge at all. */
  topLeftBadge?: ReactNode;
  /** Rendered directly under the price — e.g. ProductGrid's delivery-time
   * line. Omitted entirely by grids that don't have anything to say there
   * (RelatedProducts, MerklisteGrid), rather than every card carrying a
   * fixed slot for content only one of the three actually has. */
  belowPrice?: ReactNode;
  className?: string;
}) {
  const discount = discountPercent(product.price, product.compareAtPrice);
  const taxRate = effectiveTaxRate(product, defaultTaxRate);
  const fullyOutOfStock = product.variants.length > 0 ? product.variants.every((v) => v.outOfStock) : product.outOfStock;
  const anyLowStock = product.variants.length > 0 ? product.variants.some((v) => v.lowStock) : product.lowStock;

  return (
    <div
      className={`group bg-bg-base border border-border rounded-md overflow-hidden flex flex-col h-full transition-transform duration-300 hover:-translate-y-1 ${className}`}
    >
      <div className="relative w-full aspect-[276/210] overflow-hidden">
        {/* Link wraps only the image, not the whole header — WishlistButton
            below is its own interactive element and sits as a sibling, not
            nested inside this Link (nested interactive elements are both
            invalid HTML and would fire navigation on a wishlist click). */}
        {product.href ? (
          <Link href={product.href} aria-label={product.name} className="absolute inset-0 z-0">
            <Image
              src={product.image}
              alt={product.name}
              fill
              sizes="(min-width: 1024px) 30vw, (min-width: 640px) 50vw, 100vw"
              className={`object-cover transition-transform duration-500 group-hover:scale-105 ${fullyOutOfStock ? "opacity-60" : ""}`}
            />
          </Link>
        ) : (
          <Image
            src={product.image}
            alt={product.name}
            fill
            sizes="(min-width: 1024px) 30vw, (min-width: 640px) 50vw, 100vw"
            className={`object-cover transition-transform duration-500 group-hover:scale-105 ${fullyOutOfStock ? "opacity-60" : ""}`}
          />
        )}
        {topLeftBadge !== undefined ? (
          topLeftBadge
        ) : fullyOutOfStock ? (
          <span className="absolute top-3 left-3 rounded-full bg-text-muted px-2.5 py-1 text-label font-bold text-bg-base">
            Ausverkauft
          </span>
        ) : (
          discount !== null && (
            <span className="absolute top-3 left-3 rounded-full bg-brand px-2.5 py-1 text-label font-bold text-text-primary">
              -{discount}%
            </span>
          )
        )}
        {wishlistEnabled && (
          <WishlistButton productId={product.numericId} className="absolute top-3 right-3" revealOnHover={wishlistRevealOnHover} />
        )}
      </div>
      <div className="flex flex-col gap-3 items-start px-5 pb-5 pt-4 w-full flex-1">
        <div className="flex flex-col gap-1 items-start w-full">
          {product.categories.length > 0 && (
            <p className="text-label font-semibold text-text-muted uppercase tracking-wide">{product.categories.join(", ")}</p>
          )}
          {product.href ? (
            <Link
              href={product.href}
              className="font-semibold text-h4 text-text-primary w-full hover:text-brand transition-colors"
              style={{ fontFamily: "var(--font-lora)" }}
            >
              {product.name}
            </Link>
          ) : (
            <p className="font-semibold text-h4 text-text-primary w-full" style={{ fontFamily: "var(--font-lora)" }}>
              {product.name}
            </p>
          )}
        </div>
        <p className="flex items-baseline gap-1.5">
          {discount !== null && (
            <span className="text-label text-text-muted line-through">{formatPrice(product.compareAtPrice!)}</span>
          )}
          <span className="font-bold text-h4 text-text-primary">{formatPrice(product.price)}</span>
          {!kleinunternehmer && <span className="text-label text-text-muted">inkl. {taxRate}% MwSt.</span>}
        </p>
        {belowPrice}
        {/* Always rendered, text conditional — reserved height keeps every
            card in a row equal height regardless of low-stock status. An
            earlier version omitted this for fully-out-of-stock products
            (this line can never apply there), on the theory that it was
            dead space — but NotifyMeForm's single-row redesign (see its
            own comment) now matches AddToCartInlineButton's button height
            exactly, which made THIS line the only remaining source of a
            mismatch: omitting it made the sold-out card shorter than its
            siblings instead of taller. Keeping it unconditional is what
            actually gets an exact match now. */}
        <p className="min-h-[1.05rem] text-label font-bold text-warning">{anyLowStock ? "Nur noch wenige verfügbar" : null}</p>

        {/* flex-1 spacer — pins every card's button to the same Y
            regardless of whether the title/category line wraps. */}
        <div className="flex-1" />

        <AddToCartInlineButton
          id={product.id}
          numericId={product.numericId}
          outOfStock={product.outOfStock}
          maxQty={product.maxQty}
          variants={product.variants}
        />
      </div>
    </div>
  );
}
