const { useState: usePsCloudState, useMemo: usePsCloudMemo } = React;

function psCloudRand(seed) { let s = seed >>> 0; return () => { s = (s * 1664525 + 1013904223) >>> 0; return s / 4294967296; }; }

const PS_SCALE = { frequency: [1.42, 1.46], needmax: [1, 1], spg: [1, 1], pulse: [1, 1], 'gaian-no8': [0.74, 1.1] };
const PS_AR = 0.62; // színpad magasság/szélesség arány az egységtérhez

function psCloudScatter(n, seed, ex) {
  const rnd = psCloudRand(seed);
  let minD = 6.4, pts = [];
  for (let pass = 0; pass < 14 && pts.length < n; pass++) {
    pts = [];
    const r2 = minD * minD;
    let guard = 0;
    while (pts.length < n && guard < 90000) {
      guard++;
      const x = 2.5 + rnd() * 95, y = 3 + rnd() * 94;
      if (x > ex.x0 && x < ex.x1 && y > ex.y0 && y < ex.y1) continue;
      if (x < 40 && y > 84) continue;
      let ok = true;
      for (const p of pts) { const dx = p.x - x, dy = (p.y - y) * PS_AR; if (dx * dx + dy * dy < r2) { ok = false; break; } }
      if (ok) pts.push({ x, y });
    }
    if (pts.length < n) minD = Math.max(3.6, minD - 0.25);
  }
  const r2 = psCloudRand(seed + 11);
  return pts.slice(0, n).map((p) => ({ ...p, s: 0.85 + r2() * 0.3, d: r2() * -22, t: 16 + r2() * 12, dir: r2() > 0.5 ? 1 : -1 }));
}

function psCloudMesh(pts, k) {
  const seen = {}, edges = [];
  pts.forEach((p, i) => {
    pts.map((q, j) => ({ j, d: (p.x - q.x) ** 2 + ((p.y - q.y) * PS_AR) ** 2 })).filter((o) => o.j !== i).sort((a, b) => a.d - b.d).slice(0, k)
      .forEach(({ j }) => { const key = i < j ? i + '-' + j : j + '-' + i; if (!seen[key]) { seen[key] = 1; edges.push([i, j]); } });
  });
  return edges;
}

function psCloudOrbits(data, hubs) {
  const out = {};
  data.products.forEach((p) => {
    const idx = data.items.map((it, i) => (it.p.includes(p.id) ? i : -1)).filter((i) => i >= 0);
    const hub = hubs[p.id], map = {};
    const rings = [
      { rx: 11.5, ry: 19, cap: 10 },
      { rx: 17.5, ry: 29, cap: 14 },
      { rx: 23.5, ry: 39, cap: 20 },
    ];
    let k = 0;
    rings.forEach((ring, ri) => {
      const rest = idx.length - k;
      const take = ri === rings.length - 1 ? rest : Math.min(ring.cap, Math.ceil(rest / (rings.length - ri)));
      for (let j = 0; j < take && k < idx.length; j++, k++) {
        const a = (j / take) * Math.PI * 2 + ri * 0.5 - Math.PI / 2;
        map[idx[k]] = {
          x: Math.max(3.5, Math.min(96.5, hub.x + Math.cos(a) * ring.rx)),
          y: Math.max(5, Math.min(95, hub.y + 6 + Math.sin(a) * ring.ry)),
        };
      }
    });
    out[p.id] = map;
  });
  return out;
}

function IngredientCloud() {
  const data = window.PS_CLOUD;
  const [hover, setHover] = usePsCloudState(null);
  const [prod, setProd] = usePsCloudState(null);
  const stageRef = React.useRef(null);
  const [ex, setEx] = usePsCloudState({ x0: 15, x1: 85, y0: 17, y1: 56 });
  const last = React.useRef(null);
  React.useLayoutEffect(() => {
    const el = stageRef.current; if (!el) return;
    const calc = () => {
      const r = el.getBoundingClientRect(); if (!r.width) return;
      const bs = Array.prototype.slice.call(el.querySelectorAll('.ps-net-prod')).map((b) => b.getBoundingClientRect()).filter((b) => b.width);
      if (!bs.length) return;
      const nx = (v) => ((v - r.left) / r.width) * 100, ny = (v) => ((v - r.top) / r.height) * 100;
      const box = {
        x0: nx(Math.min.apply(null, bs.map((b) => b.left))) - 2.5,
        x1: nx(Math.max.apply(null, bs.map((b) => b.right))) + 2.5,
        y0: ny(Math.min.apply(null, bs.map((b) => b.top))) - 3,
        y1: ny(Math.max.apply(null, bs.map((b) => b.bottom))) + 3.5,
      };
      const same = last.current && Math.abs(last.current.x0 - box.x0) < 0.7 && Math.abs(last.current.x1 - box.x1) < 0.7 && Math.abs(last.current.y0 - box.y0) < 0.7 && Math.abs(last.current.y1 - box.y1) < 0.7;
      if (same) return;
      last.current = box;
      setEx(box);
    };
    calc();
    let raf = 0;
    const queue = () => { cancelAnimationFrame(raf); raf = requestAnimationFrame(calc); };
    const ro = new ResizeObserver(queue);
    ro.observe(el);
    Array.prototype.slice.call(el.querySelectorAll('.ps-net-prod')).forEach((b) => ro.observe(b));
    window.addEventListener('resize', calc);
    const t = setTimeout(calc, 900);
    return () => { ro.disconnect(); window.removeEventListener('resize', calc); clearTimeout(t); cancelAnimationFrame(raf); };
  }, []);
  const pts = usePsCloudMemo(() => psCloudScatter(data.items.length, 20260807, ex), [data.items.length, ex]);
  const edges = usePsCloudMemo(() => psCloudMesh(pts, 2), [pts]);
  const hubs = usePsCloudMemo(() => {
    const n = data.products.length, gap = 13;
    const o = {}; data.products.forEach((p, i) => { o[p.id] = { x: 50 + (i - (n - 1) / 2) * gap, y: 52 }; });
    return o;
  }, [data.products]);
  const orbits = usePsCloudMemo(() => psCloudOrbits(data, hubs), [data, hubs]);
  const at = (i) => (prod && orbits[prod][i]) || pts[i];
  const active = hover != null ? data.items[hover] : null;
  const meta = (active && window.INGREDIENTS && window.INGREDIENTS[active.n]) || {};
  const initials = (s) => s.replace(/\(.*?\)/g, '').trim().split(/\s+/).map((w) => w[0]).join('').slice(0, 3).toUpperCase();
  const sigOf = (pid) => (data.products.find((p) => p.id === pid) || {}).sig;
  const sel = prod ? sigOf(prod) : null;

  return (
    <section id="osszetevok" data-screen-label="Összetevő-hálózat" style={{ position: 'relative', background: 'var(--bg)', borderBottom: '1px solid var(--line)', padding: 'var(--sp-10) var(--gutter)' }}>
      <style dangerouslySetInnerHTML={{ __html: `
.ps-net-stage{position:relative;max-width:var(--container);margin:0 auto;background:var(--ink-900);border:1px solid var(--line-gold);overflow:hidden;aspect-ratio:1/.68;min-height:520px}
.ps-net-edges{position:absolute;inset:0;width:100%;height:100%;z-index:1;pointer-events:none;filter:drop-shadow(0 0 4px rgba(198,168,104,.4))}
.ps-net-edges line{stroke:rgba(210,180,116,.52);stroke-width:1.15;vector-effect:non-scaling-stroke;transition:stroke 400ms ease,stroke-width 400ms ease,opacity 400ms ease}
.ps-net-edges line.lit{stroke-width:1.6;stroke:rgba(224,196,126,.72)}
.ps-net-edges line.faded{opacity:.2}
.ps-net-node{position:absolute;z-index:6;transition:opacity 320ms ease,left 820ms cubic-bezier(.16,1,.3,1),top 820ms cubic-bezier(.16,1,.3,1)}
.ps-net-node.orbit{z-index:18}
.ps-net-node.dim{opacity:.16}
.ps-net-node.on{z-index:24}
.ps-net-prod:hover .ps-net-shot img{filter:drop-shadow(0 30px 58px rgba(0,0,0,.85)) drop-shadow(0 0 26px rgba(198,168,104,.5))}
.ps-net-prod .hintline{font-family:var(--font-sans);font-size:9px;letter-spacing:.2em;color:rgba(198,168,104,.75);opacity:0;transition:opacity 280ms ease}
.ps-net-prod:hover .hintline{opacity:1}
.ps-net-prod.sel .hintline{opacity:1;color:var(--gold-bright)}
.ps-net-orb{position:absolute;transform:translate(-50%,-50%);width:var(--d);height:var(--d);border-radius:50%;overflow:hidden;border:1px solid rgba(198,168,104,.42);background:#101217;cursor:help;transition:width 260ms cubic-bezier(.16,1,.3,1),height 260ms cubic-bezier(.16,1,.3,1),border-color 260ms ease,box-shadow 260ms ease}
.ps-net-orb img{width:100%;height:100%;object-fit:cover;display:block}
.ps-net-orb .mono{display:flex;align-items:center;justify-content:center;width:100%;height:100%;font-family:var(--font-sans);font-size:11px;letter-spacing:.1em;color:var(--accent)}
.ps-net-node.on .ps-net-orb{width:calc(var(--d) * 3.1);height:calc(var(--d) * 3.1);border-color:var(--gold-bright);box-shadow:0 0 0 3px rgba(198,168,104,.35),0 24px 60px -18px #000,0 0 60px rgba(198,168,104,.3)}
.ps-net-drift{animation:psNetDrift linear infinite}
@keyframes psNetDrift{0%,100%{transform:translate(0,0)}25%{transform:translate(6px,-9px)}50%{transform:translate(-5px,-4px)}75%{transform:translate(-7px,7px)}}
.ps-net-node.on .ps-net-drift{animation-play-state:paused}
.ps-net-tip{position:absolute;top:50%;transform:translateY(-50%);width:250px;background:rgba(11,12,14,.96);border:1px solid var(--line-gold);padding:16px 18px;pointer-events:none;box-shadow:0 30px 70px -24px #000}
.ps-net-tip.r{left:calc(var(--d) * 1.75 + 14px)}
.ps-net-tip.l{right:calc(var(--d) * 1.75 + 14px)}
.ps-net-tip.up{top:auto;bottom:calc(var(--d) * -0.9);transform:none}
.ps-net-tip.down{top:calc(var(--d) * -0.9);bottom:auto;transform:none}
.ps-net-tip-h{font-family:var(--font-display,var(--font-sans));font-size:1.22rem;line-height:1.2;color:var(--gold-bright);font-weight:300}
.ps-net-tip-dose{margin-top:5px;font-family:var(--font-sans);font-size:10.5px;letter-spacing:.2em;color:rgba(233,227,214,.6)}
.ps-net-tip-note{margin:11px 0 0;font-family:var(--font-sans);font-size:.82rem;line-height:1.55;color:rgba(233,227,214,.9)}
.ps-net-tip-in{display:flex;flex-wrap:wrap;gap:7px 12px;margin-top:13px;padding-top:10px;border-top:1px solid rgba(198,168,104,.25)}
.ps-net-chip{display:flex;align-items:center;gap:6px;font-family:var(--font-sans);font-size:9px;letter-spacing:.16em;color:rgba(233,227,214,.72)}
.ps-net-chip i{width:7px;height:7px;border-radius:50%;display:block}
.ps-net-prod{position:absolute;transform:translate(-50%,-100%);transform-origin:50% 100%;display:flex;flex-direction:column;align-items:center;gap:6px;background:none;border:none;cursor:pointer;padding:0;z-index:14;transition:transform 320ms cubic-bezier(.16,1,.3,1),opacity 300ms ease}
.ps-net-prod:hover,.ps-net-prod.sel{transform:translate(-50%,-100%) scale(1.05)}
.ps-net-prod.off{opacity:.3}
.ps-net-shot{position:relative;width:calc(clamp(62px,8vw,124px) * var(--sw,1));height:calc(clamp(132px,17.5vw,254px) * var(--sh,1));overflow:hidden;display:block}
.ps-net-shot img{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);height:104%;width:auto;max-width:none;display:block;filter:drop-shadow(0 30px 58px rgba(0,0,0,.85))}
.ps-net-prod.sel .ps-net-shot img{animation:psProdGlow 2.1s ease-in-out infinite}
.ps-net-prod.sel::before{content:"";position:absolute;left:50%;top:40%;width:150%;aspect-ratio:1;transform:translate(-50%,-50%);border-radius:50%;background:radial-gradient(circle,rgba(198,168,104,.28),rgba(198,168,104,.08) 42%,transparent 70%);animation:psHaloPulse 2.1s ease-in-out infinite;pointer-events:none;z-index:-1}
@keyframes psProdGlow{0%,100%{filter:drop-shadow(0 30px 58px rgba(0,0,0,.85)) drop-shadow(0 0 14px rgba(198,168,104,.35))}50%{filter:drop-shadow(0 30px 58px rgba(0,0,0,.85)) drop-shadow(0 0 44px rgba(224,196,126,.85))}}
@keyframes psHaloPulse{0%,100%{opacity:.5;transform:translate(-50%,-50%) scale(.94)}50%{opacity:1;transform:translate(-50%,-50%) scale(1.06)}}
@keyframes psOrbGlow{0%,100%{box-shadow:0 0 0 1px rgba(198,168,104,.4),0 0 10px rgba(198,168,104,.25);border-color:rgba(198,168,104,.5)}50%{box-shadow:0 0 0 2px rgba(224,196,126,.7),0 0 30px rgba(224,196,126,.6);border-color:var(--gold-bright)}}
.ps-net-orb.glow{animation:psOrbGlow 2.1s ease-in-out infinite}
.ps-net-prod .nm{font-family:var(--font-sans);font-size:clamp(9.5px,.92vw,13px);letter-spacing:.16em;color:var(--bone-100);white-space:nowrap;background:rgba(11,12,14,.94);padding:6px 12px;border:1px solid rgba(198,168,104,.32)}
.ps-net-prod .ct{font-family:var(--font-sans);font-size:10px;letter-spacing:.18em;background:rgba(11,12,14,.94);padding:3px 9px}
.ps-net-prod .bar{width:34px;height:3px}
.ps-net-meta{position:absolute;left:clamp(14px,2vw,26px);bottom:clamp(12px,1.6vw,20px);z-index:30;font-family:var(--font-sans);font-size:12.5px;letter-spacing:.22em;color:var(--bone-100);background:#0b0c0e;border:1px solid rgba(198,168,104,.5);padding:9px 16px;pointer-events:none;box-shadow:0 18px 40px -14px #000}
@media (max-width:900px){.ps-net-stage{aspect-ratio:1/1.1;min-height:600px}.ps-net-tip{width:200px;padding:12px 14px}.ps-net-tip-h{font-size:1rem}.ps-net-tip-note{font-size:.76rem}.ps-net-prod{gap:6px}}
@media (prefers-reduced-motion: reduce){.ps-net-drift,.ps-net-orb.glow,.ps-net-prod.sel .ps-net-shot img,.ps-net-prod.sel::before{animation:none}}
`}} />
      <div style={{ maxWidth: 820, margin: '0 auto var(--sp-8)' }}>
        <Eyebrow gold style={{ marginBottom: 18 }}>A VÁLASZ SZERKEZETE</Eyebrow>
        <h2 className="ps-h1" style={{ margin: '0 0 16px' }}>Erre a komplexitásra nem lehet <em style={{ fontStyle: 'italic', color: 'var(--accent)' }}>egyetlen összetevővel</em> válaszolni.</h2>
        <p className="ps-lead" style={{ margin: 0, color: 'var(--fg-2)', maxWidth: 660 }}>Öt formula, <span style={{ color: 'var(--accent)' }}>{data.total} összetevő</span> — nem lista, hanem hálózat. <span style={{ color: 'var(--accent)' }}>Kattints egy termékre</span>, és látod, mi tartozik hozzá.</p>
      </div>

      <div className="ps-net-stage" ref={stageRef} onMouseLeave={() => setHover(null)}>
        <svg className="ps-net-edges" viewBox="0 0 100 100" preserveAspectRatio="none" aria-hidden="true">
          {edges.map(([a, b], i) => {
            const A = data.items[a], B = data.items[b];
            const lit = prod ? A.p.includes(prod) && B.p.includes(prod) : active ? A === active || B === active : false;
            return <line key={i} className={lit ? 'lit' : (prod || active) ? 'faded' : ''} style={lit && sel ? { stroke: sel } : undefined}
              x1={at(a).x} y1={at(a).y} x2={at(b).x} y2={at(b).y} />;
          })}
          {prod && data.items.map((it, i) => it.p.includes(prod) ? (
            <line key={'h' + i} className="lit" style={{ stroke: sel, strokeDasharray: '2 4', opacity: 0.7 }}
              x1={hubs[prod].x} y1={hubs[prod].y + 6} x2={at(i).x} y2={at(i).y} />
          ) : null)}
          {active && active.p.map((pid) => (
            <line key={'a' + pid} className="lit" style={{ stroke: sigOf(pid), strokeDasharray: '2 4' }}
              x1={hubs[pid].x} y1={hubs[pid].y + 6} x2={at(data.items.indexOf(active)).x} y2={at(data.items.indexOf(active)).y} />
          ))}
        </svg>

        {data.items.map((it, i) => {
          const p = pts[i], q = at(i), sz = Math.round(34 * p.s);
          const dim = (prod && !it.p.includes(prod)) || (active && active !== it);
          const inOrbit = !!(prod && it.p.includes(prod));
          const side = (q.x > 55 ? 'l' : 'r') + (q.y > 74 ? ' up' : q.y < 26 ? ' down' : '');
          return (
            <div key={it.n} className={'ps-net-node' + (active === it ? ' on' : '') + (dim ? ' dim' : '') + (inOrbit ? ' orbit' : '')} style={{ left: q.x + '%', top: q.y + '%' }}>
              <div className={'ps-net-drift'} style={{ animationDuration: p.t + 's', animationDelay: p.d + 's', animationDirection: p.dir > 0 ? 'normal' : 'reverse' }}>
                <div className={'ps-net-orb' + (prod && it.p.includes(prod) ? ' glow' : '')} style={{ '--d': sz + 'px', animationDelay: (i % 12) * -0.17 + 's' }} onMouseEnter={() => setHover(i)} onMouseLeave={() => setHover(null)}>
                  {it.img ? <img src={it.img} alt={it.n} loading="lazy" /> : <span className="mono">{initials(it.n)}</span>}
                </div>
                {active === it ? (
                  <div className={'ps-net-tip ' + side} style={{ '--d': sz + 'px' }}>
                    <div className="ps-net-tip-h">{it.n}</div>
                    {meta.dose ? <div className="ps-net-tip-dose">{meta.dose}</div> : null}
                    <p className="ps-net-tip-note">{meta.note || 'A leírás itt véget ér — a többi a tapasztalaté.'}</p>
                    <div className="ps-net-tip-in">
                      {it.p.map((pid) => {
                        const pr = data.products.find((x) => x.id === pid);
                        return <span key={pid} className="ps-net-chip"><i style={{ background: pr.sig }} />{pr.short}</span>;
                      })}
                    </div>
                  </div>
                ) : null}
              </div>
            </div>
          );
        })}

        {data.products.map((p) => (
          <button key={p.id} className={'ps-net-prod' + (prod === p.id ? ' sel' : '') + (prod && prod !== p.id ? ' off' : '')}
            style={{ left: hubs[p.id].x + '%', top: '86%', '--sw': PS_SCALE[p.id] ? PS_SCALE[p.id][0] : 1, '--sh': PS_SCALE[p.id] ? PS_SCALE[p.id][1] : 1 }}
            onClick={() => { setProd(prod === p.id ? null : p.id); setHover(null); }}>
            <span className="ps-net-shot"><img src={p.img} alt={p.name} /></span>
            <span className="bar" style={{ background: p.sig }} />
            <span className="nm">{p.short}</span>
            <span className="ct" style={{ color: p.sig }}>{p.count} ÖSSZETEVŐ</span>
            <span className="hintline">{prod === p.id ? 'KIVÁLASZTVA ×' : 'KATTINTS'}</span>
          </button>
        ))}

        <div className="ps-net-meta">{data.total} ÖSSZETEVŐ 5 FORMULÁBAN</div>
      </div>
    </section>
  );
}

Object.assign(window, { IngredientCloud });
