// Small reusable bits: scroll-reveal hook, particles, 3D objects, icons.

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

/* IntersectionObserver-based reveal — adds .in to any element with .reveal */
function useReveal() {
  useEffect(() => {
    const els = document.querySelectorAll(".reveal:not(.in)");
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((e) => {
          if (e.isIntersecting) {
            e.target.classList.add("in");
            io.unobserve(e.target);
          }
        });
      },
      { threshold: 0.18, rootMargin: "0px 0px -40px 0px" }
    );
    els.forEach((el) => io.observe(el));
    return () => io.disconnect();
  });
}

/* Scroll progress 0..1 over the document */
function useScrollProgress() {
  const [p, setP] = useState(0);
  useEffect(() => {
    const onScroll = () => {
      const h = document.documentElement;
      const max = h.scrollHeight - h.clientHeight;
      setP(max > 0 ? h.scrollTop / max : 0);
    };
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  return p;
}

/* Window scrollY (raw px) */
function useScrollY() {
  const [y, setY] = useState(0);
  useEffect(() => {
    const f = () => setY(window.scrollY || 0);
    f();
    window.addEventListener("scroll", f, { passive: true });
    return () => window.removeEventListener("scroll", f);
  }, []);
  return y;
}

/* Lightweight particles — purely decorative */
function Particles({ count = 28 }) {
  const items = useMemo(() => {
    return new Array(count).fill(0).map((_, i) => ({
      left: Math.random() * 100,
      delay: -Math.random() * 14,
      dur: 10 + Math.random() * 14,
      scale: 0.5 + Math.random() * 1.6,
      o: 0.3 + Math.random() * 0.5,
    }));
  }, [count]);
  return (
    <div className="particles" aria-hidden="true">
      {items.map((p, i) => (
        <span
          key={i}
          style={{
            left: p.left + "%",
            bottom: -20,
            animationDelay: p.delay + "s",
            animationDuration: p.dur + "s",
            transform: `scale(${p.scale})`,
            opacity: p.o,
          }}
        />
      ))}
    </div>
  );
}

/* ───────────────────────────────────────────────────────────
   3D wireframe objects (pure CSS) — rotate with scroll
   ─────────────────────────────────────────────────────────── */

const SHAPE_STYLES = `
.scene { perspective: 1100px; transform-style: preserve-3d; }
.shape { position: relative; transform-style: preserve-3d; will-change: transform; }
.face {
  position: absolute; inset: 0;
  border: 1px solid var(--accent);
  background: linear-gradient(135deg, color-mix(in oklab, var(--accent) 16%, transparent), color-mix(in oklab, var(--violet) 10%, transparent));
  box-shadow: 0 0 24px color-mix(in oklab, var(--accent) 30%, transparent),
              inset 0 0 24px color-mix(in oklab, var(--accent) 18%, transparent);
  backface-visibility: visible;
}
.face::before, .face::after {
  content: ""; position: absolute; inset: 0;
  border: 1px solid color-mix(in oklab, var(--violet) 40%, transparent);
  transform: scale(.86);
  opacity: .55;
}
.face::after { transform: scale(.62); opacity: .35; }
.octa-face {
  position: absolute; left: 50%; top: 50%;
  width: 0; height: 0; transform-origin: center;
}
.octa-face .tri {
  position: absolute; left: -60px; top: -52px;
  width: 0; height: 0;
  border-left: 60px solid transparent;
  border-right: 60px solid transparent;
  border-bottom: 104px solid color-mix(in oklab, var(--accent) 22%, transparent);
  filter: drop-shadow(0 0 14px color-mix(in oklab, var(--accent) 50%, transparent));
}
.octa-face .tri-outline {
  position: absolute; left: -60px; top: -52px;
  width: 120px; height: 104px;
  /* SVG fill via background-image for the wireframe */
}
`;

function ShapeStyles() {
  return <style>{SHAPE_STYLES}</style>;
}

/* Wireframe cube — 6 faces */
function Cube({ size = 220, rotateX = 0, rotateY = 0, rotateZ = 0, className = "" }) {
  const half = size / 2;
  const faces = [
    { t: `rotateY(0deg) translateZ(${half}px)` },
    { t: `rotateY(180deg) translateZ(${half}px)` },
    { t: `rotateY(90deg) translateZ(${half}px)` },
    { t: `rotateY(-90deg) translateZ(${half}px)` },
    { t: `rotateX(90deg) translateZ(${half}px)` },
    { t: `rotateX(-90deg) translateZ(${half}px)` },
  ];
  return (
    <div
      className={"shape " + className}
      style={{
        width: size, height: size,
        transform: `rotateX(${rotateX}deg) rotateY(${rotateY}deg) rotateZ(${rotateZ}deg)`,
      }}
    >
      {faces.map((f, i) => (
        <div key={i} className="face" style={{ width: size, height: size, transform: f.t }} />
      ))}
    </div>
  );
}

/* Octahedron made of 8 SVG triangle faces. Simpler: 2 stacked square pyramids using rotated planes. */
function Octahedron({ size = 200, rotateX = 0, rotateY = 0, rotateZ = 0, className = "" }) {
  // Use 4 triangle planes forming top pyramid and 4 for bottom.
  // We'll render via inline SVG planes positioned in 3D.
  const s = size;
  const r = s / 2;
  // Faces are isoceles triangles, hinged along the equator.
  const planes = [];
  for (let i = 0; i < 4; i++) {
    const ry = i * 90;
    // top
    planes.push({ rx: -54.7356, ry, rz: 0, top: true });
    // bottom
    planes.push({ rx: 54.7356, ry, rz: 0, top: false });
  }
  return (
    <div
      className={"shape " + className}
      style={{
        width: s, height: s,
        transform: `rotateX(${rotateX}deg) rotateY(${rotateY}deg) rotateZ(${rotateZ}deg)`,
      }}
    >
      {planes.map((p, i) => (
        <div
          key={i}
          style={{
            position: "absolute",
            left: "50%",
            top: "50%",
            width: 0, height: 0,
            transform: `translate(-50%, ${p.top ? "-100%" : "0%"}) rotateY(${p.ry}deg) rotateX(${p.rx}deg)`,
            transformOrigin: p.top ? "50% 100%" : "50% 0%",
          }}
        >
          <svg
            width={s} height={s * 0.866}
            viewBox="0 0 100 86.6"
            style={{
              position: "absolute",
              left: -s/2, top: p.top ? -s*0.866 : 0,
              overflow: "visible",
              filter: "drop-shadow(0 0 14px color-mix(in oklab, var(--accent) 45%, transparent))",
            }}
          >
            <defs>
              <linearGradient id={`og${i}`} x1="0" y1="0" x2="1" y2="1">
                <stop offset="0" stopColor="var(--accent)" stopOpacity="0.18" />
                <stop offset="1" stopColor="var(--violet)" stopOpacity="0.10" />
              </linearGradient>
            </defs>
            <polygon
              points={p.top ? "50,0 100,86.6 0,86.6" : "0,0 100,0 50,86.6"}
              fill={`url(#og${i})`}
              stroke="var(--accent)"
              strokeWidth="0.6"
              strokeLinejoin="round"
            />
          </svg>
        </div>
      ))}
    </div>
  );
}

/* Torus-knot-ish ring: a flat ring rotated through several axes */
function Ring({ size = 240, rotateX = 0, rotateY = 0, rotateZ = 0, className = "" }) {
  return (
    <div
      className={"shape " + className}
      style={{
        width: size, height: size,
        transform: `rotateX(${rotateX}deg) rotateY(${rotateY}deg) rotateZ(${rotateZ}deg)`,
      }}
    >
      {[0, 60, 120].map((deg, i) => (
        <div
          key={i}
          style={{
            position: "absolute", inset: 0,
            borderRadius: "50%",
            border: "1px solid color-mix(in oklab, var(--accent) 60%, transparent)",
            transform: `rotateY(${deg}deg)`,
            boxShadow: "0 0 28px color-mix(in oklab, var(--accent) 30%, transparent), inset 0 0 22px color-mix(in oklab, var(--violet) 25%, transparent)",
          }}
        />
      ))}
      {[0, 90].map((deg, i) => (
        <div
          key={"x"+i}
          style={{
            position: "absolute", inset: 12,
            borderRadius: "50%",
            border: "1px dashed color-mix(in oklab, var(--violet) 70%, transparent)",
            transform: `rotateX(${deg + 30}deg)`,
            opacity: 0.7,
          }}
        />
      ))}
      <div style={{
        position: "absolute", left: "50%", top: "50%",
        width: 14, height: 14, borderRadius: "50%",
        transform: "translate(-50%,-50%)",
        background: "var(--accent)",
        boxShadow: "0 0 24px var(--accent), 0 0 44px var(--accent)"
      }}/>
    </div>
  );
}

Object.assign(window, {
  useReveal, useScrollProgress, useScrollY,
  Particles, Cube, Octahedron, Ring, ShapeStyles,
});
