import Link from "next/link";
import Image from "next/image";
import { getProducts, getShippingSettings, getDefaultTaxRatePercent, getKleinunternehmer, getWishlistEnabled, getShopFilterEnabled } from "../../lib/payload";
import { effectiveTaxRate } from "../../lib/cartTotals";
import { formatPrice, discountPercent } from "../../lib/format";
import { RevealGroup, RevealItem } from "../../components/Reveal";
import { AddToCartInlineButton } from "../../components/AddToCartInlineButton";
import { WishlistButton } from "../../components/WishlistButton";
import { ArrowRightIcon } from "../../components/ArrowRightIcon";
import { PriceRangeFilter } from "./PriceRangeFilter";

// Server Component — fetches straight from Payload (getProducts(), ISR
// cached 60s) rather than going through the client-side useProducts()
// hook /cart's components need; this grid doesn't react to cart state, so
// there's no reason to pay for a client fetch when a server one already
// gives faster first paint and no loading flash.

// Products have no category taxonomy today (only Posts do) — a "N
// checkboxes" category sidebar isn't buildable against real data yet, so
// this only covers price, the one dimension that already exists on every
// product. A real min/max range (PriceRangeFilter.tsx), not preset toggle
// buckets — tried buckets-as-toggle-chips first, reverted 2026-07-30
// ("keine toggle badges").
export async function ProductGrid({ searchParams }: { searchParams?: { minPrice?: string; maxPrice?: string } }) {
  const [allProducts, shipping, defaultTaxRate, kleinunternehmer, wishlistEnabled, shopFilterEnabled] = await Promise.all([
    getProducts(),
    getShippingSettings(),
    getDefaultTaxRatePercent(),
    getKleinunternehmer(),
    getWishlistEnabled(),
    getShopFilterEnabled(),
  ]);
  const allActiveProducts = allProducts.filter((p) => p.active);

  if (allActiveProducts.length === 0) {
    return (
      <section className="w-full bg-bg-base flex flex-col items-center pb-16 md:pb-20 px-[var(--layout-padding-x)]">
        <p className="text-body text-text-muted">Aktuell keine Produkte verfügbar.</p>
      </section>
    );
  }

  const catalogPrices = allActiveProducts.map((p) => p.price);
  const catalogMin = Math.min(...catalogPrices);
  const catalogMax = Math.max(...catalogPrices);
  const minPrice = shopFilterEnabled && searchParams?.minPrice ? Number(searchParams.minPrice) : null;
  const maxPrice = shopFilterEnabled && searchParams?.maxPrice ? Number(searchParams.maxPrice) : null;
  const products = allActiveProducts.filter((p) => (minPrice === null || p.price >= minPrice) && (maxPrice === null || p.price <= maxPrice));

  const hasSidebarFilter = shopFilterEnabled && catalogMin !== catalogMax;

  return (
    <section className="w-full bg-bg-base flex flex-col pb-16 md:pb-20 px-[var(--layout-padding-x)]">
      {/* <lg: filter (if any) sits as its own bar above the grid — same as
          before. lg+: it moves into a left sidebar instead (see aside
          below), so it's hidden here to avoid rendering twice. */}
      {hasSidebarFilter && (
        <div className="lg:hidden">
          <PriceRangeFilter catalogMin={catalogMin} catalogMax={catalogMax} />
        </div>
      )}

      {/* lg:flex — a real left sidebar only once there's an actual filter
          to put in it (hasSidebarFilter); with no filter, the grid alone
          fills the row exactly as before, no empty reserved column. */}
      <div className={hasSidebarFilter ? "lg:flex lg:gap-10 w-full" : "w-full"}>
        {hasSidebarFilter && (
          <aside className="hidden lg:block lg:w-56 shrink-0">
            <PriceRangeFilter catalogMin={catalogMin} catalogMax={catalogMax} layout="sidebar" />
          </aside>
        )}

        <div className="flex-1 min-w-0 flex flex-col">
          {products.length === 0 && <p className="text-body text-text-muted pb-6">Keine Produkte in dieser Preisspanne gefunden.</p>}

          {/* 2-up from the mobile breakpoint (sm, 640px) through 1023px — was
              sm:grid-cols-12 with each card sm:col-span-3 (4-up), too narrow a
              card through that tablet range. lg+ is now 3-up (col-span-4 of
              12) rather than 4-up — narrowed to leave room for the sidebar
              filter alongside it (see hasSidebarFilter above); with no
              filter active the grid still renders at this same 3-up density,
              simplest to keep one fixed lg: density rather than branching
              the whole grid on hasSidebarFilter too. */}
          <RevealGroup className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-12 gap-6 sm:gap-[var(--layout-grid-gap)] w-full">
            {products.map((product) => {
          const discount = discountPercent(product.price, product.compareAtPrice);
          const taxRate = effectiveTaxRate(product, defaultTaxRate);
          // A varianted product only reads as "ausverkauft" overall once
          // every one of its variants is — a single sold-out variant just
          // shows as such in the picker itself (AddToCartInlineButton),
          // not as a blanket badge that would misleadingly suggest the
          // whole product is unavailable while other variants still are.
          const fullyOutOfStock = product.variants.length > 0 ? product.variants.every((v) => v.outOfStock) : product.outOfStock;
          // Mirrors fullyOutOfStock's "any vs. every" split — a varianted
          // product reads as low-stock as soon as one variant is, since a
          // shopper landing on the grid hasn't picked a variant yet.
          const anyLowStock = product.variants.length > 0 ? product.variants.some((v) => v.lowStock) : product.lowStock;
          return (
          <RevealItem
            key={product.id}
            className="group lg:col-span-4 bg-bg-base border border-border rounded-md overflow-hidden flex flex-col h-full transition-transform duration-300 hover:-translate-y-1"
          >
            <div className="relative w-full aspect-[276/210] overflow-hidden">
              <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" : ""}`}
              />
              {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 />
              )}
            </div>
            <div className="flex flex-col gap-4 items-start px-5 pb-5 pt-4 w-full flex-1">
              <p
                className="font-semibold text-h4 text-text-primary w-full"
                style={{ fontFamily: "var(--font-lora)" }}
              >
                {product.name}
              </p>
              <div className="flex flex-col gap-1 items-start">
                <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>
                <p className="text-label text-text-muted">
                  Lieferzeit: {shipping.totalDays.min}–{shipping.totalDays.max} Werktage innerhalb Deutschlands
                </p>
              </div>
              {/* Always rendered, text conditional — not a conditional
                  block — so this line's height (min-h as a cross-browser
                  safety net for the empty case) is identical whether or
                  not the product is low-stock. See AddToCartButton.tsx's
                  own comment: an earlier text-based low-stock hint here
                  broke equal card heights across the grid, which is why
                  it moved to the image-overlay pill in the first place. */}
              <p className="min-h-[1.05rem] text-label font-bold text-warning">
                {anyLowStock ? "Nur noch wenige verfügbar" : null}
              </p>
              {product.href && (
                <Link
                  href={product.href}
                  className="flex items-center gap-1 font-bold text-label text-text-primary hover:text-brand transition-colors"
                >
                  <span>Mehr erfahren</span>
                  <ArrowRightIcon />
                </Link>
              )}

              {/* flex-1 spacer — pins every card's button to the same Y
                  regardless of the "Mehr erfahren" line only products with
                  a detail page have (see figma-to-nextjs skill's Tools.tsx
                  equal-height lesson). */}
              <div className="flex-1" />

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