// Shop page and PDP

// Viser porsjonspris som hovedtall (fisk/skalldyr) og kilopris som undertekst.
// For ikke-vekt-produkter (stk/pakke/glass/liter) vises bare p.price.
const ProductPriceDisplay = ({ p }) => {
  const isFishLike = p.kind === "fish" || p.kind === "shellfish";
  if (!isFishLike) {
    return (
      <span style={{ fontFamily: "var(--hv-font-display)", fontWeight: 700, fontSize: 15 }}>
        {p.price} kr
      </span>
    );
  }
  const bp = typeof basePortion === "function" ? basePortion(p) : null;
  const grams = bp || 250;
  const portion = Math.round((p.price * grams) / 1000);
  const gramsLabel = grams >= 1000 ? `${grams/1000} kg` : `${grams} g`;
  return (
    <span style={{ display: "inline-flex", flexDirection: "column", lineHeight: 1.15 }}>
      <span style={{ fontFamily: "var(--hv-font-display)", fontWeight: 700, fontSize: 15, color: "var(--hv-fg-1)" }}>
        {portion} kr <span style={{ fontSize: 12, fontWeight: 500, color: "var(--hv-teal)" }}>pr porsjon</span>
      </span>
      <span style={{ fontSize: 10.5, color: "var(--hv-fg-3)", marginTop: 3, fontWeight: 500, letterSpacing: "0.02em" }}>
        {p.price} kr/kg
      </span>
    </span>
  );
};

const CATS = ["Alle", "Hvit fisk", "Rød fisk", "Skalldyr og skjell", "Fiskemat"];

const NATURAL_FILTERS = [
  {
    id: "egenskaper",
    label: "Egenskaper",
    options: [
      { id: "wild", label: "Villfanget", test: p => p.wild === true },
      { id: "klar", label: "Klar å spise", test: p => p.tag === "Klar å spise" },
      { id: "fersk", label: "Fersk i dag", test: p => p.tag === "Fersk i dag" },
      { id: "uten-bein", label: "Kan leveres uten bein", test: p => Array.isArray(p.options?.bein) && p.options.bein.includes("Uten bein") },
      { id: "uten-skinn", label: "Kan leveres uten skinn", test: p => Array.isArray(p.options?.skinn) && p.options.skinn.includes("Uten skinn") },
    ],
  },
  {
    id: "type",
    label: "Type",
    options: [
      { id: "fish", label: "Fisk (hel/filet)", test: p => p.kind === "fish" },
      { id: "shellfish", label: "Skalldyr og skjell", test: p => p.kind === "shellfish" },
      { id: "unit", label: "Glass, pakker, kasser", test: p => p.kind === "unit" },
    ],
  },
];

const SORT_OPTS = [
  { id: "name", label: "Navn A–Å" },
  { id: "price-asc", label: "Pris ↑ lavest" },
  { id: "price-desc", label: "Pris ↓ høyest" },
];

const ART_LIST = [
  { id: "blåkveite", label: "Blåkveite", match: n => /blåkveite/i.test(n) },
  { id: "blåskjell", label: "Blåskjell", match: n => /blåskjell/i.test(n) },
  { id: "breiflabb", label: "Breiflabb", match: n => /breiflabb/i.test(n) },
  { id: "brosme", label: "Brosme", match: n => /brosme/i.test(n) },
  { id: "bøkling", label: "Bøkling", match: n => /bøkling/i.test(n) },
  { id: "dorade", label: "Dorade", match: n => /dorade/i.test(n) },
  { id: "fjellørret", label: "Fjellørret", match: n => /fjellørret/i.test(n) },
  { id: "flekksteinbit", label: "Flekksteinbit", match: n => /flekksteinbit/i.test(n) },
  { id: "hjerteskjell", label: "Hjerteskjell", match: n => /hjerteskjell/i.test(n) },
  { id: "hummer", label: "Hummer", match: n => /hummer/i.test(n) },
  { id: "hyse", label: "Hyse", match: n => /\bhyse\b/i.test(n) },
  { id: "ishavsrøye", label: "Ishavsrøye", match: n => /ishavsrøye/i.test(n) },
  { id: "kamskjell", label: "Kamskjell", match: n => /kamskjell/i.test(n) },
  { id: "kongekrabbe", label: "Kongekrabbe", match: n => /kongekrabbe/i.test(n) },
  { id: "snøkrabbe", label: "Snøkrabbe", match: n => /snøkrabbe/i.test(n) },
  { id: "krabbe", label: "Krabbe", match: n => /krabbe/i.test(n) && !/(konge|snø)krabbe/i.test(n) },
  { id: "kveite", label: "Kveite", match: n => /\bkveite\b/i.test(n) },
  { id: "laks", label: "Laks", match: n => /\blaks\b/i.test(n) },
  { id: "lange", label: "Lange", match: n => /\blange\b/i.test(n) },
  { id: "lyr", label: "Lyr", match: n => /\blyr\b/i.test(n) },
  { id: "lysing", label: "Lysing", match: n => /lysing/i.test(n) },
  { id: "makrell", label: "Makrell", match: n => /makrell/i.test(n) },
  { id: "piggvar", label: "Piggvar", match: n => /piggvar/i.test(n) },
  { id: "reker", label: "Reker", match: n => /reker/i.test(n) },
  { id: "rødspette", label: "Rødspette", match: n => /rødspette/i.test(n) },
  { id: "sei", label: "Sei", match: n => /\bsei\b/i.test(n) },
  { id: "sild", label: "Sild", match: n => /sild/i.test(n) },
  { id: "sjøkreps", label: "Sjøkreps", match: n => /sjøkreps/i.test(n) },
  { id: "skate", label: "Skate", match: n => /\bskate/i.test(n) },
  { id: "skrei", label: "Skrei", match: n => /skrei/i.test(n) },
  { id: "torsk", label: "Torsk", match: n => /\btorsk\b/i.test(n) },
  { id: "uer", label: "Uer", match: n => /\buer\b/i.test(n) },
  { id: "ørret", label: "Ørret", match: n => /\børret\b/i.test(n) && !/fjellørret/i.test(n) },
  { id: "østers", label: "Østers", match: n => /østers/i.test(n) },
];

const Shop = ({ goPDP, addToCart, initCat, clearInitCat }) => {
  const [cat, setCat] = React.useState(() => {
    const init = initCat || window.__shopInitCat || "Alle";
    window.__shopInitCat = null;
    return init;
  });
  const [query, setQuery] = React.useState("");
  const [filters, setFilters] = React.useState({});
  const [filterOpen, setFilterOpen] = React.useState(false);
  const [sort, setSort] = React.useState("name");
  const [priceMin, setPriceMin] = React.useState("");
  const [priceMax, setPriceMax] = React.useState("");
  const [artFilter, setArtFilter] = React.useState({});
  const [artSearch, setArtSearch] = React.useState("");
  const filterRef = React.useRef(null);

  const toggleFilter = (groupId, optId) => {
    setFilters(prev => {
      const next = { ...prev };
      const group = { ...(next[groupId] || {}) };
      if (group[optId]) delete group[optId]; else group[optId] = true;
      if (Object.keys(group).length === 0) delete next[groupId];
      else next[groupId] = group;
      return next;
    });
  };
  const toggleArt = (id) => {
    setArtFilter(prev => {
      const next = { ...prev };
      if (next[id]) delete next[id]; else next[id] = true;
      return next;
    });
  };
  const clearFilters = () => {
    setFilters({});
    setSort("name");
    setPriceMin("");
    setPriceMax("");
    setArtFilter({});
    setArtSearch("");
  };

  const priceFilterActive = priceMin !== "" || priceMax !== "";
  const sortActive = sort !== "name";
  const activeFilterCount =
    Object.values(filters).reduce((s, g) => s + Object.keys(g).length, 0)
    + Object.keys(artFilter).length
    + (priceFilterActive ? 1 : 0)
    + (sortActive ? 1 : 0);

  React.useEffect(() => {
    if (!filterOpen) return;
    const onDown = (e) => {
      if (filterRef.current && !filterRef.current.contains(e.target)) setFilterOpen(false);
    };
    const onKey = (e) => { if (e.key === "Escape") setFilterOpen(false); };
    window.addEventListener("mousedown", onDown);
    window.addEventListener("keydown", onKey);
    return () => {
      window.removeEventListener("mousedown", onDown);
      window.removeEventListener("keydown", onKey);
    };
  }, [filterOpen]);

  React.useEffect(() => {
    if (initCat) {
      setCat(initCat);
      setQuery("");
      setFilters({});
      setArtFilter({});
      setPriceMin("");
      setPriceMax("");
      setSort("name");
      if (typeof clearInitCat === "function") clearInitCat();
    }
  }, [initCat, clearInitCat]);

  const list = React.useMemo(() => {
    const visible = PRODUCTS.filter(p => p.status !== "hidden" && !p.deleted);
    let items = cat === "Alle" ? visible : visible.filter(p => p.cat === cat);
    if (query.trim()) {
      const q = query.trim().toLowerCase();
      items = items.filter(p =>
        p.name.toLowerCase().includes(q) ||
        (p.desc && p.desc.toLowerCase().includes(q)) ||
        (p.cat && p.cat.toLowerCase().includes(q))
      );
    }
    for (const group of NATURAL_FILTERS) {
      const sel = filters[group.id];
      if (!sel || Object.keys(sel).length === 0) continue;
      const tests = group.options.filter(o => sel[o.id]).map(o => o.test);
      if (tests.length === 0) continue;
      items = items.filter(p => tests.some(t => t(p)));
    }
    const minP = parseInt(priceMin, 10);
    const maxP = parseInt(priceMax, 10);
    if (!isNaN(minP)) items = items.filter(p => p.price >= minP);
    if (!isNaN(maxP)) items = items.filter(p => p.price <= maxP);
    const activeArts = ART_LIST.filter(a => artFilter[a.id]);
    if (activeArts.length > 0) {
      items = items.filter(p => activeArts.some(a => a.match(p.name)));
    }
    const sorted = [...items];
    if (sort === "price-asc") sorted.sort((a, b) => a.price - b.price);
    else if (sort === "price-desc") sorted.sort((a, b) => b.price - a.price);
    else sorted.sort((a, b) => a.name.localeCompare(b.name, "nb"));
    return sorted;
  }, [cat, query, filters, priceMin, priceMax, artFilter, sort]);

  return (
    <>
      <Section tight>
        <Wrap>
          <div style={{ paddingTop: 40 }}>
            <Eyebrow>Butikken</Eyebrow>
            <h1 className="nw-display" style={{ marginTop: 16, fontSize: "clamp(48px, 7vw, 104px)" }}>
              Alt vi <em>har nå.</em>
            </h1>
            <p className="nw-lead" style={{ marginTop: 20, maxWidth: "56ch" }}>
              Listen oppdateres når båten kommer inn. Er en vare borte, er den solgt ut — vi fyller ikke på fra fryser.
            </p>
          </div>
        </Wrap>
      </Section>
      <Wrap>
        <div style={{ display: "flex", flexDirection: "column", gap: 16, marginBottom: 32 }}>
          <div style={{ display: "flex", gap: 12, alignItems: "center", justifyContent: "space-between", flexWrap: "wrap" }}>
            <input
              type="search"
              placeholder="Søk etter produkt…"
              value={query}
              onChange={e => setQuery(e.target.value)}
              style={{
                flex: "1 1 240px", maxWidth: 400,
                padding: "10px 16px", fontSize: 15,
                border: "1px solid var(--hv-line)", borderRadius: 8,
                background: "var(--hv-surface)", color: "var(--hv-fg-1)",
                outline: "none",
              }}
            />
            <div ref={filterRef} style={{ position: "relative", zIndex: 50 }}>
              <button
                type="button"
                onClick={() => setFilterOpen(o => !o)}
                aria-expanded={filterOpen}
                aria-haspopup="true"
                className={"nw-kalk-chip" + (filterOpen || activeFilterCount > 0 ? " active" : "")}
                style={{ display: "inline-flex", alignItems: "center", gap: 8, fontSize: 14, padding: "10px 16px", cursor: "pointer" }}
              >
                <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                  <path d="M2 4h12M4 8h8M6 12h4"/>
                </svg>
                Filtrer
                {activeFilterCount > 0 && (
                  <span style={{
                    display: "inline-flex", alignItems: "center", justifyContent: "center",
                    minWidth: 20, height: 20, padding: "0 6px", borderRadius: 999,
                    background: filterOpen ? "rgba(8,10,9,0.85)" : "var(--hv-teal)",
                    color: filterOpen ? "var(--hv-teal)" : "var(--hv-ink)",
                    fontSize: 11, fontWeight: 700, lineHeight: 1,
                  }}>{activeFilterCount}</span>
                )}
              </button>
              {filterOpen && (
                <div
                  role="dialog"
                  aria-label="Filtrer produkter"
                  style={{
                    position: "absolute", top: "calc(100% + 8px)", right: 0,
                    width: 360, maxWidth: "calc(100vw - 32px)",
                    maxHeight: "calc(100vh - 120px)", overflowY: "auto",
                    background: "var(--hv-ink-2)",
                    backgroundColor: "#0F1412",
                    border: "1px solid var(--hv-line)",
                    borderRadius: 14,
                    padding: 18,
                    zIndex: 1000,
                    boxShadow: "0 24px 48px -12px rgba(0,0,0,0.65), 0 4px 12px rgba(0,0,0,0.4)",
                    display: "flex", flexDirection: "column", gap: 18,
                  }}
                >
                  <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", position: "sticky", top: -18, marginTop: -18, paddingTop: 18, marginLeft: -18, marginRight: -18, paddingLeft: 18, paddingRight: 18, paddingBottom: 6, background: "#0F1412", zIndex: 2 }}>
                    <span style={{ fontSize: 12, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.12em", color: "var(--hv-fg-3)" }}>
                      Naturlige filtre
                    </span>
                    {activeFilterCount > 0 && (
                      <button
                        type="button"
                        onClick={clearFilters}
                        style={{
                          background: "none", border: "none", cursor: "pointer",
                          color: "var(--hv-teal)", fontSize: 12, fontWeight: 600,
                          padding: 0, textDecoration: "underline",
                        }}
                      >Tøm alle</button>
                    )}
                  </div>

                  {/* Sortering */}
                  <div>
                    <div style={{ fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.12em", color: "var(--hv-fg-2)", marginBottom: 10 }}>
                      Sortering
                    </div>
                    <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
                      {SORT_OPTS.map(s => (
                        <button
                          key={s.id}
                          type="button"
                          onClick={() => setSort(s.id)}
                          className={"nw-kalk-chip" + (sort === s.id ? " active" : "")}
                          style={{ fontSize: 12.5, padding: "6px 12px", cursor: "pointer" }}
                        >{s.label}</button>
                      ))}
                    </div>
                  </div>

                  {/* Pris min/max */}
                  <div>
                    <div style={{ fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.12em", color: "var(--hv-fg-2)", marginBottom: 10 }}>
                      Pris (kr)
                    </div>
                    <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                      <div style={{ flex: 1, position: "relative" }}>
                        <input
                          type="number"
                          min="0"
                          step="10"
                          inputMode="numeric"
                          placeholder="Min"
                          value={priceMin}
                          onChange={e => setPriceMin(e.target.value.replace(/[^0-9]/g, ""))}
                          style={{
                            width: "100%", padding: "8px 38px 8px 12px",
                            border: "1px solid var(--hv-line)", borderRadius: 8,
                            background: "rgba(255,255,255,0.03)", color: "var(--hv-fg-1)",
                            fontSize: 13, outline: "none",
                          }}
                        />
                        <span style={{ position: "absolute", right: 12, top: "50%", transform: "translateY(-50%)", fontSize: 11, color: "var(--hv-fg-3)", pointerEvents: "none" }}>kr</span>
                      </div>
                      <span style={{ color: "var(--hv-fg-3)", fontSize: 13 }}>–</span>
                      <div style={{ flex: 1, position: "relative" }}>
                        <input
                          type="number"
                          min="0"
                          step="10"
                          inputMode="numeric"
                          placeholder="Maks"
                          value={priceMax}
                          onChange={e => setPriceMax(e.target.value.replace(/[^0-9]/g, ""))}
                          style={{
                            width: "100%", padding: "8px 38px 8px 12px",
                            border: "1px solid var(--hv-line)", borderRadius: 8,
                            background: "rgba(255,255,255,0.03)", color: "var(--hv-fg-1)",
                            fontSize: 13, outline: "none",
                          }}
                        />
                        <span style={{ position: "absolute", right: 12, top: "50%", transform: "translateY(-50%)", fontSize: 11, color: "var(--hv-fg-3)", pointerEvents: "none" }}>kr</span>
                      </div>
                    </div>
                    <div style={{ fontSize: 11, color: "var(--hv-fg-3)", marginTop: 6 }}>
                      Kilopris for fisk og skalldyr · stk-pris for glass/pakker
                    </div>
                  </div>

                  {NATURAL_FILTERS.map(group => (
                    <div key={group.id}>
                      <div style={{ fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.12em", color: "var(--hv-fg-2)", marginBottom: 10 }}>
                        {group.label}
                      </div>
                      <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
                        {group.options.map(opt => {
                          const active = !!(filters[group.id] && filters[group.id][opt.id]);
                          const matchCount = PRODUCTS.filter(p => {
                            try { return opt.test(p); } catch { return false; }
                          }).length;
                          return (
                            <button
                              key={opt.id}
                              type="button"
                              onClick={() => toggleFilter(group.id, opt.id)}
                              className={"nw-kalk-chip" + (active ? " active" : "")}
                              style={{ fontSize: 12.5, padding: "6px 12px", cursor: "pointer" }}
                            >
                              {active && <span style={{ marginRight: 4 }}>✓</span>}
                              {opt.label}
                              <span style={{ marginLeft: 6, fontSize: 11, color: active ? "rgba(8,10,9,0.55)" : "var(--hv-fg-3)" }}>{matchCount}</span>
                            </button>
                          );
                        })}
                      </div>
                    </div>
                  ))}

                  {/* Spesifikk art */}
                  <div>
                    <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 10 }}>
                      <span style={{ fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.12em", color: "var(--hv-fg-2)" }}>
                        Spesifikk art
                      </span>
                      {Object.keys(artFilter).length > 0 && (
                        <button
                          type="button"
                          onClick={() => setArtFilter({})}
                          style={{ background: "none", border: "none", cursor: "pointer", color: "var(--hv-teal)", fontSize: 11, fontWeight: 600, padding: 0, textDecoration: "underline" }}
                        >Nullstill arter</button>
                      )}
                    </div>
                    <input
                      type="search"
                      placeholder="Søk art (f.eks. torsk, laks, krabbe…)"
                      value={artSearch}
                      onChange={e => setArtSearch(e.target.value)}
                      style={{
                        width: "100%", padding: "8px 12px", marginBottom: 10,
                        border: "1px solid var(--hv-line)", borderRadius: 8,
                        background: "rgba(255,255,255,0.03)", color: "var(--hv-fg-1)",
                        fontSize: 13, outline: "none",
                      }}
                    />
                    <div style={{ display: "flex", flexWrap: "wrap", gap: 6, maxHeight: 200, overflowY: "auto", paddingRight: 4 }}>
                      {(() => {
                        const q = artSearch.trim().toLowerCase();
                        const filtered = q ? ART_LIST.filter(a => a.label.toLowerCase().includes(q)) : ART_LIST;
                        if (filtered.length === 0) return (
                          <span style={{ fontSize: 12.5, color: "var(--hv-fg-3)", padding: "4px 0" }}>Ingen art matcher «{artSearch}»</span>
                        );
                        return filtered.map(a => {
                          const active = !!artFilter[a.id];
                          const matchCount = PRODUCTS.filter(p => a.match(p.name)).length;
                          if (matchCount === 0 && !active) return null;
                          return (
                            <button
                              key={a.id}
                              type="button"
                              onClick={() => toggleArt(a.id)}
                              className={"nw-kalk-chip" + (active ? " active" : "")}
                              style={{ fontSize: 12.5, padding: "6px 12px", cursor: "pointer" }}
                            >
                              {active && <span style={{ marginRight: 4 }}>✓</span>}
                              {a.label}
                              <span style={{ marginLeft: 6, fontSize: 11, color: active ? "rgba(8,10,9,0.55)" : "var(--hv-fg-3)" }}>{matchCount}</span>
                            </button>
                          );
                        });
                      })()}
                    </div>
                  </div>
                </div>
              )}
            </div>
          </div>
          <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
            {CATS.map(c => (
              <button key={c}
                className={"nw-kalk-chip" + (cat === c ? " active" : "")}
                onClick={() => setCat(c)}
              >{c} <span style={{ color: cat === c ? "rgba(8,10,9,0.5)" : "var(--hv-fg-3)", marginLeft: 4, fontSize: 11 }}>
                {(() => { const v = PRODUCTS.filter(p => p.status !== "hidden" && !p.deleted); return c === "Alle" ? v.length : v.filter(p => p.cat === c).length; })()}
              </span></button>
            ))}
          </div>
          {activeFilterCount > 0 && (
            <div style={{ display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap" }}>
              <span style={{ fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.1em", color: "var(--hv-fg-3)" }}>Aktive filtre:</span>
              {sortActive && (
                <button
                  type="button"
                  onClick={() => setSort("name")}
                  className="nw-kalk-chip active"
                  style={{ fontSize: 12, padding: "5px 10px", cursor: "pointer" }}
                  aria-label="Tilbakestill sortering"
                >
                  {SORT_OPTS.find(s => s.id === sort)?.label} <span style={{ marginLeft: 4, fontSize: 13, lineHeight: 1 }}>×</span>
                </button>
              )}
              {priceFilterActive && (
                <button
                  type="button"
                  onClick={() => { setPriceMin(""); setPriceMax(""); }}
                  className="nw-kalk-chip active"
                  style={{ fontSize: 12, padding: "5px 10px", cursor: "pointer" }}
                  aria-label="Fjern prisfilter"
                >
                  {priceMin || "0"}–{priceMax || "∞"} kr <span style={{ marginLeft: 4, fontSize: 13, lineHeight: 1 }}>×</span>
                </button>
              )}
              {NATURAL_FILTERS.flatMap(group =>
                Object.keys(filters[group.id] || {}).map(optId => {
                  const opt = group.options.find(o => o.id === optId);
                  if (!opt) return null;
                  return (
                    <button
                      key={`${group.id}:${optId}`}
                      type="button"
                      onClick={() => toggleFilter(group.id, optId)}
                      className="nw-kalk-chip active"
                      style={{ fontSize: 12, padding: "5px 10px", cursor: "pointer" }}
                      aria-label={`Fjern filter ${opt.label}`}
                    >
                      {opt.label} <span style={{ marginLeft: 4, fontSize: 13, lineHeight: 1 }}>×</span>
                    </button>
                  );
                })
              )}
              {Object.keys(artFilter).map(id => {
                const a = ART_LIST.find(x => x.id === id);
                if (!a) return null;
                return (
                  <button
                    key={`art:${id}`}
                    type="button"
                    onClick={() => toggleArt(id)}
                    className="nw-kalk-chip active"
                    style={{ fontSize: 12, padding: "5px 10px", cursor: "pointer" }}
                    aria-label={`Fjern art ${a.label}`}
                  >
                    {a.label} <span style={{ marginLeft: 4, fontSize: 13, lineHeight: 1 }}>×</span>
                  </button>
                );
              })}
              <button
                type="button"
                onClick={clearFilters}
                style={{
                  background: "none", border: "none", cursor: "pointer",
                  color: "var(--hv-fg-3)", fontSize: 12, fontWeight: 600,
                  padding: "5px 6px", textDecoration: "underline",
                }}
              >Tøm</button>
            </div>
          )}
        </div>
        {(query || activeFilterCount > 0) && (
          <p style={{ fontSize: 14, color: "var(--hv-fg-3)", marginBottom: 16 }}>
            {list.length} {list.length === 1 ? "resultat" : "resultater"}{query ? ` for «${query}»` : ""}
          </p>
        )}
      </Wrap>
      <Section tight>
        <Wrap>
          {list.length === 0 ? (
            <p style={{ color: "var(--hv-fg-3)", padding: "40px 0" }}>Ingen produkter funnet.</p>
          ) : (
            <div className="nw-pgrid">
              {list.map(p => (
                <div className="nw-pcard" key={p.slug} onClick={() => goPDP(p.slug)}>
                  <div className="nw-pcard-media">
                    <img src={p.img} alt={p.name} loading="lazy" />
                    {p.wild && <span className="nw-pcard-tag nw-pcard-wild">Villfanget</span>}
                    {p.tag && !p.wild && <span className="nw-pcard-tag">{p.tag}</span>}
                  </div>
                  <div className="nw-pcard-body">
                    <div className="nw-pcard-cat">{p.cat}</div>
                    <div className="nw-pcard-name">{p.name}</div>
                    <div className="nw-pcard-foot">
                      <ProductPriceDisplay p={p} />
                      <button className="nw-btn nw-btn-ghost nw-btn-sm" style={{ padding: "8px 12px" }} onClick={(e) => { e.stopPropagation(); addToCart(p); }}>
                        <Plus size={14} /> Legg til
                      </button>
                    </div>
                  </div>
                </div>
              ))}
            </div>
          )}
        </Wrap>
      </Section>
    </>
  );
};

const FERSKVARE_FAQ = {
  q: "Er dette garantert tilgjengelig på leveringsdagen?",
  a: "Havøyet selger kun ferskvare — aldri fryst, aldri på lager. Det betyr at vi ikke kan garantere at et bestemt produkt er tilgjengelig på en gitt dag. Tilbudet oppdateres når båten kommer inn, og enkelte varer kan være utsolgt. Velg gjerne et alternativ, eller kontakt oss hvis du har et spesifikt ønske.",
};

// ─── PDP Reviews ──────────────────────────────────────────────────────────
const Stars = ({ value = 0, size = 14, interactive = false, onChange }) => {
  const [hover, setHover] = React.useState(0);
  const display = interactive && hover ? hover : value;
  return (
    <span style={{ display: "inline-flex", gap: 2 }} onMouseLeave={() => interactive && setHover(0)}>
      {[1,2,3,4,5].map(i => (
        <span key={i}
          onMouseEnter={() => interactive && setHover(i)}
          onClick={() => interactive && onChange && onChange(i)}
          style={{
            cursor: interactive ? "pointer" : "default",
            color: i <= display ? "#f5b93a" : "var(--hv-fg-3)",
            fontSize: size,
            lineHeight: 1,
          }}
        >★</span>
      ))}
    </span>
  );
};

const PDPReviews = ({ slug, productName }) => {
  const [reviews, setReviews] = React.useState([]);
  const [avg, setAvg] = React.useState(0);
  const [count, setCount] = React.useState(0);
  const [showForm, setShowForm] = React.useState(false);
  const [form, setForm] = React.useState({ name: "", rating: 5, text: "" });
  const [submitting, setSubmitting] = React.useState(false);
  const [msg, setMsg] = React.useState(null);

  const apiBase = window.HV_API_BASE || "";

  const fetchReviews = React.useCallback(async () => {
    try {
      const r = await fetch(`${apiBase}/api/reviews?slug=${encodeURIComponent(slug)}`, { cache: "no-store" });
      if (!r.ok) return;
      const data = await r.json();
      setReviews(data.reviews || []);
      setAvg(data.avg || 0);
      setCount(data.count || 0);
    } catch (e) { /* offline - ingen anmeldelser vises */ }
  }, [slug, apiBase]);

  React.useEffect(() => { fetchReviews(); }, [fetchReviews]);

  const submit = async (e) => {
    e?.preventDefault();
    if (!form.text.trim()) { setMsg({ type: "err", text: "Skriv en anmeldelse før du sender." }); return; }
    setSubmitting(true); setMsg(null);
    try {
      const r = await fetch(`${apiBase}/api/reviews`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ slug, name: form.name, rating: form.rating, text: form.text }),
      });
      if (!r.ok) throw new Error("Server returnerte " + r.status);
      setForm({ name: "", rating: 5, text: "" });
      setShowForm(false);
      setMsg({ type: "ok", text: "Takk for anmeldelsen!" });
      await fetchReviews();
    } catch (e) {
      setMsg({ type: "err", text: "Kunne ikke sende: " + e.message });
    } finally { setSubmitting(false); }
  };

  const RATING_LABELS = ["", "Ikke bra", "Greit nok", "Bra", "Veldig bra", "Fantastisk"];

  return (
    <Section tight>
      <Wrap>
        <div style={{ maxWidth: 760, margin: "0 auto" }}>
          {/* ─── HEADER ─────────────────────────────────────────────── */}
          <div style={{ textAlign: "center", marginBottom: 40 }}>
            <Eyebrow>Tilbakemeldinger</Eyebrow>
            <h2 className="nw-h2" style={{ marginTop: 14, marginBottom: 16 }}>Kundeanmeldelser</h2>
            {count > 0 ? (
              <div style={{ display: "inline-flex", alignItems: "center", gap: 10, padding: "8px 16px", borderRadius: 999, background: "var(--hv-teal-wash)", border: "1px solid rgba(65,193,186,0.25)" }}>
                <Stars value={Math.round(avg)} size={16} />
                <span style={{ fontSize: 14, color: "var(--hv-fg-2)", fontWeight: 600 }}>{avg.toFixed(1)} av 5</span>
                <span style={{ width: 3, height: 3, borderRadius: "50%", background: "var(--hv-fg-3)" }}/>
                <span style={{ fontSize: 14, color: "var(--hv-fg-3)" }}>{count} {count === 1 ? "anmeldelse" : "anmeldelser"}</span>
              </div>
            ) : (
              <p style={{ color: "var(--hv-fg-3)", fontSize: 15 }}>Ingen anmeldelser ennå — bli den første til å dele din erfaring.</p>
            )}
          </div>

          {/* ─── MESSAGE BANNER ──────────────────────────────────────── */}
          {msg && (
            <div style={{
              padding: "14px 18px", borderRadius: 10, marginBottom: 24, fontSize: 14,
              display: "flex", alignItems: "center", gap: 10,
              background: msg.type === "ok" ? "rgba(65,193,186,0.1)" : "rgba(239,68,68,0.1)",
              color: msg.type === "ok" ? "var(--hv-teal)" : "#ef4444",
              border: "1px solid " + (msg.type === "ok" ? "rgba(65,193,186,0.3)" : "rgba(239,68,68,0.3)"),
            }}>
              <span style={{ fontSize: 18 }}>{msg.type === "ok" ? "✓" : "!"}</span>
              <span>{msg.text}</span>
            </div>
          )}

          {/* ─── CTA / FORM ──────────────────────────────────────────── */}
          {!showForm && (
            <div style={{ display: "flex", justifyContent: "center", marginBottom: 40 }}>
              <Btn onClick={() => setShowForm(true)}>
                <span style={{ marginRight: 8 }}>✎</span>
                Skriv en anmeldelse
              </Btn>
            </div>
          )}

          {showForm && (
            <form onSubmit={submit} className="nw-review-form" style={{
              position: "relative",
              background: "linear-gradient(180deg, rgba(65,193,186,0.06), rgba(65,193,186,0.02) 40%, transparent)",
              padding: "32px 32px 28px",
              borderRadius: 16,
              border: "1px solid var(--hv-line)",
              marginBottom: 40,
              display: "flex", flexDirection: "column", gap: 20,
              boxShadow: "0 24px 48px -24px rgba(65,193,186,0.15)",
            }}>
              {/* Teal accent-border i toppen */}
              <div style={{ position: "absolute", top: 0, left: 24, right: 24, height: 2, background: "linear-gradient(90deg, transparent, var(--hv-teal), transparent)", borderRadius: 2 }}/>

              <div>
                <div style={{ fontSize: 12, fontWeight: 700, letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--hv-teal)", marginBottom: 8 }}>
                  Din vurdering
                </div>
                <h3 style={{ fontFamily: "var(--hv-font-display)", fontSize: 26, fontWeight: 800, letterSpacing: "-0.01em", color: "var(--hv-fg-1)", margin: 0, lineHeight: 1.2 }}>
                  Del din erfaring med <em style={{ color: "var(--hv-teal)", fontStyle: "italic" }}>{productName}</em>
                </h3>
              </div>

              {/* Stjerner med tekst-etikett */}
              <div style={{ padding: "22px 0", borderTop: "1px solid var(--hv-line)", borderBottom: "1px solid var(--hv-line)", textAlign: "center" }}>
                <div style={{ fontSize: 12, fontWeight: 700, letterSpacing: "0.12em", textTransform: "uppercase", color: "var(--hv-fg-2)", marginBottom: 10 }}>
                  Hvor fornøyd er du?
                </div>
                <div style={{ transform: "scale(1.4)", transformOrigin: "center", margin: "10px 0 14px" }}>
                  <Stars value={form.rating} size={24} interactive onChange={v => setForm({ ...form, rating: v })}/>
                </div>
                <div style={{ fontSize: 15, color: "var(--hv-teal)", fontWeight: 700, minHeight: 20 }}>
                  {RATING_LABELS[form.rating]}
                </div>
              </div>

              {/* Navn + anmeldelse */}
              <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
                <div>
                  <label style={labelStyle}>Navn <span style={{ color: "var(--hv-fg-2)", fontWeight: 500, textTransform: "none", letterSpacing: 0, fontSize: 12 }}>(valgfritt)</span></label>
                  <input type="text" value={form.name} onChange={e => setForm({ ...form, name: e.target.value })} placeholder="Kari Normann" style={inputStyle}/>
                </div>
                <div>
                  <label style={labelStyle}>Anmeldelse</label>
                  <textarea value={form.text} onChange={e => setForm({ ...form, text: e.target.value })} rows={4} placeholder="Hva likte du? Hva overrasket deg? Ville du anbefalt til andre?" style={{ ...inputStyle, resize: "vertical", minHeight: 120, lineHeight: 1.65, fontSize: 16 }}/>
                  <div style={{ fontSize: 12, color: "var(--hv-fg-2)", marginTop: 6, textAlign: "right", fontWeight: 500 }}>
                    {form.text.length}/2000 tegn
                  </div>
                </div>
              </div>

              {/* Footer med info + knapper */}
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, flexWrap: "wrap", paddingTop: 8 }}>
                <div style={{ fontSize: 12, color: "var(--hv-fg-3)", display: "flex", alignItems: "center", gap: 6 }}>
                  <span style={{ color: "var(--hv-teal)" }}>✓</span>
                  Anmeldelsen publiseres umiddelbart
                </div>
                <div style={{ display: "flex", gap: 10 }}>
                  <Btn variant="ghost" onClick={(e) => { e.preventDefault(); setShowForm(false); setMsg(null); }}>Avbryt</Btn>
                  <Btn onClick={submit} disabled={submitting}>{submitting ? "Sender…" : "Send anmeldelse →"}</Btn>
                </div>
              </div>
            </form>
          )}

          {/* ─── REVIEWS LIST ────────────────────────────────────────── */}
          {reviews.length > 0 && (
            <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
              {reviews.map(r => {
                const initials = (r.name || "?").split(" ").map(s => s[0]).join("").slice(0, 2).toUpperCase();
                return (
                  <div key={r.id} style={{
                    padding: "20px 22px",
                    borderRadius: 12,
                    border: "1px solid var(--hv-line)",
                    background: "rgba(255,255,255,0.015)",
                    display: "flex", gap: 16,
                  }}>
                    <div style={{
                      width: 40, height: 40, borderRadius: "50%",
                      background: "var(--hv-teal-wash)",
                      color: "var(--hv-teal)",
                      display: "flex", alignItems: "center", justifyContent: "center",
                      fontSize: 13, fontWeight: 700, fontFamily: "var(--hv-font-display)",
                      flexShrink: 0,
                    }}>{initials}</div>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", flexWrap: "wrap", gap: 8, marginBottom: 6 }}>
                        <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                          <span style={{ fontWeight: 700, fontFamily: "var(--hv-font-display)", fontSize: 15 }}>{r.name}</span>
                          <Stars value={r.rating} size={12}/>
                        </div>
                        <span style={{ fontSize: 12, color: "var(--hv-fg-3)" }}>{r.date}</span>
                      </div>
                      <p style={{ color: "var(--hv-fg-1)", fontSize: 15.5, lineHeight: 1.7, margin: 0, whiteSpace: "pre-wrap", fontWeight: 400 }}>{r.text}</p>
                    </div>
                  </div>
                );
              })}
            </div>
          )}
        </div>
      </Wrap>
    </Section>
  );
};

const labelStyle = {
  display: "block", fontSize: 12, fontWeight: 700, textTransform: "uppercase",
  letterSpacing: "0.12em", color: "var(--hv-fg-2)", marginBottom: 8,
};
const inputStyle = {
  width: "100%", padding: "14px 16px", borderRadius: 10,
  border: "1px solid var(--hv-line)",
  background: "rgba(255,255,255,0.03)",
  color: "var(--hv-fg-1)", fontSize: 16, fontWeight: 500, fontFamily: "var(--hv-font-body)",
  outline: "none",
  transition: "border-color 220ms var(--hv-ease), background 220ms var(--hv-ease)",
};

const PDPFaq = ({ slug }) => {
  const base = (typeof PRODUCT_FAQS !== "undefined" && PRODUCT_FAQS[slug]) || [];
  const faqs = [...base, FERSKVARE_FAQ];
  const [open, setOpen] = React.useState(null);
  const ldJson = JSON.stringify({
    "@context": "https://schema.org",
    "@type": "FAQPage",
    "mainEntity": faqs.map(f => ({
      "@type": "Question",
      "name": f.q,
      "acceptedAnswer": { "@type": "Answer", "text": f.a },
    })),
  });
  return (
    <Section tight>
      <Wrap>
        <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: ldJson }} />
        <h2 className="nw-h2" style={{ marginBottom: 32 }}>Ofte stilte spørsmål</h2>
        <div style={{ display: "flex", flexDirection: "column", gap: 2, maxWidth: 720 }}>
          {faqs.map((f, i) => (
            <div key={i} style={{ borderBottom: "1px solid var(--hv-line)" }}>
              <button
                onClick={() => setOpen(open === i ? null : i)}
                style={{
                  width: "100%", display: "flex", justifyContent: "space-between", alignItems: "center",
                  padding: "18px 0", background: "none", border: "none", cursor: "pointer",
                  textAlign: "left", color: "var(--hv-fg-1)", fontSize: 16, fontWeight: 600,
                  fontFamily: "var(--hv-font-display)",
                }}
              >
                <span>{f.q}</span>
                <span style={{ color: "var(--hv-teal)", fontSize: 20, marginLeft: 16, flexShrink: 0, transition: "transform 220ms" }}>
                  {open === i ? "−" : "+"}
                </span>
              </button>
              {open === i && (
                <p style={{ margin: "0 0 18px", color: "var(--hv-fg-2)", fontSize: 15, lineHeight: 1.7 }}>
                  {f.a}
                </p>
              )}
            </div>
          ))}
        </div>
      </Wrap>
    </Section>
  );
};

// Custom skalldyrkasse-bygger: klikkbare kategori-seksjoner med flervalg,
// maksgrense basert på antall personer (maxPerPerson × antall).
const CustomBoxBuilder = ({ builder, antall, selected, setSelected }) => {
  const [openCat, setOpenCat] = React.useState(builder.categories[0]?.id);
  const hardCap = builder.hardCap || Infinity;
  const theoreticalMax = builder.maxPerPerson * (antall || 1);
  const maxTotal = Math.min(hardCap, theoreticalMax);
  const capReached = theoreticalMax >= hardCap;
  // Kategorier som ikke teller mot maksgrensen (f.eks. tilbehør)
  const isFreeCat = (catId) => {
    const cat = builder.categories.find(c => c.id === catId);
    return !!(cat && cat.countTowardCap === false);
  };
  // Kun produkter i kategorier som teller, teller mot maksgrensen
  const total = Object.values(selected).filter(s => !isFreeCat(s.catId)).length;
  const remaining = Math.max(0, maxTotal - total);
  const panelRefs = React.useRef({});

  // Toggle produkt i/ut av valg
  const toggleProduct = (catId, produkt) => {
    const key = catId + ":" + produkt.navn;
    const free = isFreeCat(catId);
    setSelected(prev => {
      const next = { ...prev };
      if (next[key]) {
        delete next[key];
      } else if (free || Object.values(next).filter(s => !isFreeCat(s.catId)).length < maxTotal) {
        next[key] = { catId, navn: produkt.navn, pris: produkt.pris };
      }
      return next;
    });
  };

  // Stagger-animasjon av produkter når en kategori åpnes
  React.useEffect(() => {
    if (!window.anime || !openCat) return;
    const panel = panelRefs.current[openCat];
    if (!panel) return;
    const chips = panel.querySelectorAll("[data-prod-opt]");
    window.anime.set(chips, { opacity: 0, translateY: 8, scale: 0.94 });
    window.anime({
      targets: chips,
      opacity: [0, 1],
      translateY: [8, 0],
      scale: [0.94, 1],
      duration: 450,
      delay: window.anime.stagger(22),
      easing: "cubicBezier(0.16, 1, 0.3, 1)",
    });
  }, [openCat]);

  return (
    <div style={{ marginBottom: 24 }}>
      {/* Status-banner: valgt X av Y */}
      <div style={{
        display: "flex", alignItems: "center", justifyContent: "space-between",
        padding: "14px 18px", marginBottom: 14,
        background: remaining === 0 ? "rgba(245,158,11,0.08)" : "var(--hv-teal-wash)",
        border: `1px solid ${remaining === 0 ? "rgba(245,158,11,0.3)" : "rgba(65,193,186,0.25)"}`,
        borderRadius: 10,
      }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
          <span style={{ fontSize: 12, textTransform: "uppercase", letterSpacing: "0.08em", color: "var(--hv-fg-3)", fontWeight: 700 }}>Valgt</span>
          <span style={{ fontSize: 18, fontWeight: 700, fontFamily: "var(--hv-font-display)", color: total > 0 ? "var(--hv-teal)" : "var(--hv-fg-2)" }}>
            {total} / {maxTotal}
          </span>
          <span style={{ fontSize: 13, color: "var(--hv-fg-3)" }}>
            {capReached
              ? `(maks ${hardCap} arter per kasse)`
              : `(${builder.maxPerPerson} arter per person × ${antall} ${antall === 1 ? "person" : "personer"})`}
          </span>
        </div>
        {remaining > 0 ? (
          <span style={{ fontSize: 12, color: "var(--hv-fg-3)" }}>{remaining} igjen</span>
        ) : (
          <span style={{ fontSize: 12, color: "#f59e0b", fontWeight: 600 }}>Maks nådd</span>
        )}
      </div>

      {/* Kategorier som utvider seg ved klikk */}
      <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
        {builder.categories.map(cat => {
          const isOpen = openCat === cat.id;
          const catSelected = Object.values(selected).filter(s => s.catId === cat.id).length;
          return (
            <div key={cat.id} style={{
              border: `1px solid ${isOpen ? "rgba(65,193,186,0.4)" : "var(--hv-line)"}`,
              borderRadius: 12, overflow: "hidden",
              background: isOpen ? "rgba(65,193,186,0.04)" : "transparent",
              transition: "border-color 260ms var(--hv-ease), background 260ms var(--hv-ease)",
            }}>
              <button
                type="button"
                onClick={() => setOpenCat(isOpen ? null : cat.id)}
                style={{
                  width: "100%", padding: "16px 18px", cursor: "pointer",
                  background: "none", border: "none", textAlign: "left",
                  display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12,
                  color: "var(--hv-fg-1)",
                }}
              >
                <div>
                  <div style={{ fontSize: 16, fontWeight: 700, fontFamily: "var(--hv-font-display)", marginBottom: 2 }}>
                    {cat.label}
                    {catSelected > 0 && <span style={{ marginLeft: 8, fontSize: 13, color: "var(--hv-teal)", fontWeight: 600 }}>· {catSelected} valgt</span>}
                  </div>
                  <div style={{ fontSize: 13, color: "var(--hv-fg-3)" }}>{cat.desc} · {cat.produkter.length} råvarer</div>
                </div>
                <span style={{
                  display: "inline-flex", alignItems: "center", justifyContent: "center",
                  width: 28, height: 28, borderRadius: "50%",
                  border: "1px solid var(--hv-line)",
                  color: "var(--hv-teal)", fontSize: 18, fontWeight: 400,
                  transition: "transform 260ms var(--hv-ease)",
                  transform: isOpen ? "rotate(45deg)" : "rotate(0)",
                  flexShrink: 0,
                }}>+</span>
              </button>
              {isOpen && (
                <div
                  ref={el => { if (el) panelRefs.current[cat.id] = el; }}
                  style={{ padding: "0 18px 18px", borderTop: "1px solid var(--hv-line)", paddingTop: 14, display: "flex", flexWrap: "wrap", gap: 8 }}
                >
                  {cat.produkter.map(prod => {
                    const key = cat.id + ":" + prod.navn;
                    const picked = !!selected[key];
                    const free = isFreeCat(cat.id);
                    const disabled = !picked && !free && remaining === 0;
                    return (
                      <button
                        key={prod.navn}
                        type="button"
                        data-prod-opt
                        onClick={() => !disabled && toggleProduct(cat.id, prod)}
                        disabled={disabled}
                        style={{
                          display: "inline-flex", alignItems: "center", gap: 8,
                          padding: "8px 14px", borderRadius: 999,
                          fontSize: 13, fontWeight: 500,
                          cursor: disabled ? "not-allowed" : "pointer",
                          background: picked ? "var(--hv-teal)" : "transparent",
                          color: picked ? "var(--hv-ink)" : (disabled ? "var(--hv-fg-4)" : "var(--hv-fg-1)"),
                          border: `1px solid ${picked ? "var(--hv-teal)" : (disabled ? "var(--hv-line)" : "var(--hv-line)")}`,
                          opacity: disabled ? 0.5 : 1,
                          transition: "all 180ms var(--hv-ease)",
                          willChange: "transform, opacity",
                        }}
                      >
                        {picked && <span style={{ fontSize: 14, lineHeight: 1 }}>✓</span>}
                        {prod.navn}
                        {prod.pris > 0 && (
                          <span style={{ fontSize: 11, opacity: 0.7, fontFamily: "monospace", fontVariantNumeric: "tabular-nums" }}>
                            {prod.pris} kr/{cat.pricing === "perPerson" ? "pers" : "kg"}
                          </span>
                        )}
                      </button>
                    );
                  })}
                </div>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
};

// Favoritt-hjerte på PDP: synkes mot Flask hvis bruker er innlogget (har nw_customer_email)
const FavoriteHeart = ({ slug }) => {
  const [isFav, setIsFav] = React.useState(false);
  const [email, setEmail] = React.useState(() => localStorage.getItem("nw_customer_email") || "");

  React.useEffect(() => {
    if (!email) return;
    const base = window.HV_API_BASE || "";
    fetch(`${base}/api/customer/account?email=${encodeURIComponent(email)}`, { cache: "no-store" })
      .then(r => r.json()).then(d => setIsFav((d.favorites || []).includes(slug)))
      .catch(() => {});
  }, [email, slug]);

  const toggle = async () => {
    if (!email) {
      const em = prompt("Oppgi e-posten din for å lagre favoritter:");
      if (!em || !em.includes("@")) return;
      localStorage.setItem("nw_customer_email", em.trim().toLowerCase());
      setEmail(em.trim().toLowerCase());
    }
    const currEmail = localStorage.getItem("nw_customer_email");
    try {
      const base = window.HV_API_BASE || "";
      const r = await fetch(`${base}/api/customer/favorites`, {
        method: "POST", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email: currEmail, slug, action: "toggle" }),
      });
      const d = await r.json();
      if (r.ok) setIsFav((d.favorites || []).includes(slug));
    } catch (e) {}
  };

  return (
    <button type="button" onClick={toggle} aria-label="Favoritt"
      style={{ display: "inline-flex", alignItems: "center", gap: 6, padding: "4px 10px", borderRadius: 999,
        background: "transparent", border: `1px solid ${isFav ? "#ef4444" : "var(--hv-line)"}`,
        color: isFav ? "#ef4444" : "var(--hv-fg-3)", fontSize: 13, cursor: "pointer",
        transition: "all 200ms var(--hv-ease)" }}>
      {isFav ? "♥" : "♡"} {isFav ? "Favoritt" : "Legg til favoritt"}
    </button>
  );
};

const OPT_LABELS = {
  vekt: "Vekt", snitt: "Snitt", bein: "Bein", skinn: "Skinn",
  smak: "Smak", antall: "Antall", personer: "Personer", pers: "Antall personer",
  is: "Is", tilbehor: "Tilbehør",
};

function parseGrams(s) {
  if (!s) return null;
  const m = String(s).toLowerCase().replace(",", ".").match(/^\s*([\d.]+)\s*(g|kg)?\s*$/);
  if (!m) return null;
  const n = parseFloat(m[1]);
  return (m[2] === "kg" ? Math.round(n * 1000) : Math.round(n));
}

function formatGrams(g) {
  let s;
  if (g >= 1000) {
    const kg = g / 1000;
    s = (Number.isInteger(kg) ? String(kg) : String(kg).replace(".", ",")) + " kg";
  } else {
    s = `${g} g`;
  }
  return "ca. " + s;
}

// Beregn multiplikator fra en "antall"/"personer"-verdi.
// For sushi: "24 biter" på et produkt der unitLabel inneholder "(12 biter)" → 24/12 = 2.
// For andre: parseInt (f.eks. "2" → 2, "Egendefinert" → customPersoner).
function computeMult(raw, p, customPersoner) {
  if (raw === "Egendefinert") return Math.max(2, parseInt(customPersoner, 10) || 2);
  if (typeof raw !== "string") return 1;
  const rawBites = raw.match(/^(\d+)\s*biter$/);
  const unitBites = (p.unitLabel || "").match(/\((\d+)\s*biter\)/);
  if (rawBites && unitBites) {
    const r = parseInt(rawBites[1], 10) / parseInt(unitBites[1], 10);
    return r > 0 ? r : 1;
  }
  return parseInt(raw, 10) || 1;
}

const PDP = ({ slug, goShop, goPDP, addToCart }) => {
  const p = PRODUCTS.find(x => x.slug === slug) || PRODUCTS[0];
  const [qty, setQty] = React.useState(1);

  // Valgt variant per option-nøkkel (vekt/snitt/bein/skinn/...)
  const initOpts = React.useCallback(() => {
    const init = {};
    if (p.options) for (const [k, vals] of Object.entries(p.options)) init[k] = vals[0];
    return init;
  }, [p.slug]);
  const [selectedOpts, setSelectedOpts] = React.useState(initOpts);
  React.useEffect(() => { setSelectedOpts(initOpts()); setQty(1); }, [p.slug]);

  const pickOpt = (key, val) => setSelectedOpts(prev => ({ ...prev, [key]: val }));

  const related = PRODUCTS.filter(x => x.cat === p.cat && x.slug !== p.slug && x.status !== "hidden" && !x.deleted).slice(0, 3);

  // Egendefinert vekt (gram) når brukeren velger "Egendefinert"
  const [customGrams, setCustomGrams] = React.useState(500);
  // Egendefinert antall personer (min 2)
  const [customPersoner, setCustomPersoner] = React.useState(8);

  // Custom-box bygger (for din-skalldyrkasse osv.) — key = catId:navn → { catId, navn, pris }
  const [boxSelection, setBoxSelection] = React.useState({});
  // Tilbakestill box-utvalget når produktet endres
  React.useEffect(() => { setBoxSelection({}); }, [p.slug]);

  // ── Beregn pris og vekt for valgt variant ────────────────────────────────
  const isFishLike = p.kind === "fish" || p.kind === "shellfish";
  const isCustom = selectedOpts.vekt === "Egendefinert";
  const selGrams = isCustom ? Math.max(50, parseInt(customGrams, 10) || 0) : parseGrams(selectedOpts.vekt);
  const effGrams = selGrams || (isFishLike ? basePortion(p) : null);

  // Tillegg i kilopris basert på valg (mer arbeid → høyere pris)
  // Uten bein: +40 kr/kg, Uten skinn: +30 kr/kg
  const perKgSurcharge = (
    (selectedOpts.bein === "Uten bein" ? 40 : 0) +
    (selectedOpts.skinn === "Uten skinn" ? 30 : 0)
  );
  const effectiveKgPrice = p.price + (isFishLike ? perKgSurcharge : 0);

  let unitPrice, unitLabel, unitSuffix;
  if (isFishLike) {
    const g = effGrams || 1000;
    unitPrice = Math.round((effectiveKgPrice * g) / 1000);
    unitLabel = formatGrams(g);
    unitSuffix = "kg";
  } else if (p.customBuilder) {
    // Prisen for custom-bygget kasse:
    // Hver person får 600 g totalt per kategori (skalldyr og skjell hver for seg).
    // Mengden fordeles likt mellom de artene som er valgt innen kategorien.
    // Tilbehør (countTowardCap: false) bidrar ikke.
    const raw = selectedOpts.personer ?? selectedOpts.antall;
    const mult = computeMult(raw, p, customPersoner);
    const KG_PER_PERSON_PER_CAT = 0.6;  // 600 g per person per kategori
    const selValues = Object.values(boxSelection);
    let artsSum = 0;
    for (const cat of p.customBuilder.categories) {
      const itemsInCat = selValues.filter(s => s.catId === cat.id);
      if (itemsInCat.length === 0) continue;
      if (cat.pricing === "perPerson") {
        // Tilbehør: flat pris per person (f.eks. Brød 50 kr × personer)
        for (const item of itemsInCat) {
          artsSum += (item.pris || 0) * mult;
        }
      } else {
        // Skalldyr/Skjell: 600 g per person per kategori, splittes likt mellom valgte arter
        const kgPerArt = KG_PER_PERSON_PER_CAT / itemsInCat.length;
        for (const item of itemsInCat) {
          artsSum += (item.pris || 0) * kgPerArt * mult;
        }
      }
    }
    unitPrice = Math.round(artsSum);
    unitLabel = `${mult} ${mult === 1 ? "person" : "personer"}`;
    unitSuffix = p.unitLabel || "kasse";
  } else {
    // `personer` og `antall` brukes om hverandre som multiplikator
    const raw = selectedOpts.personer ?? selectedOpts.antall;
    const mult = computeMult(raw, p, customPersoner);
    unitPrice = p.price * mult;
    unitLabel = mult > 1 ? `${mult} ${p.unitLabel || "stk"}` : (p.unitLabel || "stk");
    unitSuffix = p.unitLabel || "stk";
  }

  const totalPrice = unitPrice * qty;
  const totalLabel = (() => {
    if (isFishLike) return formatGrams((effGrams || 1000) * qty);
    const raw = selectedOpts.personer ?? selectedOpts.antall;
    const mult = computeMult(raw, p, customPersoner);
    const count = qty * mult;
    let label = p.unitLabel || "stk";
    // Sushi-pakker: vis kun totalt antall biter (ikke "X pakker")
    const biterMatch = label.match(/\((\d+)\s*biter\)/);
    if (biterMatch) {
      const biterPerPack = parseInt(biterMatch[1], 10);
      return `${biterPerPack * count} biter`;
    }
    if (count !== 1 && label.startsWith("pakke")) {
      label = "pakker" + label.slice(5);
    }
    return `${count} ${label}`;
  })();

  return (
    <>
      <Wrap style={{ paddingTop: 40 }}>
        <div style={{ display: "flex", gap: 8, fontSize: 13, color: "var(--hv-fg-3)", marginBottom: 32 }}>
          <button onClick={goShop}>Butikk</button>
          <span>/</span>
          <button onClick={() => { window.__shopInitCat = p.cat; goShop(); }}>{p.cat}</button>
          <span>/</span>
          <span style={{ color: "var(--hv-fg-1)" }}>{p.name}</span>
        </div>
        <div className="nw-pdp">
          <div className="nw-pdp-gallery">
            <div className="nw-pdp-main">
              <img src={p.img} alt={p.name} />
            </div>
          </div>
          <div>
            <div className="nw-pdp-meta" style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
              {p.wild && <span className="nw-badge nw-badge-fresh">Villfanget</span>}
              {p.tag && !(p.wild && p.tag === "Villfanget") && <span className="nw-badge nw-badge-fresh">{p.tag}</span>}
              <span className="nw-badge nw-badge-fresh" style={{ background: "transparent", border: "1px solid var(--hv-line)", color: "var(--hv-fg-2)" }}>{p.cat}</span>
              <FavoriteHeart slug={p.slug} />
            </div>
            <h1 className="nw-pdp-name">{p.name}</h1>
            {p.customBuilder ? (
              (() => {
                const hasSelection = Object.values(boxSelection).some(s => {
                  const cat = p.customBuilder.categories.find(c => c.id === s.catId);
                  return cat && cat.countTowardCap !== false;
                });
                return hasSelection ? (
                  <div className="nw-pdp-price">{unitPrice} kr<span className="unit">/ {unitSuffix}</span></div>
                ) : (
                  <div className="nw-pdp-price" style={{ opacity: 0.7, fontSize: "clamp(20px, 2.4vw, 28px)" }}>
                    Velg innhold for å se pris
                  </div>
                );
              })()
            ) : (
              <div className="nw-pdp-price">{effectiveKgPrice} kr<span className="unit">/ {unitSuffix}</span></div>
            )}
            <p className="nw-pdp-desc">{p.desc}</p>
            {p.options && (
              <div className="nw-pdp-options" style={{ marginBottom: 24 }}>
                {Object.entries(p.options).map(([key, vals]) => {
                  const isWeightGroup = key === "vekt" && isFishLike;
                  const isPersonerGroup = key === "personer" || key === "antall";
                  const chipValues = (isWeightGroup || isPersonerGroup) ? [...vals, "Egendefinert"] : vals;
                  return (
                    <div key={key} style={{ marginBottom: 14 }}>
                      <div style={{ fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.12em", color: "var(--hv-fg-3)", marginBottom: 8, display: "flex", alignItems: "center", gap: 8 }}>
                        {OPT_LABELS[key] || key}
                        {isWeightGroup && (
                          <span style={{ fontSize: 10, fontWeight: 500, textTransform: "none", letterSpacing: 0, color: "var(--hv-fg-3)", opacity: 0.8 }}>
                            ⓘ omtrentlige vekter
                          </span>
                        )}
                      </div>
                      <div style={{ display: "flex", gap: 8, flexWrap: "wrap", alignItems: "center" }}>
                        {chipValues.map(v => {
                          const surcharge = (key === "bein" && v === "Uten bein") ? 40
                            : (key === "skinn" && v === "Uten skinn") ? 30 : 0;
                          const label = isWeightGroup && v !== "Egendefinert" ? `ca. ${v}` : v;
                          return (
                            <button
                              key={v}
                              type="button"
                              className={"nw-kalk-chip" + (selectedOpts[key] === v ? " active" : "")}
                              style={{ fontSize: 13, cursor: "pointer" }}
                              onClick={() => pickOpt(key, v)}
                            >
                              {label}
                              {surcharge > 0 && <span style={{ marginLeft: 6, opacity: 0.7, fontSize: 11 }}>+{surcharge} kr/kg</span>}
                            </button>
                          );
                        })}
                        {isWeightGroup && selectedOpts[key] === "Egendefinert" && (
                          <div style={{ display: "inline-flex", alignItems: "center", gap: 6, marginLeft: 4 }}>
                            <span style={{ fontSize: 13, color: "var(--hv-fg-3)" }}>ca.</span>
                            <input
                              type="number"
                              min="50"
                              step="50"
                              value={customGrams}
                              onChange={e => setCustomGrams(e.target.value)}
                              style={{
                                width: 90,
                                padding: "8px 10px",
                                border: "1px solid var(--hv-teal)",
                                borderRadius: 999,
                                background: "transparent",
                                color: "var(--hv-fg-1)",
                                fontSize: 13,
                                fontFamily: "var(--hv-font-body)",
                                outline: "none",
                                textAlign: "center",
                              }}
                            />
                            <span style={{ fontSize: 13, color: "var(--hv-fg-3)" }}>gram</span>
                          </div>
                        )}
                        {isPersonerGroup && selectedOpts[key] === "Egendefinert" && (
                          <div style={{ display: "inline-flex", alignItems: "center", gap: 6, marginLeft: 4 }}>
                            <input
                              type="number"
                              min="2"
                              step="1"
                              value={customPersoner}
                              onChange={e => setCustomPersoner(e.target.value)}
                              onBlur={e => {
                                const v = parseInt(e.target.value, 10);
                                if (!v || v < 2) setCustomPersoner(2);
                              }}
                              style={{
                                width: 80,
                                padding: "8px 10px",
                                border: "1px solid var(--hv-teal)",
                                borderRadius: 999,
                                background: "transparent",
                                color: "var(--hv-fg-1)",
                                fontSize: 13,
                                fontFamily: "var(--hv-font-body)",
                                outline: "none",
                                textAlign: "center",
                              }}
                            />
                            <span style={{ fontSize: 13, color: "var(--hv-fg-3)" }}>personer (min 2)</span>
                          </div>
                        )}
                      </div>
                    </div>
                  );
                })}
              </div>
            )}
            {p.customBuilder && (() => {
              const raw = selectedOpts.personer ?? selectedOpts.antall;
              const mult = raw === "Egendefinert"
                ? Math.max(2, parseInt(customPersoner, 10) || 2)
                : (parseInt(raw, 10) || 1);
              return (
                <CustomBoxBuilder
                  builder={p.customBuilder}
                  antall={mult}
                  selected={boxSelection}
                  setSelected={setBoxSelection}
                />
              );
            })()}
            <div className="nw-pdp-facts">
              <div className="nw-pdp-fact"><span className="k">Opprinnelse</span><span className="v">{p.origin}</span></div>
              {!p.options?.vekt && p.weight && (
                <div className="nw-pdp-fact"><span className="k">Porsjon</span><span className="v">{p.weight}</span></div>
              )}
              <div className="nw-pdp-fact"><span className="k">Holdbarhet</span><span className="v">{p.shelf}</span></div>
              <div className="nw-pdp-fact"><span className="k">Pakket</span><span className="v">{p.packed}</span></div>
            </div>
            <div className="nw-pdp-add">
              {(() => {
                const hasCountingSelection = !p.customBuilder || Object.values(boxSelection).some(s => {
                  const cat = p.customBuilder.categories.find(c => c.id === s.catId);
                  return cat && cat.countTowardCap !== false;
                });
                if (!hasCountingSelection) {
                  return (
                    <Btn size="lg" onClick={() => {}} style={{ opacity: 0.5, pointerEvents: "none" }}>
                      Velg råvarer først
                    </Btn>
                  );
                }
                return (
                  <Btn size="lg" onClick={() => addToCart({ ...p, price: unitPrice, selectedOpts, variantLabel: unitLabel, boxSelection: Object.values(boxSelection) }, qty)}>
                    Legg i kurv
                    <Dash/>
                    <span style={{ fontWeight: 700 }}>{totalLabel}</span>
                    <span style={{ fontSize: "0.78em", fontWeight: 600, opacity: 0.85, marginLeft: "0.5em" }}>
                      <Price amount={totalPrice}/>
                    </span>
                  </Btn>
                );
              })()}
            </div>
            <div style={{ display: "flex", gap: 16, alignItems: "center", fontSize: 13, color: "var(--hv-fg-3)", marginTop: 20 }}>
              <span style={{ display: "flex", alignItems: "center", gap: 8 }}><Truck size={16} style={{ color: "var(--hv-teal)" }} /> Leveres Bergen alle hverdager kl. 13–18</span>
              <span style={{ display: "flex", alignItems: "center", gap: 8 }}><Check size={16} style={{ color: "var(--hv-ok)" }}/> På lager · 4 igjen</span>
            </div>
          </div>
        </div>
      </Wrap>
      <PDPReviews slug={p.slug} productName={p.name} />
      <PDPFaq slug={p.slug} />
      <Section>
        <Wrap>
          <div className="nw-section-head">
            <div>
              <Eyebrow>Ogs&aring; i {p.cat}</Eyebrow>
              <h2 className="nw-h2" style={{ marginTop: 16 }}>Kanskje du vil ha</h2>
            </div>
          </div>
          <div className="nw-pgrid">
            {related.map(rp => (
              <div className="nw-pcard" key={rp.slug} onClick={() => goPDP(rp.slug)}>
                <div className="nw-pcard-media"><img src={rp.img} alt={rp.name}/></div>
                <div className="nw-pcard-body">
                  <div className="nw-pcard-cat">{rp.cat}</div>
                  <div className="nw-pcard-name">{rp.name}</div>
                  <div className="nw-pcard-foot">
                    <Price amount={rp.price} unit={rp.unit}/>
                    <ArrowRight size={16} style={{ color: "var(--hv-teal)" }}/>
                  </div>
                </div>
              </div>
            ))}
          </div>
        </Wrap>
      </Section>
    </>
  );
};

Object.assign(window, { Shop, PDP });
