// ============ UI primitives ============

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

// Intersection-based reveal
function Reveal({ children, delay = 0, as: Tag = "div", className = "", style = {} }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const show = () => {
      setTimeout(() => { if (el) el.classList.add("reveal-in"); }, delay * 1000);
    };
    const rect = el.getBoundingClientRect();
    const vh = window.innerHeight || document.documentElement.clientHeight;
    if (rect.top < vh + 600) {
      show();
      return;
    }
    const io = new IntersectionObserver(
      ([e]) => { if (e.isIntersecting) { show(); io.disconnect(); } },
      { threshold: 0.05 }
    );
    io.observe(el);
    return () => io.disconnect();
  }, [delay]);
  return (
    <Tag ref={ref} className={`reveal ${className}`} style={style}>
      {children}
    </Tag>
  );
}

// Textured image placeholder. Tone: coffee|cream|leaf|dark|accent|bean
function Placeholder({ tone = "coffee", label, className = "", style = {} }) {
  return (
    <div className={`ph ph-${tone} ${className}`} style={style}>
      {label && <span className="ph-label">{label}</span>}
    </div>
  );
}

// Decorative steam SVG (subtle, no emoji)
function Steam({ style = {} }) {
  return (
    <svg viewBox="0 0 60 120" fill="none" style={{ width: 50, height: 100, ...style }} aria-hidden="true">
      <path d="M20 100 Q30 80 20 60 Q10 40 20 20" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" opacity="0.35">
        <animate attributeName="opacity" values="0;0.4;0" dur="3s" repeatCount="indefinite" />
      </path>
      <path d="M35 100 Q45 78 35 56 Q25 34 35 14" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" opacity="0.3">
        <animate attributeName="opacity" values="0;0.35;0" dur="3s" begin="0.8s" repeatCount="indefinite" />
      </path>
      <path d="M50 100 Q58 82 50 64 Q42 46 50 28" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" opacity="0.28">
        <animate attributeName="opacity" values="0;0.32;0" dur="3s" begin="1.6s" repeatCount="indefinite" />
      </path>
    </svg>
  );
}

// Delicate organic leaf/branch SVG (hand-drawn feel)
function LeafBranch({ className = "", style = {} }) {
  return (
    <svg className={className} style={style} viewBox="0 0 640 800" fill="none" aria-hidden="true">
      <g stroke="currentColor" strokeWidth="1.2" fill="none" opacity="0.9">
        <path d="M320 40 C300 200, 300 400, 320 760" strokeDasharray="0 0" />
        <path d="M320 140 C260 170, 210 220, 190 290" />
        <path d="M320 140 C380 170, 430 220, 450 290" />
        <path d="M320 240 C250 270, 200 320, 180 400" />
        <path d="M320 240 C390 270, 440 320, 460 400" />
        <path d="M320 360 C260 390, 220 440, 210 510" />
        <path d="M320 360 C380 390, 420 440, 430 510" />
        <path d="M320 480 C270 510, 240 550, 235 610" />
        <path d="M320 480 C370 510, 400 550, 405 610" />
      </g>
      <g fill="currentColor" opacity="0.7">
        <ellipse cx="190" cy="290" rx="32" ry="10" transform="rotate(-30 190 290)" />
        <ellipse cx="450" cy="290" rx="32" ry="10" transform="rotate(30 450 290)" />
        <ellipse cx="180" cy="400" rx="38" ry="12" transform="rotate(-28 180 400)" />
        <ellipse cx="460" cy="400" rx="38" ry="12" transform="rotate(28 460 400)" />
        <ellipse cx="210" cy="510" rx="34" ry="11" transform="rotate(-26 210 510)" />
        <ellipse cx="430" cy="510" rx="34" ry="11" transform="rotate(26 430 510)" />
        <ellipse cx="235" cy="610" rx="28" ry="9"  transform="rotate(-24 235 610)" />
        <ellipse cx="405" cy="610" rx="28" ry="9"  transform="rotate(24 405 610)" />
      </g>
    </svg>
  );
}

// Tiny coffee bean SVG
function Bean({ className = "", style = {} }) {
  return (
    <svg className={className} style={style} viewBox="0 0 40 60" fill="none" aria-hidden="true">
      <ellipse cx="20" cy="30" rx="14" ry="22" fill="currentColor" opacity="0.9" />
      <path d="M20 10 Q14 30 20 50 Q26 30 20 10" stroke="rgba(0,0,0,0.25)" strokeWidth="1" fill="none" />
    </svg>
  );
}

// Circular rotating text (for hero stamp)
function CircleText({ text, radius = 48, fontSize = 10, className = "" }) {
  const id = useMemo(() => "ct-" + Math.random().toString(36).slice(2, 8), []);
  const size = (radius + fontSize + 4) * 2;
  return (
    <svg viewBox={`0 0 ${size} ${size}`} className={className} style={{ width: "100%", height: "100%" }}>
      <defs>
        <path id={id} d={`M ${size/2},${size/2} m -${radius},0 a ${radius},${radius} 0 1,1 ${radius*2},0 a ${radius},${radius} 0 1,1 -${radius*2},0`} />
      </defs>
      <text fill="currentColor" fontFamily="JetBrains Mono, monospace" fontSize={fontSize} letterSpacing="2">
        <textPath href={`#${id}`} startOffset="0">{text}</textPath>
      </text>
    </svg>
  );
}

// Arrow glyph
function Arrow({ className = "arrow" }) {
  return (
    <svg className={className} width="16" height="10" viewBox="0 0 16 10" fill="none">
      <path d="M1 5h13m0 0L10 1m4 4l-4 4" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
}

Object.assign(window, { Reveal, Placeholder, Steam, LeafBranch, Bean, CircleText, Arrow });
