// Shared utilities, orbit mark, cursor, reveal, etc.
// Exports globally: OrbitMark, OrbitBig, Cursor, useReveal, MagneticLink, Arrow, useScrolled

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

// ---- The orbit mark (ring + core + spark) --------------------
function OrbitMark({ size = 32, color = "var(--oz-purple-500)", spark = "var(--oz-gold-400)", animated = false, className = "" }) {
  return (
    <svg className={`orbit-mark ${className}`} width={size} height={size} viewBox="0 0 64 64" aria-hidden="true">
      <circle cx="32" cy="32" r="20" fill="none" stroke={color} strokeWidth="4" />
      <circle cx="32" cy="32" r="8" fill={color} />
      <g style={animated ? { transformOrigin: '32px 32px', animation: 'orbit-rot 12s linear infinite' } : {}}>
        <circle cx="50" cy="18" r="4" fill={spark} />
      </g>
    </svg>
  );
}

// ---- Big layered orbit used in hero --------------------------
function OrbitBig() {
  return (
    <svg viewBox="-20 -20 320 320" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
      <defs>
        <radialGradient id="oz-glow" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor="var(--oz-purple-500)" stopOpacity="0.4" />
          <stop offset="60%" stopColor="var(--oz-purple-700)" stopOpacity="0.05" />
          <stop offset="100%" stopColor="var(--oz-purple-900)" stopOpacity="0" />
        </radialGradient>
      </defs>
      {/* ambient glow */}
      <circle cx="140" cy="140" r="160" fill="url(#oz-glow)" />

      {/* outer dashed ring — counter rotates */}
      <g className="spinner-slow">
        <circle cx="140" cy="140" r="138" fill="none" stroke="rgba(255,255,255,0.08)" strokeWidth="1" strokeDasharray="2 8" />
      </g>
      {/* mid ring */}
      <g>
        <circle cx="140" cy="140" r="108" fill="none" stroke="rgba(255,255,255,0.10)" strokeWidth="1" />
      </g>
      {/* primary orbit */}
      <g className="spinner">
        <circle cx="140" cy="140" r="78" fill="none" stroke="var(--oz-purple-400)" strokeWidth="1.5" strokeOpacity="0.5" />
        {/* orbiting spark */}
        <g transform="translate(218, 140)">
          <circle r="8" fill="var(--oz-gold-400)" />
          <circle r="16" fill="var(--oz-gold-400)" fillOpacity="0.18" />
        </g>
      </g>
      {/* core */}
      <circle cx="140" cy="140" r="44" fill="var(--oz-purple-500)" />
      <circle cx="140" cy="140" r="44" fill="url(#oz-glow)" />
      <circle cx="140" cy="140" r="16" fill="var(--oz-paper)" fillOpacity="0.15" />
      <circle cx="140" cy="140" r="6" fill="var(--oz-paper)" />
    </svg>
  );
}

// ---- Per-section orbit (mobile only) ------------------------
function SectionOrbit({ variant = "services" }) {
  const common = { className: "section__orbit", "aria-hidden": "true", viewBox: "0 0 64 64", width: "56", height: "56" };
  if (variant === "services") {
    return (
      <svg {...common}>
        <circle cx="32" cy="32" r="28" fill="none" stroke="var(--oz-purple-500)" strokeWidth="1.5" strokeDasharray="2 6" />
        <g className="spinner">
          <circle cx="60" cy="32" r="4" fill="var(--oz-gold-400)" />
        </g>
        <circle cx="32" cy="32" r="10" fill="var(--oz-purple-500)" />
        <circle cx="32" cy="32" r="4" fill="var(--oz-paper)" fillOpacity="0.55" />
      </svg>
    );
  }
  if (variant === "process") {
    return (
      <svg {...common}>
        <circle cx="32" cy="32" r="26" fill="none" stroke="var(--oz-gold-400)" strokeWidth="1.5" strokeOpacity="0.55" />
        <g className="spinner-slow">
          <circle cx="58" cy="32" r="3" fill="var(--oz-purple-300)" />
          <circle cx="6"  cy="32" r="3" fill="var(--oz-purple-300)" />
          <circle cx="32" cy="6"  r="2" fill="var(--oz-gold-400)" />
          <circle cx="32" cy="58" r="2" fill="var(--oz-gold-400)" />
        </g>
        <circle cx="32" cy="32" r="8" fill="var(--oz-gold-400)" />
      </svg>
    );
  }
  if (variant === "about") {
    return (
      <svg {...common}>
        <circle cx="32" cy="32" r="26" fill="none" stroke="var(--oz-purple-400)" strokeWidth="1.5" />
        <g className="spinner">
          <path d="M58 32 A 26 26 0 0 1 42 55" stroke="var(--oz-gold-400)" strokeWidth="3" fill="none" strokeLinecap="round" />
          <circle cx="58" cy="32" r="3.5" fill="var(--oz-gold-400)" />
        </g>
        <circle cx="32" cy="32" r="9" fill="var(--oz-purple-500)" />
        <circle cx="32" cy="32" r="3" fill="var(--oz-paper)" />
      </svg>
    );
  }
  // contact
  return (
    <svg {...common}>
      <g className="spinner-slow">
        <circle cx="32" cy="32" r="28" fill="none" stroke="rgba(255,255,255,0.28)" strokeWidth="1" strokeDasharray="3 4" />
      </g>
      <g className="spinner">
        <circle cx="56" cy="32" r="5" fill="var(--oz-gold-400)" />
        <circle cx="56" cy="32" r="9" fill="var(--oz-gold-400)" fillOpacity="0.18" />
        <circle cx="8"  cy="32" r="2" fill="var(--oz-purple-300)" />
      </g>
      <circle cx="32" cy="32" r="7" fill="var(--oz-purple-500)" />
      <circle cx="32" cy="32" r="2.5" fill="var(--oz-paper)" />
    </svg>
  );
}

// ---- Custom cursor -------------------------------------------
function Cursor({ enabled }) {
  const dotRef = useRef(null);
  const ringRef = useRef(null);
  const pos = useRef({ x: -100, y: -100 });
  const ringPos = useRef({ x: -100, y: -100 });
  const raf = useRef(null);
  const isTouch = typeof window !== 'undefined' && (
    window.matchMedia('(hover: none) and (pointer: coarse)').matches ||
    'ontouchstart' in window
  );

  // Touch devices: paint a gold trail that follows the finger, each point
  // fading independently — first-touched fades first, lift-point fades last.
  useEffect(() => {
    if (!enabled || !isTouch) return;
    document.body.classList.remove('cursor-custom', 'cursor-hot', 'cursor-dark');

    let lastSpawn = 0;
    let lastX = 0;
    let lastY = 0;

    const spawn = (x, y) => {
      const mark = document.createElement('div');
      mark.className = 'tap-mark';
      mark.style.left = x + 'px';
      mark.style.top = y + 'px';
      document.body.appendChild(mark);
      setTimeout(() => mark.remove(), 1400);
    };

    const onStart = (e) => {
      const t = e.touches && e.touches[0];
      if (!t) return;
      lastX = t.clientX; lastY = t.clientY;
      lastSpawn = Date.now();
      spawn(lastX, lastY);
    };
    const onMove = (e) => {
      const t = e.touches && e.touches[0];
      if (!t) return;
      const now = Date.now();
      const dx = t.clientX - lastX;
      const dy = t.clientY - lastY;
      const dist = Math.sqrt(dx * dx + dy * dy);
      if (now - lastSpawn < 22 && dist < 14) return;
      lastX = t.clientX; lastY = t.clientY;
      lastSpawn = now;
      spawn(lastX, lastY);
    };
    const onEnd = (e) => {
      const t = e.changedTouches && e.changedTouches[0];
      if (!t) return;
      spawn(t.clientX, t.clientY);
    };

    window.addEventListener('touchstart', onStart, { passive: true });
    window.addEventListener('touchmove',  onMove,  { passive: true });
    window.addEventListener('touchend',   onEnd,   { passive: true });
    return () => {
      window.removeEventListener('touchstart', onStart);
      window.removeEventListener('touchmove',  onMove);
      window.removeEventListener('touchend',   onEnd);
    };
  }, [enabled, isTouch]);

  useEffect(() => {
    if (!enabled || isTouch) {
      document.body.classList.remove('cursor-custom', 'cursor-hot', 'cursor-dark');
      return;
    }
    document.body.classList.add('cursor-custom');

    const onMove = (e) => {
      pos.current.x = e.clientX;
      pos.current.y = e.clientY;
      if (dotRef.current) {
        dotRef.current.style.transform = `translate(${e.clientX}px, ${e.clientY}px) translate(-50%, -50%)`;
      }
    };
    const onOver = (e) => {
      const t = e.target.closest('[data-hover], a, button, .service-row, .hero__headline, .cta');
      if (t) document.body.classList.add('cursor-hot');
      else document.body.classList.remove('cursor-hot');
    };
    const tick = () => {
      ringPos.current.x += (pos.current.x - ringPos.current.x) * 0.18;
      ringPos.current.y += (pos.current.y - ringPos.current.y) * 0.18;
      if (ringRef.current) {
        ringRef.current.style.transform = `translate(${ringPos.current.x}px, ${ringPos.current.y}px) translate(-50%, -50%)`;
      }
      // detect element under the ring and tint accordingly
      raf.current = requestAnimationFrame(tick);
    };
    const onScroll = () => {
      const y = ringPos.current.y || 0;
      const el = document.elementFromPoint(ringPos.current.x || 0, y);
      if (!el) return;
      const darkSection = el.closest('.section--dark, .section--purple, .hero, .footer, .marquee-section');
      if (darkSection) document.body.classList.add('cursor-dark');
      else document.body.classList.remove('cursor-dark');
    };
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseover', onOver);
    window.addEventListener('mousemove', onScroll);
    window.addEventListener('scroll', onScroll, { passive: true });
    raf.current = requestAnimationFrame(tick);
    return () => {
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseover', onOver);
      window.removeEventListener('mousemove', onScroll);
      window.removeEventListener('scroll', onScroll);
      cancelAnimationFrame(raf.current);
      document.body.classList.remove('cursor-custom', 'cursor-hot', 'cursor-dark');
    };
  }, [enabled]);

  if (!enabled || isTouch) return null;
  return (
    <>
      <div className="cursor-ring" ref={ringRef} />
      <div className="cursor-dot" ref={dotRef} />
    </>
  );
}

// ---- Magnetic wrapper -----------------------------------------
function Magnetic({ children, strength = 0.3, className = "" }) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const onMove = (e) => {
      const rect = el.getBoundingClientRect();
      const x = e.clientX - rect.left - rect.width / 2;
      const y = e.clientY - rect.top - rect.height / 2;
      el.style.transform = `translate(${x * strength}px, ${y * strength}px)`;
    };
    const onLeave = () => {
      el.style.transform = 'translate(0, 0)';
    };
    el.addEventListener('mousemove', onMove);
    el.addEventListener('mouseleave', onLeave);
    return () => {
      el.removeEventListener('mousemove', onMove);
      el.removeEventListener('mouseleave', onLeave);
    };
  }, [strength]);
  return <span ref={ref} className={className} style={{ display: 'inline-block', transition: 'transform 220ms cubic-bezier(0.2,0.8,0.2,1)' }}>{children}</span>;
}

// ---- Reveal on scroll -----------------------------------------
function useRevealRoot() {
  useEffect(() => {
    const els = document.querySelectorAll('.reveal');
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) {
          e.target.classList.add('is-in');
          io.unobserve(e.target);
        }
      });
    }, { threshold: 0.12, rootMargin: '0px 0px -10% 0px' });
    els.forEach(el => io.observe(el));
    return () => io.disconnect();
  }, []);
}

// ---- Sticky-nav scroll state ---------------------------------
function useScrolled(threshold = 40) {
  const [s, setS] = useState(false);
  useEffect(() => {
    const onScroll = () => setS(window.scrollY > threshold);
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, [threshold]);
  return s;
}

// ---- Track which section the viewport top is inside ----------
function useActiveSection() {
  const [dark, setDark] = useState(true); // hero starts dark
  useEffect(() => {
    const check = () => {
      const y = 80;
      const el = document.elementFromPoint(window.innerWidth / 2, y);
      if (!el) return;
      const darkEl = el.closest('.section--dark, .section--purple, .hero, .footer');
      setDark(!!darkEl);
    };
    check();
    window.addEventListener('scroll', check, { passive: true });
    window.addEventListener('resize', check);
    return () => {
      window.removeEventListener('scroll', check);
      window.removeEventListener('resize', check);
    };
  }, []);
  return dark;
}

// ---- Icons ----------------------------------------------------
function ArrowUpRight({ size = 18 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
      <line x1="7" y1="17" x2="17" y2="7" />
      <polyline points="7 7 17 7 17 17" />
    </svg>
  );
}
function ArrowRight({ size = 18 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
      <line x1="5" y1="12" x2="19" y2="12" />
      <polyline points="12 5 19 12 12 19" />
    </svg>
  );
}
function Check({ size = 24 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <polyline points="20 6 9 17 4 12" />
    </svg>
  );
}
function Spark({ size = 18 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
      <path d="M12 2v6M12 16v6M2 12h6M16 12h6M5 5l4 4M15 15l4 4M5 19l4-4M15 9l4-4"/>
    </svg>
  );
}

Object.assign(window, {
  OrbitMark, OrbitBig, SectionOrbit, Cursor, Magnetic,
  useRevealRoot, useScrolled, useActiveSection,
  ArrowUpRight, ArrowRight, Check, Spark,
});
