import { getProducts, getShippingSettings, getDefaultTaxRatePercent, getKleinunternehmer, getWishlistEnabled, getShopFilterEnabled } from "../../lib/payload";
import { RevealGroup, RevealItem } from "../../components/Reveal";
import { ProductCard } from "../../components/ProductCard";
import { PriceRangeFilter } from "./PriceRangeFilter";
import { CategoryFilter } from "./CategoryFilter";

// 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.

// Three filter dimensions: price (PriceRangeFilter.tsx, a real min/max
// slider — preset toggle buckets were tried first and reverted 2026-07-30,
// "keine toggle badges"), category (CategoryFilter.tsx, since
// `products.categories` now exists — same distinct-values-in-use pattern
// as the blog's category chips), and availability (in-stock only).
function isProductFullyOutOfStock(product: { outOfStock: boolean; variants: { outOfStock: boolean }[] }): boolean {
  return product.variants.length > 0 ? product.variants.every((v) => v.outOfStock) : product.outOfStock;
}

export async function ProductGrid({
  searchParams,
}: {
  searchParams?: { minPrice?: string; maxPrice?: string; categories?: string; inStock?: 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 allCategories = Array.from(new Set(allActiveProducts.flatMap((p) => p.categories))).sort((a, b) => a.localeCompare(b, "de"));
  const activeCategories =
    shopFilterEnabled && searchParams?.categories ? searchParams.categories.split(",").filter(Boolean) : [];
  const inStockOnly = shopFilterEnabled && searchParams?.inStock === "1";
  const anyOutOfStock = allActiveProducts.some(isProductFullyOutOfStock);

  const products = allActiveProducts.filter((p) => {
    if (minPrice !== null && p.price < minPrice) return false;
    if (maxPrice !== null && p.price > maxPrice) return false;
    // Uncategorized products (categories.length === 0) always match — see
    // Product.categories' own comment in lib/payload.ts.
    if (activeCategories.length > 0 && p.categories.length > 0 && !p.categories.some((c) => activeCategories.includes(c))) {
      return false;
    }
    if (inStockOnly && isProductFullyOutOfStock(p)) return false;
    return true;
  });

  const hasSidebarFilter = shopFilterEnabled && (catalogMin !== catalogMax || allCategories.length > 1 || anyOutOfStock);

  return (
    <section className="w-full bg-bg-base flex flex-col pb-16 md:pb-20 px-[var(--layout-padding-x)]">
      {/* <lg: filters (if any) sit as their own bar above the grid — same
          as before. lg+: they move into a left sidebar instead (see aside
          below), so this is hidden there to avoid rendering twice. */}
      {hasSidebarFilter && (
        <div className="lg:hidden flex flex-col gap-4 pb-10">
          <PriceRangeFilter catalogMin={catalogMin} catalogMax={catalogMax} />
          <CategoryFilter categories={allCategories} />
        </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:flex lg:flex-col lg:w-56 shrink-0 gap-6">
            {/* Same label treatment as AccountNav.tsx's "Mein Konto"
                heading — this sidebar is visually modeled on that one. */}
            <p className="text-label font-bold text-text-muted uppercase tracking-wide px-3 pb-2">Filter</p>
            <PriceRangeFilter catalogMin={catalogMin} catalogMax={catalogMax} layout="sidebar" />
            <CategoryFilter categories={allCategories} />
          </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 für diese Filter 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. */}
          {/* key'd on the rendered product set — same fix, same reason as
              blog/page.tsx's RevealGroup: `whileInView` only fires once per
              component instance, and a filter change (price/category/
              inStock) re-renders this same page in place rather than
              remounting it, so RevealGroup itself never naturally unmounts
              between filter states. Without the key, freshly swapped-in
              RevealItems mounted into an already-settled parent and stayed
              stuck at opacity 0 — the grid going blank/white after
              applying a filter. */}
          {/* No items-start here (was set before, silently defeating
              ProductCard's own h-full, built exactly for equal-height
              cards) — default items-stretch is what makes every card in a
              row match the tallest one overall. That alone doesn't align
              each card's internal rows (e.g. the price sitting right
              after a subline that wraps to 2 lines on one card but 1 on
              its neighbor) — see ProductCard.tsx's own comment on the
              subgrid rows (grid-auto-rows below) that solves that part:
              each RevealItem here spans the same 6 row-tracks and passes
              them down via grid-template-rows: subgrid, so row heights are
              genuinely shared, no fixed line-clamp/truncation needed. */}
          <RevealGroup
            key={products.map((p) => p.id).join(",")}
            className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-12 gap-6 sm:gap-[var(--layout-grid-gap)] [grid-auto-rows:auto_auto_auto_auto_auto_minmax(0,1fr)] w-full"
          >
            {products.map((product) => (
              <RevealItem key={product.id} className="lg:col-span-4 grid [grid-template-rows:subgrid] [grid-row:span_6]">
                <ProductCard
                  product={product}
                  defaultTaxRate={defaultTaxRate}
                  kleinunternehmer={kleinunternehmer}
                  wishlistEnabled={wishlistEnabled}
                  wishlistRevealOnHover
                  belowPrice={
                    <p className="text-label text-text-muted">
                      Lieferzeit: {shipping.totalDays.min}–{shipping.totalDays.max} Werktage innerhalb Deutschlands
                    </p>
                  }
                />
              </RevealItem>
            ))}
          </RevealGroup>
        </div>
      </div>
    </section>
  );
}
