// Shared primitives for the Excelsa one-page site

const { useEffect, useRef, useState, useMemo, useCallback } = React;

/* ---------- Scroll reveal ---------- */
function Reveal({ children, delay = 0, className = "", as = "div", ...rest }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) { el.classList.add("in"); io.unobserve(el); } });
    }, { threshold: 0.12 });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  const Tag = as;
  const d = delay ? `d${delay}` : "";
  return <Tag ref={ref} className={`reveal ${d} ${className}`} {...rest}>{children}</Tag>;
}

/* ---------- Parallax hook: returns scrollY ---------- */
function useScrollY(){
  const [y, setY] = useState(0);
  useEffect(() => {
    let raf = 0;
    const onScroll = () => {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => setY(window.scrollY));
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => { window.removeEventListener("scroll", onScroll); cancelAnimationFrame(raf); };
  }, []);
  return y;
}

/* ---------- Parallax element ---------- */
function Parallax({ speed = 0.2, children, className = "", style = {}, ...rest }) {
  const ref = useRef(null);
  useEffect(() => {
    let raf = 0;
    const onScroll = () => {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        if (!ref.current) return;
        const rect = ref.current.getBoundingClientRect();
        const vh = window.innerHeight;
        const center = rect.top + rect.height / 2 - vh / 2;
        ref.current.style.transform = `translate3d(0, ${-center * speed}px, 0)`;
      });
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => { window.removeEventListener("scroll", onScroll); cancelAnimationFrame(raf); };
  }, [speed]);
  return <div ref={ref} className={className} style={style} {...rest}>{children}</div>;
}

/* ---------- Section shell ---------- */
function SectionHeader({ num, label, title, lede, align = "left" }){
  return (
    <div className="stack" style={{ textAlign: align, alignItems: align === "center" ? "center" : "flex-start", gap: 20 }}>
      <Reveal className="section-label"><span className="section-num">§ {num}</span><span style={{marginLeft:10}}>{label}</span></Reveal>
      <Reveal delay={1}><h2 className="display" dangerouslySetInnerHTML={{ __html: title }} /></Reveal>
      {lede && <Reveal delay={2}><p className="lede">{lede}</p></Reveal>}
    </div>
  );
}

/* ---------- Placeholder image box ---------- */
function Placeholder({ label, aspect = "4 / 3", style = {}, note }){
  return (
    <div className="placeholder" style={{ aspectRatio: aspect, ...style }}>
      <div className="ph-inner">
        <div>{label}</div>
        {note && <div style={{ marginTop: 8, opacity: 0.7, letterSpacing: 0.04, textTransform: "none" }}>{note}</div>}
      </div>
    </div>
  );
}

/* ---------- Stat block ---------- */
function Stat({ value, unit, label, note }){
  return (
    <div className="stack" style={{ gap: 8 }}>
      <div style={{ display:"flex", alignItems:"baseline", gap:6, fontFamily:"var(--serif)", lineHeight:1 }}>
        <span style={{ fontSize:"clamp(48px, 6vw, 84px)", fontWeight:500, letterSpacing:"-0.03em" }}>{value}</span>
        {unit && <span className="mono" style={{ fontSize:12, color:"var(--ink-3)", letterSpacing:"0.2em", textTransform:"uppercase" }}>{unit}</span>}
      </div>
      <div className="mono" style={{ fontSize:11, letterSpacing:"0.22em", textTransform:"uppercase", color:"var(--ink-3)" }}>{label}</div>
      {note && <div style={{ fontSize:14, color:"var(--ink-2)", maxWidth:"32ch" }}>{note}</div>}
    </div>
  );
}

/* ---------- Marquee ---------- */
function Marquee({ items, speed = 40, dark = false }){
  const content = items.concat(items);
  return (
    <div style={{
      overflow:"hidden",
      borderTop: `1px solid ${dark ? "rgba(244,237,225,0.2)" : "var(--line)"}`,
      borderBottom: `1px solid ${dark ? "rgba(244,237,225,0.2)" : "var(--line)"}`,
      padding: "22px 0",
      background: dark ? "var(--ink)" : "transparent",
      color: dark ? "var(--paper)" : "var(--ink)",
    }}>
      <div style={{
        display:"inline-flex", gap:48, whiteSpace:"nowrap",
        animation:`marquee ${speed}s linear infinite`,
      }}>
        {content.map((it, i) => (
          <span key={i} className="mono" style={{ fontSize: 13, letterSpacing:"0.18em", textTransform:"uppercase", display:"inline-flex", alignItems:"center", gap:24 }}>
            {it}
            <span style={{ opacity: 0.4 }}>✦</span>
          </span>
        ))}
      </div>
      <style>{`@keyframes marquee { from{transform:translateX(0)} to{transform:translateX(-50%)} }`}</style>
    </div>
  );
}

/* ---------- SVG: coffee leaf ---------- */
function Leaf({ size = 120, style = {}, fill = "var(--sage)", stroke = "var(--sage-2)" }){
  return (
    <svg viewBox="0 0 200 260" width={size} style={style} aria-hidden="true">
      <defs>
        <linearGradient id="leafG" x1="0" y1="0" x2="1" y2="1">
          <stop offset="0" stopColor={fill} stopOpacity="0.9" />
          <stop offset="1" stopColor={stroke} stopOpacity="0.9" />
        </linearGradient>
      </defs>
      <path d="M100 10 C 160 60, 180 140, 100 250 C 20 140, 40 60, 100 10 Z" fill="url(#leafG)" stroke={stroke} strokeWidth="1.2"/>
      <path d="M100 18 L100 246" stroke={stroke} strokeWidth="1" fill="none" opacity="0.6"/>
      {Array.from({length:9}).map((_,i)=>{
        const y = 40 + i*22;
        const dir = i%2===0 ? 1 : -1;
        return <path key={i} d={`M100 ${y} Q ${100 + dir*35} ${y+18}, ${100 + dir*70} ${y+30}`} stroke={stroke} strokeWidth="0.8" fill="none" opacity="0.55"/>;
      })}
    </svg>
  );
}

/* ---------- SVG: cherry ---------- */
function Cherry({ size = 80, style = {}, color = "var(--copper)" }){
  return (
    <svg viewBox="0 0 100 120" width={size} style={style} aria-hidden="true">
      <path d="M50 5 C 48 25, 42 35, 35 38" stroke="var(--sage-2)" strokeWidth="2" fill="none" strokeLinecap="round"/>
      <circle cx="50" cy="70" r="42" fill={color} />
      <ellipse cx="38" cy="55" rx="10" ry="6" fill="rgba(255,255,255,0.28)" />
      <circle cx="50" cy="70" r="42" fill="none" stroke="rgba(0,0,0,0.18)" strokeWidth="1"/>
    </svg>
  );
}

/* ---------- Full botanical illustration (SVG, hand-drawn feel) ---------- */
function BotanicalPlate({ width = "100%", height = 520 }){
  return (
    <svg viewBox="0 0 480 640" width={width} height={height} style={{ display:"block" }} aria-hidden="true">
      <defs>
        <filter id="rough" x="-5%" y="-5%" width="110%" height="110%">
          <feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" seed="4"/>
          <feDisplacementMap in="SourceGraphic" scale="0.8"/>
        </filter>
      </defs>
      <g stroke="var(--ink-2)" strokeWidth="0.8" fill="none" filter="url(#rough)">
        {/* main stem */}
        <path d="M240 620 C 235 500, 245 400, 240 300 C 235 220, 250 140, 240 60"/>
        {/* branches */}
        <path d="M240 520 Q 180 500, 120 470"/>
        <path d="M240 460 Q 310 440, 360 400"/>
        <path d="M240 380 Q 170 360, 110 320"/>
        <path d="M240 300 Q 320 280, 370 240"/>
        <path d="M240 220 Q 180 200, 130 170"/>
        <path d="M240 140 Q 310 120, 350 90"/>

        {/* leaves */}
        <LeafShape cx={120} cy={470} r={0.15} angle={-30}/>
        <LeafShape cx={360} cy={400} r={0.17} angle={40}/>
        <LeafShape cx={110} cy={320} r={0.18} angle={-40}/>
        <LeafShape cx={370} cy={240} r={0.16} angle={35}/>
        <LeafShape cx={130} cy={170} r={0.14} angle={-35}/>
        <LeafShape cx={350} cy={90}  r={0.15} angle={45}/>
        <LeafShape cx={240} cy={60}  r={0.13} angle={0}/>
      </g>

      {/* cherries (copper) */}
      <g>
        {[
          [200,505],[215,498],[225,512],
          [285,450],[298,458],
          [170,360],[185,352],[198,365],
          [295,260],[308,270],
          [205,170],[218,163],
        ].map(([cx,cy],i)=>(
          <g key={i}>
            <circle cx={cx} cy={cy} r="7" fill="var(--copper)" stroke="var(--ink-2)" strokeWidth="0.7"/>
            <circle cx={cx-2} cy={cy-2} r="1.6" fill="rgba(255,255,255,0.5)"/>
          </g>
        ))}
      </g>

      {/* bean detail insets (bottom left) */}
      <g transform="translate(40,540)" stroke="var(--ink-2)" fill="none">
        <ellipse cx="30" cy="30" rx="22" ry="28" strokeWidth="0.8"/>
        <path d="M30 4 Q 34 30, 30 56" strokeWidth="0.8"/>
        <text x="0" y="78" fontFamily="var(--hand)" fontSize="14" fill="var(--ink-2)" stroke="none">fig. i — endosperm</text>
      </g>
      <g transform="translate(120,540)" stroke="var(--ink-2)" fill="none">
        <path d="M20 10 Q 55 30, 20 50 Q -10 30, 20 10 Z" strokeWidth="0.8"/>
        <path d="M8 30 Q 20 34, 32 30" strokeWidth="0.5" opacity="0.6"/>
        <text x="-4" y="78" fontFamily="var(--hand)" fontSize="14" fill="var(--ink-2)" stroke="none">fig. ii — cherry</text>
      </g>

      {/* scale bar */}
      <g transform="translate(380, 580)" fontFamily="var(--mono)" fontSize="9" fill="var(--ink-3)">
        <line x1="0" y1="0" x2="60" y2="0" stroke="var(--ink-2)" strokeWidth="0.7"/>
        <line x1="0" y1="-3" x2="0" y2="3" stroke="var(--ink-2)" strokeWidth="0.7"/>
        <line x1="60" y1="-3" x2="60" y2="3" stroke="var(--ink-2)" strokeWidth="0.7"/>
        <text x="20" y="14" letterSpacing="1">5 CM</text>
      </g>

      {/* label — top right */}
      <g fontFamily="var(--serif)" fill="var(--ink)">
        <text x="300" y="30" fontSize="16" fontStyle="italic">Coffea excelsa</text>
        <text x="300" y="46" fontSize="11" fill="var(--ink-3)" fontFamily="var(--mono)" letterSpacing="1">A. CHEVALIER, 1903</text>
      </g>
    </svg>
  );
}
function LeafShape({ cx, cy, r = 0.15, angle = 0 }){
  const w = 120*r*2, h = 180*r*2;
  return (
    <g transform={`translate(${cx},${cy}) rotate(${angle}) scale(${r*2})`}>
      <path d="M0 -40 C 30 -20, 35 30, 0 60 C -35 30, -30 -20, 0 -40 Z" />
      <path d="M0 -38 L 0 58" />
      {Array.from({length:6}).map((_,i)=>{
        const y=-30+i*16; const d=i%2===0?1:-1;
        return <path key={i} d={`M0 ${y} Q ${d*10} ${y+6}, ${d*22} ${y+10}`} />;
      })}
    </g>
  );
}

/* ---------- Radar chart for cupping ---------- */
function Radar({ axes, values, size = 260, color = "var(--copper)", max = 10 }){
  const cx = size/2, cy = size/2, r = size/2 - 40;
  const step = (Math.PI*2) / axes.length;
  const points = values.map((v, i) => {
    const a = -Math.PI/2 + i*step;
    const rr = (v/max)*r;
    return [cx + Math.cos(a)*rr, cy + Math.sin(a)*rr];
  });
  const rings = [0.25, 0.5, 0.75, 1].map(f => {
    const pts = axes.map((_,i)=>{
      const a = -Math.PI/2 + i*step;
      return `${cx + Math.cos(a)*r*f},${cy + Math.sin(a)*r*f}`;
    });
    return pts.join(" ");
  });
  return (
    <svg viewBox={`0 0 ${size} ${size}`} width="100%" style={{ display:"block" }} aria-hidden="true">
      {rings.map((p,i)=>(
        <polygon key={i} points={p} fill="none" stroke="var(--line)" strokeWidth="0.8"/>
      ))}
      {axes.map((ax,i)=>{
        const a = -Math.PI/2 + i*step;
        const x2 = cx + Math.cos(a)*r, y2 = cy + Math.sin(a)*r;
        return <line key={i} x1={cx} y1={cy} x2={x2} y2={y2} stroke="var(--line)" strokeWidth="0.6"/>;
      })}
      <polygon points={points.map(p=>p.join(",")).join(" ")}
        fill={color} fillOpacity="0.22" stroke={color} strokeWidth="1.2"/>
      {points.map(([x,y],i)=>(
        <circle key={i} cx={x} cy={y} r="2.6" fill={color}/>
      ))}
      {axes.map((ax,i)=>{
        const a = -Math.PI/2 + i*step;
        const x = cx + Math.cos(a)*(r+18), y = cy + Math.sin(a)*(r+18);
        return <text key={i} x={x} y={y} textAnchor="middle" dominantBaseline="middle"
          fontFamily="var(--mono)" fontSize="9" letterSpacing="1.2" fill="var(--ink-3)">{ax.toUpperCase()}</text>;
      })}
    </svg>
  );
}

/* ---------- Make everything globally available ---------- */
Object.assign(window, {
  Reveal, Parallax, useScrollY, SectionHeader, Placeholder, Stat, Marquee,
  Leaf, Cherry, BotanicalPlate, Radar,
});
