// ============================================================
// EFFECTS — KintsugiMark + ambient seam backdrop
// The brand visual: a faceted shard with golden mending seams.
// ============================================================

function KintsugiMark({ size = 360, drawIn = true, motion = true }) {
  const theme = window.useActiveTheme();
  const [t, setT] = React.useState(0);

  React.useEffect(() => {
    if (!motion) return;
    let raf, start;
    const loop = (ts) => {
      if (!start) start = ts;
      setT((ts - start) / 1000);
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, [motion]);

  const breatheScale = motion ? 1 + 0.012 * Math.sin(t * 0.7) : 1;
  const driftX = motion ? Math.sin(t * 0.3) * 4 : 0;
  const driftY = motion ? Math.cos(t * 0.24) * 3 : 0;

  // Faceted lozenge geometry. The outer diamond is broken into 7 internal
  // facets; each shares an edge with at least one neighbour. Those shared
  // edges become the gold "kintsugi" seams.
  // Coords are on a 0..200 viewBox, diamond apex at top (100,10), bottom (100,260).
  const facets = [
    // [polygon points, fill tint]
    ["100,10 60,80 100,100", 0.06],            // top-left wedge
    ["100,10 100,100 160,70", 0.10],           // top-right wedge
    ["60,80 100,100 70,170 30,140", 0.05],     // mid-left
    ["100,100 160,70 180,160 130,150", 0.08],  // mid-right
    ["100,100 130,150 100,180 70,170", 0.12],  // centre
    ["70,170 100,180 100,260 50,210", 0.05],   // bottom-left
    ["100,180 130,150 180,160 150,220 100,260", 0.07], // bottom-right
  ];

  // Seam paths: the polylines that trace the boundary between facets.
  // Drawing-order matters for the stagger; longer seams animate later.
  const seams = [
    "M100 10 L100 100 L100 180 L100 260",       // central vertical (spine)
    "M60 80 L100 100 L160 70",                  // upper Y
    "M30 140 L60 80",                           // upper-left arm
    "M180 160 L160 70",                         // upper-right arm
    "M70 170 L100 100 L130 150",                // mid V
    "M50 210 L70 170 L130 150 L150 220",        // lower zigzag
  ];

  const accent = theme.accent;
  const accentDeep = theme.accentDeep;
  const facetTop = theme.facetFillTop;
  const facetBottom = theme.facetFillBottom;

  return (
    <div
      style={{
        position: "relative",
        width: size,
        height: size,
        transform: `translate(${driftX}px, ${driftY}px) scale(${breatheScale})`,
        transition: "transform 60ms linear",
      }}
    >
      {/* Soft gold glow halo behind the mark */}
      <div
        style={{
          position: "absolute",
          inset: "-18%",
          background:
            "radial-gradient(circle at 50% 50%, rgba(245,193,78,0.20), rgba(245,193,78,0.04) 38%, transparent 65%)",
          filter: "blur(14px)",
          pointerEvents: "none",
        }}
        aria-hidden
      />

      <svg
        viewBox="0 0 200 280"
        width="100%"
        height="100%"
        style={{
          position: "absolute",
          inset: 0,
          overflow: "visible",
        }}
        aria-label="Shard — faceted mark"
        role="img"
      >
        <defs>
          <linearGradient id="kintsugi-facet-grad" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor={facetTop} stopOpacity={theme.dark ? 0.55 : 0.4} />
            <stop offset="100%" stopColor={facetBottom} stopOpacity={theme.dark ? 0.9 : 0.6} />
          </linearGradient>
          <linearGradient id="kintsugi-seam-grad" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor={accent} />
            <stop offset="100%" stopColor={accentDeep} />
          </linearGradient>
          <filter id="kintsugi-seam-glow" x="-50%" y="-50%" width="200%" height="200%">
            <feGaussianBlur stdDeviation="1.8" result="blur" />
            <feMerge>
              <feMergeNode in="blur" />
              <feMergeNode in="SourceGraphic" />
            </feMerge>
          </filter>
        </defs>

        {/* Facet fills */}
        <g>
          {facets.map(([pts, tintAlpha], i) => (
            <polygon
              key={i}
              points={pts}
              fill="url(#kintsugi-facet-grad)"
              stroke="rgba(255,255,255,0.04)"
              strokeWidth="0.5"
              style={{
                opacity: 0,
                transformOrigin: "100px 140px",
                animation: drawIn
                  ? `kintsugi-facet-in 700ms cubic-bezier(.22,.9,.28,1) ${i * 90}ms forwards`
                  : undefined,
                ...(drawIn
                  ? {}
                  : { opacity: 1, transform: "scale(1)" }),
              }}
            />
          ))}
          {/* Subtle warm overlay on the right side facets */}
          {facets.map(([pts, tintAlpha], i) => (
            <polygon
              key={`tint-${i}`}
              points={pts}
              fill={accent}
              fillOpacity={tintAlpha}
              style={{
                opacity: 0,
                animation: drawIn
                  ? `kintsugi-facet-in 700ms ease ${i * 90 + 200}ms forwards`
                  : undefined,
                ...(drawIn ? {} : { opacity: 1 }),
              }}
            />
          ))}
        </g>

        {/* Outer shard outline — traces every facet vertex on the silhouette
            so the outline matches the actual outer edge of the shard, with
            broken-corner notches that fit the kintsugi metaphor. */}
        <polygon
          points="100,10 160,70 180,160 150,220 100,260 50,210 30,140 60,80"
          fill="none"
          stroke={accent}
          strokeWidth="2"
          strokeLinejoin="round"
          filter="url(#kintsugi-seam-glow)"
          style={{
            strokeDasharray: 900,
            strokeDashoffset: drawIn ? 900 : 0,
            animation: drawIn
              ? "kintsugi-seam-draw 1400ms cubic-bezier(.22,.9,.28,1) 200ms forwards"
              : undefined,
            "--seam-len": 900,
          }}
        />

        {/* Inner seam paths — drawn in sequence after the outer outline */}
        <g
          stroke="url(#kintsugi-seam-grad)"
          strokeWidth="1.8"
          fill="none"
          strokeLinecap="round"
          strokeLinejoin="round"
          filter="url(#kintsugi-seam-glow)"
        >
          {seams.map((d, i) => (
            <path
              key={i}
              d={d}
              style={{
                strokeDasharray: 400,
                strokeDashoffset: drawIn ? 400 : 0,
                animation: drawIn
                  ? `kintsugi-seam-draw 1100ms cubic-bezier(.22,.9,.28,1) ${600 + i * 180}ms forwards`
                  : undefined,
                "--seam-len": 400,
              }}
            />
          ))}
        </g>

        {/* Vertex nodes — small gold points at major junctions. No glow
            filter here so the dots don't visually break the seams they sit on. */}
        <g fill={accent}>
          {[
            [100, 10],
            [60, 80],
            [160, 70],
            [100, 100],
            [30, 140],
            [180, 160],
            [70, 170],
            [130, 150],
            [50, 210],
            [150, 220],
            [100, 260],
          ].map(([x, y], i) => (
            <circle
              key={i}
              cx={x}
              cy={y}
              r="1.8"
              style={{
                opacity: 0,
                animation: drawIn
                  ? `kintsugi-facet-in 400ms ease ${1400 + i * 40}ms forwards`
                  : undefined,
                ...(drawIn ? {} : { opacity: 1 }),
              }}
            />
          ))}
        </g>
      </svg>

      {/* Subtle orbiting node — same brand-pulse trick as BRAINS */}
      {motion && (
        <div
          aria-hidden
          style={{
            position: "absolute",
            left: "50%",
            top: "50%",
            width: 5,
            height: 5,
            marginLeft: -2.5,
            marginTop: -2.5,
            borderRadius: "50%",
            background: accent,
            boxShadow: `0 0 12px 2px rgba(245,193,78,0.85)`,
            transform: `translate(${Math.cos(t * 0.9) * size * 0.36}px, ${Math.sin(t * 0.9) * size * 0.42}px)`,
            opacity: 0.85,
            pointerEvents: "none",
          }}
        />
      )}
    </div>
  );
}

// Ambient gold-seam backdrop — thin diagonal lines that suggest mended
// fractures running behind a section. Decorative only.
function SeamBackdrop({ density = 6, opacity = 0.08 }) {
  const theme = window.useActiveTheme();
  const seams = Array.from({ length: density }).map((_, i) => {
    const top = (i / density) * 100 + (i % 2 === 0 ? 4 : -4);
    const skew = -8 + (i % 3) * 6;
    return { top, skew, key: i };
  });
  return (
    <div
      aria-hidden
      style={{
        position: "absolute",
        inset: 0,
        overflow: "hidden",
        pointerEvents: "none",
      }}
    >
      {seams.map((s) => (
        <div
          key={s.key}
          style={{
            position: "absolute",
            left: "-10%",
            right: "-10%",
            top: `${s.top}%`,
            height: 1,
            background: `linear-gradient(90deg, transparent 0%, ${theme.accent} ${20 + s.key * 6}%, transparent 100%)`,
            opacity,
            transform: `rotate(${s.skew}deg)`,
            transformOrigin: "center",
          }}
        />
      ))}
    </div>
  );
}

window.KintsugiMark = KintsugiMark;
window.SeamBackdrop = SeamBackdrop;

// ============================================================
// SHARD FIELD — fixed full-page three.js backdrop.
// Sparse gold wireframe fragments + dust drifting in deep space,
// with gentle scroll parallax. Sits behind all content; pointer
// events off; skipped entirely when motion is off or WebGL fails.
// ============================================================

function ShardField() {
  const theme = window.useActiveTheme();
  const mountRef = React.useRef(null);

  React.useEffect(() => {
    if (!window.THREE || !window.motionAllowed() || !mountRef.current) return;
    const THREE = window.THREE;
    const mount = mountRef.current;

    let renderer;
    try {
      renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    } catch (e) {
      return;
    }
    const dpr = Math.min(window.devicePixelRatio || 1, 1.75);
    renderer.setPixelRatio(dpr);
    renderer.setSize(window.innerWidth, window.innerHeight);
    mount.appendChild(renderer.domElement);

    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(
      55,
      window.innerWidth / window.innerHeight,
      0.1,
      60
    );
    camera.position.z = 10;

    const accent = new THREE.Color(theme.accent);
    const group = new THREE.Group();
    scene.add(group);

    // Sparse wireframe fragments — deterministic placement.
    const seeded = (i) => {
      const x = Math.sin(i * 91.7 + 47.3) * 24634.6345;
      return x - Math.floor(x);
    };
    const fragMat = new THREE.LineBasicMaterial({
      color: accent,
      transparent: true,
      opacity: theme.dark ? 0.16 : 0.22,
    });
    const fragments = [];
    for (let i = 0; i < 9; i++) {
      const base =
        i % 3 === 0
          ? new THREE.TetrahedronGeometry(0.5 + seeded(i) * 0.5, 0)
          : new THREE.OctahedronGeometry(0.4 + seeded(i + 40) * 0.45, 0);
      base.scale(1, 1.3 + seeded(i + 7) * 0.4, 1);
      const edges = new THREE.EdgesGeometry(base);
      const frag = new THREE.LineSegments(edges, fragMat);
      frag.position.set(
        (seeded(i + 11) - 0.5) * 18,
        (seeded(i + 23) - 0.5) * 12,
        -2 - seeded(i + 31) * 6
      );
      frag.rotation.set(seeded(i + 3) * Math.PI, seeded(i + 5) * Math.PI, 0);
      frag.userData = {
        rx: (seeded(i + 13) - 0.5) * 0.0024,
        ry: (seeded(i + 17) - 0.5) * 0.003,
        bobA: seeded(i + 19) * Math.PI * 2,
        bobS: 0.16 + seeded(i + 29) * 0.22,
      };
      group.add(frag);
      fragments.push(frag);
      base.dispose();
    }

    // Dust points.
    const DUST = 140;
    const dustPos = new Float32Array(DUST * 3);
    for (let i = 0; i < DUST; i++) {
      dustPos[i * 3] = (seeded(i + 101) - 0.5) * 22;
      dustPos[i * 3 + 1] = (seeded(i + 211) - 0.5) * 14;
      dustPos[i * 3 + 2] = -1 - seeded(i + 307) * 8;
    }
    const dustGeo = new THREE.BufferGeometry();
    dustGeo.setAttribute("position", new THREE.BufferAttribute(dustPos, 3));
    const dustMat = new THREE.PointsMaterial({
      color: accent,
      size: 0.035,
      transparent: true,
      opacity: theme.dark ? 0.4 : 0.5,
      sizeAttenuation: true,
    });
    const dust = new THREE.Points(dustGeo, dustMat);
    group.add(dust);

    let raf = 0;
    let t = 0;
    const tick = () => {
      t += 0.016;
      // scroll parallax — scrollY read inside rAF, never via scroll listener
      const sy = window.scrollY || 0;
      group.position.y = sy * 0.0012;
      group.rotation.y = Math.sin(t * 0.04) * 0.06;
      fragments.forEach((f) => {
        f.rotation.x += f.userData.rx;
        f.rotation.y += f.userData.ry;
        f.position.y += Math.sin(t * f.userData.bobS + f.userData.bobA) * 0.0012;
      });
      dust.rotation.y = t * 0.008;
      renderer.render(scene, camera);
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);

    const onResize = () => {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(window.innerWidth, window.innerHeight);
    };
    window.addEventListener("resize", onResize);

    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener("resize", onResize);
      fragments.forEach((f) => f.geometry.dispose());
      fragMat.dispose();
      dustGeo.dispose();
      dustMat.dispose();
      renderer.dispose();
      if (renderer.domElement.parentNode === mount) {
        mount.removeChild(renderer.domElement);
      }
    };
  }, [theme.dark, theme.accent]);

  if (!window.THREE) return null;
  return (
    <div
      ref={mountRef}
      aria-hidden
      style={{
        position: "fixed",
        inset: 0,
        zIndex: 0,
        pointerEvents: "none",
      }}
    />
  );
}

window.ShardField = ShardField;
