// utils.jsx — Cursor, reveal hook, marquee, magnetic
const { useEffect, useRef, useState, useLayoutEffect } = React;

/* ---------------- Custom cursor ---------------- */
function Cursor() {
  const dot = useRef(null);
  const ring = useRef(null);
  const [label, setLabel] = useState("");
  useEffect(() => {
    let mx = window.innerWidth / 2, my = window.innerHeight / 2;
    let rx = mx, ry = my;
    let raf;
    const onMove = (e) => { mx = e.clientX; my = e.clientY; if (dot.current) dot.current.style.transform = `translate(${mx}px, ${my}px) translate(-50%, -50%)`; };
    const loop = () => {
      rx += (mx - rx) * 0.18;
      ry += (my - ry) * 0.18;
      if (ring.current) ring.current.style.transform = `translate(${rx}px, ${ry}px) translate(-50%, -50%)`;
      raf = requestAnimationFrame(loop);
    };
    const onOver = (e) => {
      const el = e.target.closest("[data-cursor]");
      if (el) {
        setLabel(el.getAttribute("data-cursor") || "");
        ring.current?.classList.add("is-hover");
        dot.current?.classList.add("is-hover");
      } else {
        setLabel("");
        ring.current?.classList.remove("is-hover");
        dot.current?.classList.remove("is-hover");
      }
    };
    window.addEventListener("mousemove", onMove);
    document.addEventListener("mouseover", onOver);
    loop();
    return () => { window.removeEventListener("mousemove", onMove); document.removeEventListener("mouseover", onOver); cancelAnimationFrame(raf); };
  }, []);
  return (
    <React.Fragment>
      <div className="cursor-dot" ref={dot}></div>
      <div className="cursor-ring" ref={ring}>{label}</div>
    </React.Fragment>
  );
}

/* ---------------- Scroll reveal ---------------- */
function useReveal() {
  useEffect(() => {
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((e) => {
          if (e.isIntersecting) {
            e.target.classList.add("in");
            io.unobserve(e.target);
          }
        });
      },
      { threshold: 0.15, rootMargin: "0px 0px -8% 0px" }
    );
    document.querySelectorAll(".reveal, .reveal-words").forEach((el) => io.observe(el));
    return () => io.disconnect();
  }, []);
}

/* ---------------- Word-by-word reveal text ---------------- */
// Extract text from any React node (strings, numbers, arrays, elements)
function _wrText(node) {
  if (node == null || typeof node === "boolean") return "";
  if (typeof node === "string" || typeof node === "number") return String(node);
  if (Array.isArray(node)) return node.map(_wrText).join("");
  if (React.isValidElement(node)) return _wrText(node.props.children);
  return "";
}

// Walk children -> tokens of { text, wrap? }, where wrap is the inline element
// (e.g. <i className="it">…</i>) that this word should be rendered inside of.
function _wrTokens(children) {
  const out = [];
  React.Children.forEach(children, (child) => {
    if (child == null || typeof child === "boolean") return;
    if (typeof child === "string" || typeof child === "number") {
      String(child).split(/\s+/).forEach((w) => { if (w) out.push({ text: w }); });
      return;
    }
    if (React.isValidElement(child)) {
      const inner = _wrText(child.props.children);
      inner.split(/\s+/).forEach((w) => {
        if (w) out.push({ text: w, wrap: child });
      });
    }
  });
  return out;
}

function WordsReveal({ children, as = "div", className = "", delay = 0 }) {
  const Tag = as;
  const tokens = _wrTokens(children);
  return (
    <Tag className={`reveal-words ${className}`}>
      {tokens.map((tok, i) => (
        <span className="word" key={i}>
          <i style={{ transitionDelay: `${delay + i * 40}ms` }}>
            {tok.wrap
              ? React.cloneElement(tok.wrap, {}, tok.text)
              : tok.text}
          </i>
          {i < tokens.length - 1 ? " " : ""}
        </span>
      ))}
    </Tag>
  );
}

/* ---------------- Marquee ---------------- */
function Marquee({ items, dark = false }) {
  const arr = [...items, ...items, ...items];
  return (
    <div className={`marquee ${dark ? "dark" : ""}`}>
      <div className="track">
        {arr.map((t, i) => (
          <React.Fragment key={i}>
            <span>{t}</span>
            <span className="dot">✶</span>
          </React.Fragment>
        ))}
      </div>
    </div>
  );
}

/* ---------------- Magnetic ---------------- */
function Magnetic({ children, strength = 0.35, as = "div", className = "", ...rest }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      const x = e.clientX - (r.left + r.width / 2);
      const y = e.clientY - (r.top + r.height / 2);
      el.style.transform = `translate(${x * strength}px, ${y * 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]);
  const Tag = as;
  return <Tag ref={ref} className={className} style={{ transition: "transform .35s cubic-bezier(0.22,1,0.36,1)" }} {...rest}>{children}</Tag>;
}

/* ---------------- Clock ---------------- */
function Clock() {
  const [t, setT] = useState("");
  useEffect(() => {
    const tick = () => {
      const d = new Date();
      const h = String(d.getHours()).padStart(2, "0");
      const m = String(d.getMinutes()).padStart(2, "0");
      setT(`${h}:${m} IST`);
    };
    tick();
    const id = setInterval(tick, 30000);
    return () => clearInterval(id);
  }, []);
  return <span className="clock">{t} — Kolkata</span>;
}

Object.assign(window, { Cursor, useReveal, WordsReveal, Marquee, Magnetic, Clock });
