import { Fragment, type ReactNode } from "react";
import Image from "next/image";
import Link from "next/link";
import { AddToCartButton } from "./AddToCartButton";
import { Reveal } from "./Reveal";
import { WishlistButton } from "./WishlistButton";
import { getSpotlightProduct, getShippingSettings, getDefaultTaxRatePercent, getKleinunternehmer, getWishlistEnabled } from "../lib/payload";
import { formatPrice, discountPercent } from "../lib/format";
import { effectiveTaxRate } from "../lib/cartTotals";

type LexicalTextNode = { type: "text"; text: string; format?: number };
type LexicalNode = { type: string; text?: string; format?: number; children?: LexicalNode[] };

// Minimal Lexical JSON → JSX converter for spotlightText — deliberately NOT
// the full block-oriented RichText.tsx (Posts/LegalPages' renderer, with
// its own heading/paragraph spacing and image/quote blocks). This teaser
// only ever needs paragraphs of plain text with optional bold spans
// (Lexical's text `format` bitmask: 1 = bold), rendered inline to match
// this section's own <p className="text-body ..."> treatment rather than
// picking up article-level block styling.
function renderInline(node: LexicalNode, key: number): ReactNode {
  if (node.type === "text") {
    const textNode = node as LexicalTextNode;
    const format = typeof textNode.format === "number" ? textNode.format : 0;
    const bold = (format & 1) === 1;
    // 2 = italic in Lexical's format bitmask — was silently dropped here,
    // so italic spans (e.g. Tasse "Die Pause"'s spotlightText) rendered as
    // plain text on the homepage despite showing correctly in the admin's
    // richText editor.
    const italic = (format & 2) === 2;
    let el: ReactNode = textNode.text;
    if (italic) el = <em>{el}</em>;
    if (bold) el = <strong>{el}</strong>;
    return <Fragment key={key}>{el}</Fragment>;
  }
  if (node.type === "linebreak") return <br key={key} />;
  // Any other inline node (link, etc.) — render its text children without
  // the wrapper itself; this teaser has no use for an actual <a> here.
  return (node.children ?? []).map((child, i) => renderInline(child, i));
}

function SpotlightText({ content, fallback }: { content: unknown; fallback: string }) {
  const root = (content as { root?: { children?: LexicalNode[] } } | null)?.root;
  if (!root?.children?.length) {
    return <p className="text-body text-text-body whitespace-pre-line">{fallback}</p>;
  }
  return (
    <>
      {root.children.map((paragraph, i) => (
        <p key={i} className="text-body text-text-body">
          {(paragraph.children ?? []).map((child, j) => renderInline(child, j))}
        </p>
      ))}
    </>
  );
}

/**
 * Product teaser for whichever product is marked `spotlight` in Payload
 * (defaults to none — the section just doesn't render until one is set),
 * placed after the Werkzeuge section (not right after the Hero — that
 * already has its own primary CTA, the 7-Tage-Challenge, and a second
 * strong purchase CTA competing with it there would dilute focus).
 * Werkzeuge already introduces the flagship tool as a concept with an
 * "Entdecken" link; this is the natural next step — a concrete way to buy
 * it, right where interest was just built, rather than dropped at the
 * very top before the page has earned any trust. Not derived from a
 * Figma frame (page-home never had this section) — a deliberate,
 * code-only addition, styled to match /todo-cards' pricing panel.
 * Headline/copy/photo are the product's own dedicated spotlight* fields
 * (deliberately separate from its plain catalog name/description/image —
 * see Products.ts), not duplicated here as hardcoded literals.
 */
export async function ProductSpotlight() {
  const [product, shipping, defaultTaxRate, kleinunternehmer, wishlistEnabled] = await Promise.all([
    getSpotlightProduct(),
    getShippingSettings(),
    getDefaultTaxRatePercent(),
    getKleinunternehmer(),
    getWishlistEnabled(),
  ]);
  if (!product) return null;

  const image = product.spotlightImage || product.image;
  const discount = discountPercent(product.price, product.compareAtPrice);
  const taxRate = effectiveTaxRate(product, defaultTaxRate);
  // Same "any vs. every" split as ProductGrid.tsx.
  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 (
    // id="spotlight" — the Navbar's "Shop" link becomes an anchor to this
    // section instead of navigating to /shop whenever exactly 1 product is
    // active (see Navbar.tsx/layout.tsx).
    <section id="spotlight" className="w-full bg-bg-base py-12 sm:py-16 px-[var(--layout-padding-x)]">
      {/* Row layout only from lg (1024px) up — sm:flex-row used to kick in
          at 640px, but a 380px-wide image + text squeezed into the rest of
          a tablet-width viewport (768-1023px) read as cramped/too wide.
          Tablet now stays stacked like mobile, but max-w-[32rem] between sm
          and lg keeps that stacked card centered and narrower than the
          tablet viewport instead of stretching to fill it — true mobile
          (below sm) stays unconstrained since the viewport itself is
          already narrow there. */}
      <Reveal className="max-w-[75rem] sm:max-w-[32rem] lg:max-w-[75rem] mx-auto rounded-md flex flex-col lg:flex-row gap-8 lg:gap-12 items-center p-6 sm:p-10">
        <div className="group relative w-full lg:w-[23.75rem] lg:shrink-0 aspect-[410/227] rounded-sm overflow-hidden">
          <Image
            src={image}
            alt={product.name}
            fill
            sizes="(min-width: 1024px) 380px, (min-width: 640px) 512px, 100vw"
            className="object-cover transition-transform duration-500 group-hover:scale-105"
          />
          {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 && product.spotlightShowWishlist && (
            <WishlistButton productId={product.numericId} className="absolute top-3 right-3" revealOnHover />
          )}
        </div>

        <div className="flex flex-col gap-4 items-start flex-1 min-w-0 w-full">
          <p className="font-bold text-h-small text-brand">{product.spotlightEyebrow || "Neu im Shop"}</p>
          <p
            className="font-semibold text-h-section text-text-primary"
            style={{ fontFamily: "var(--font-lora)" }}
          >
            {product.spotlightHeadline || product.name}
          </p>
          <SpotlightText content={product.spotlightText} fallback={product.descriptionText} />
          {/* MwSt./Versand disclosure on its own line, not crammed into
              the price row itself — same reasoning as todo-cards'
              Pricing.tsx (identical text, same narrow-column risk). */}
          <div className="flex flex-col gap-1 items-start">
            <div className="flex gap-2 items-baseline">
              {discount !== null && (
                <p className="text-body text-text-muted line-through">{formatPrice(product.compareAtPrice!)}</p>
              )}
              <p className="font-bold text-h3 text-text-primary">{formatPrice(product.price)}</p>
            </div>
            <p className="text-label text-text-muted">
              {kleinunternehmer
                ? product.noShippingCost
                  ? "Keine Versandkosten"
                  : "zzgl. Versand"
                : `inkl. ${taxRate}% MwSt. ${product.noShippingCost ? "– keine Versandkosten" : "zzgl. Versand"}`}
            </p>
            {!product.noShippingCost && (
              <p className="text-label text-text-muted">
                Lieferzeit: {shipping.totalDays.min}–{shipping.totalDays.max} Werktage innerhalb Deutschlands
              </p>
            )}
          </div>
          {/* Single product, no grid siblings to stay equal-height with
              (unlike ProductGrid.tsx/RelatedProducts.tsx), so this can be
              a plain conditional line instead of a reserved-height slot. */}
          {anyLowStock && <p className="text-label font-bold text-warning">Nur noch wenige verfügbar</p>}
          {/* items-start at sm: — without it, the default cross-axis
              stretch makes "Mehr erfahren" grow to match
              AddToCartButton's own height whenever that one gets taller
              (e.g. the low-stock hint line pushing its content down), so
              a plain text link visibly ends up "fatter" than the actual
              button next to it. */}
          <div className="flex flex-col sm:flex-row items-stretch sm:items-start gap-3 w-full sm:w-auto">
            {/* No className override — the section's bg is bg-bg-base now
                (matches Tools/Blog above/below), same as AddToCartButton's
                own default styling/ring-offset, so no override is needed
                here. */}
            <AddToCartButton label="In den Warenkorb" productId={product.id} numericId={product.numericId} outOfStock={product.outOfStock} maxQty={product.maxQty} variants={product.variants} />
            {product.href && (
              <Link
                href={product.href}
                className="inline-flex items-center justify-center px-6 py-[0.8125rem] rounded-sm border border-border text-body font-bold text-text-primary whitespace-nowrap hover:border-brand hover:text-brand active:scale-[0.97] transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-2 focus-visible:ring-offset-bg-base"
              >
                Mehr erfahren
              </Link>
            )}
          </div>
        </div>
      </Reveal>
    </section>
  );
}
