// Procedural artwork surfaces + ambient effects (no SVG art, no stock images)
const { useEffect, useRef, useState } = React;

// --- deterministic hash so each piece looks different but stable
function hash(seed) {
  let h = 0;
  for (let i = 0; i < seed.length; i++) h = (h * 31 + seed.charCodeAt(i)) | 0;
  return () => {
    h = (h * 1664525 + 1013904223) | 0;
    return ((h >>> 0) % 100000) / 100000;
  };
}

// Procedural artwork surface — abstract painted texture from a piece's palette.
// Reads as art, not as a placeholder gray box.
function ArtSurface({ piece, density = 1, className = "", style = {} }) {
  const ref = useRef(null);
  useEffect(() => {
    const canvas = ref.current;
    if (!canvas) return;
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    const w = canvas.clientWidth, h = canvas.clientHeight;
    canvas.width = w * dpr; canvas.height = h * dpr;
    const ctx = canvas.getContext("2d");
    ctx.scale(dpr, dpr);
    const rand = hash(piece.id);
    const [c0, c1, c2, c3] = piece.palette;

    // base gradient (deep ground)
    const g = ctx.createLinearGradient(0, 0, w, h);
    g.addColorStop(0, c0);
    g.addColorStop(0.6, c1);
    g.addColorStop(1, c0);
    ctx.fillStyle = g; ctx.fillRect(0, 0, w, h);

    // wash blobs (mid tone)
    for (let i = 0; i < 28 * density; i++) {
      const x = rand() * w, y = rand() * h, r = (40 + rand() * 280) * (0.6 + density * 0.4);
      const rg = ctx.createRadialGradient(x, y, 0, x, y, r);
      rg.addColorStop(0, c1 + "");
      rg.addColorStop(1, "rgba(0,0,0,0)");
      ctx.globalAlpha = 0.18 + rand() * 0.22;
      ctx.fillStyle = rg;
      ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI * 2); ctx.fill();
    }
    ctx.globalAlpha = 1;

    // brushstroke streaks (highlight palette)
    ctx.lineCap = "round";
    for (let i = 0; i < 80 * density; i++) {
      const x0 = rand() * w, y0 = rand() * h;
      const ang = rand() * Math.PI * 2;
      const len = 30 + rand() * 220;
      const x1 = x0 + Math.cos(ang) * len, y1 = y0 + Math.sin(ang) * len;
      const col = rand() > 0.7 ? c3 : c2;
      ctx.strokeStyle = col;
      ctx.globalAlpha = 0.04 + rand() * 0.18;
      ctx.lineWidth = 0.6 + rand() * 3.5;
      ctx.beginPath(); ctx.moveTo(x0, y0); ctx.lineTo(x1, y1); ctx.stroke();
    }

    // fine grain (pigment)
    const img = ctx.getImageData(0, 0, w, h);
    for (let i = 0; i < img.data.length; i += 4) {
      const n = (rand() - 0.5) * 22;
      img.data[i]   = Math.max(0, Math.min(255, img.data[i]   + n));
      img.data[i+1] = Math.max(0, Math.min(255, img.data[i+1] + n));
      img.data[i+2] = Math.max(0, Math.min(255, img.data[i+2] + n));
    }
    ctx.putImageData(img, 0, 0);

    // foil scratches (top-layer accent)
    ctx.globalAlpha = 1;
    for (let i = 0; i < 16 * density; i++) {
      const x = rand() * w, y = rand() * h;
      const ang = rand() * Math.PI * 2;
      const len = 8 + rand() * 60;
      ctx.strokeStyle = c3;
      ctx.globalAlpha = 0.35 + rand() * 0.35;
      ctx.lineWidth = 0.4 + rand() * 0.8;
      ctx.beginPath();
      ctx.moveTo(x, y);
      ctx.lineTo(x + Math.cos(ang) * len, y + Math.sin(ang) * len);
      ctx.stroke();
    }
    ctx.globalAlpha = 1;

    // vignette
    const v = ctx.createRadialGradient(w/2, h/2, Math.min(w,h)*0.3, w/2, h/2, Math.max(w,h)*0.75);
    v.addColorStop(0, "rgba(0,0,0,0)");
    v.addColorStop(1, "rgba(0,0,0,0.5)");
    ctx.fillStyle = v; ctx.fillRect(0, 0, w, h);
  }, [piece.id, density]);

  return (
    <canvas
      ref={ref}
      className={className}
      style={{ display: "block", width: "100%", height: "100%", ...style }}
    />
  );
}

// Ambient ink canvas for the hero — slow, gravity-less particles
function InkField({ accent = "#a8825a" }) {
  const ref = useRef(null);
  const mouseRef = useRef({ x: 0.5, y: 0.5, active: false });

  useEffect(() => {
    const canvas = ref.current;
    if (!canvas) return;
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    let w, h, raf;
    const resize = () => {
      w = canvas.clientWidth; h = canvas.clientHeight;
      canvas.width = w * dpr; canvas.height = h * dpr;
    };
    resize();
    window.addEventListener("resize", resize);
    const ctx = canvas.getContext("2d");
    ctx.scale(dpr, dpr);

    const N = 90;
    const parts = Array.from({ length: N }, () => ({
      x: Math.random() * w,
      y: Math.random() * h,
      vx: (Math.random() - 0.5) * 0.18,
      vy: (Math.random() - 0.5) * 0.18,
      r: 0.6 + Math.random() * 2.2,
      life: Math.random(),
    }));

    const onMove = (e) => {
      const r = canvas.getBoundingClientRect();
      mouseRef.current.x = (e.clientX - r.left) / r.width;
      mouseRef.current.y = (e.clientY - r.top) / r.height;
      mouseRef.current.active = true;
    };
    window.addEventListener("mousemove", onMove);

    let t = 0;
    const tick = () => {
      t += 0.005;
      ctx.fillStyle = "rgba(12, 10, 8, 0.10)";
      ctx.fillRect(0, 0, w, h);

      // slow drifting nebula
      const cx = (mouseRef.current.x) * w;
      const cy = (mouseRef.current.y) * h;
      const rg = ctx.createRadialGradient(cx, cy, 0, cx, cy, Math.max(w, h) * 0.5);
      rg.addColorStop(0, accent + "26");
      rg.addColorStop(1, "rgba(0,0,0,0)");
      ctx.fillStyle = rg;
      ctx.fillRect(0, 0, w, h);

      for (const p of parts) {
        // gentle field
        const ang = Math.sin(p.x * 0.003 + t) + Math.cos(p.y * 0.003 - t);
        p.vx += Math.cos(ang) * 0.004;
        p.vy += Math.sin(ang) * 0.004;
        // mouse repulsion
        const dx = p.x - cx, dy = p.y - cy;
        const d2 = dx*dx + dy*dy;
        if (d2 < 22000) {
          const f = (22000 - d2) / 22000;
          p.vx += (dx / Math.sqrt(d2 + 1)) * f * 0.3;
          p.vy += (dy / Math.sqrt(d2 + 1)) * f * 0.3;
        }
        p.vx *= 0.96; p.vy *= 0.96;
        p.x += p.vx; p.y += p.vy;
        if (p.x < 0) p.x += w; if (p.x > w) p.x -= w;
        if (p.y < 0) p.y += h; if (p.y > h) p.y -= h;

        ctx.beginPath();
        ctx.fillStyle = "rgba(240, 232, 219, " + (0.18 + Math.sin(p.life * 9 + t * 4) * 0.12) + ")";
        ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
        ctx.fill();
      }
      raf = requestAnimationFrame(tick);
    };
    tick();

    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener("resize", resize);
      window.removeEventListener("mousemove", onMove);
    };
  }, [accent]);

  return <canvas ref={ref} style={{ position: "absolute", inset: 0, width: "100%", height: "100%" }} />;
}

// Custom cursor — small dot + lagging ring
function Cursor() {
  const dotRef = useRef(null);
  const ringRef = useRef(null);
  const stateRef = useRef({ x: 0, y: 0, tx: 0, ty: 0, hover: false });

  useEffect(() => {
    if (matchMedia("(pointer: coarse)").matches) return;
    const onMove = (e) => {
      stateRef.current.tx = e.clientX;
      stateRef.current.ty = e.clientY;
      if (dotRef.current) {
        dotRef.current.style.transform = `translate(${e.clientX}px, ${e.clientY}px)`;
      }
    };
    const onOver = (e) => {
      const t = e.target;
      const hover = !!(t && t.closest && t.closest("[data-cursor]"));
      stateRef.current.hover = hover;
      const label = hover ? t.closest("[data-cursor]").getAttribute("data-cursor") : "";
      if (ringRef.current) {
        ringRef.current.dataset.hover = hover ? "1" : "0";
        ringRef.current.querySelector(".c-label").textContent = label || "";
      }
    };
    window.addEventListener("mousemove", onMove);
    window.addEventListener("mouseover", onOver);

    let raf;
    const tick = () => {
      const s = stateRef.current;
      s.x += (s.tx - s.x) * 0.18;
      s.y += (s.ty - s.y) * 0.18;
      if (ringRef.current) {
        ringRef.current.style.transform = `translate(${s.x}px, ${s.y}px)`;
      }
      raf = requestAnimationFrame(tick);
    };
    tick();
    document.documentElement.classList.add("has-custom-cursor");
    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener("mousemove", onMove);
      window.removeEventListener("mouseover", onOver);
      document.documentElement.classList.remove("has-custom-cursor");
    };
  }, []);

  return (
    <React.Fragment>
      <div ref={dotRef} className="cursor-dot" />
      <div ref={ringRef} className="cursor-ring" data-hover="0">
        <span className="c-label" />
      </div>
    </React.Fragment>
  );
}

// Reveal-on-scroll wrapper
function Reveal({ children, as: Tag = "div", className = "", delay = 0, ...rest }) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) setSeen(true); });
    }, { threshold: 0.12 });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return (
    <Tag
      ref={ref}
      className={`reveal ${seen ? "seen" : ""} ${className}`}
      style={{ transitionDelay: `${delay}ms` }}
      {...rest}
    >{children}</Tag>
  );
}

// Magnetic hover for buttons
function Magnetic({ children, strength = 0.25, className = "" }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      const dx = e.clientX - (r.left + r.width / 2);
      const dy = e.clientY - (r.top + r.height / 2);
      el.style.transform = `translate(${dx * strength}px, ${dy * strength}px)`;
    };
    const onLeave = () => { el.style.transform = ""; };
    el.addEventListener("mousemove", onMove);
    el.addEventListener("mouseleave", onLeave);
    return () => {
      el.removeEventListener("mousemove", onMove);
      el.removeEventListener("mouseleave", onLeave);
    };
  }, [strength]);
  return <div ref={ref} className={`magnetic ${className}`}>{children}</div>;
}

Object.assign(window, { ArtSurface, InkField, Cursor, Reveal, Magnetic });
