// Shared components for LA REAL — counter, marquee, cursor, observer
// Exposed on window as LR.* so all 3 directions can use them.

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

// ── Hooks ────────────────────────────────────────────────────────────────────

// Returns whether an element has entered the viewport at least once.
// In a static artboard there's no scrolling so we resolve to true after mount.
function useReveal(opts = {}) {
  const ref = useRef(null);
  const [shown, setShown] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    // If the element is inside a non-scrolling artboard, just reveal.
    const inArtboard = ref.current.closest('[data-dc-slot]');
    if (inArtboard) {
      const t = setTimeout(() => setShown(true), opts.delay || 0);
      return () => clearTimeout(t);
    }
    const io = new IntersectionObserver(
      (es) => es.forEach((e) => e.isIntersecting && setShown(true)),
      { threshold: opts.threshold ?? 0.15 }
    );
    io.observe(ref.current);
    return () => io.disconnect();
  }, []);
  return [ref, shown];
}

// Counts up from 0 → value with easeOutCubic.
function useCount(target, { duration = 1400, start = true } = {}) {
  const [v, setV] = useState(0);
  useEffect(() => {
    if (!start) return;
    let raf, t0;
    const tick = (t) => {
      if (!t0) t0 = t;
      const p = Math.min(1, (t - t0) / duration);
      const eased = 1 - Math.pow(1 - p, 3);
      setV(target * eased);
      if (p < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [target, start, duration]);
  return v;
}

// ── Components ──────────────────────────────────────────────────────────────

// Renders a numeric/string stat. Numeric values briefly animate up; if the
// component re-mounts (e.g. inside a design-canvas artboard) it falls back to
// showing the final value so we don't get stuck at 0.
function Counter({ value, prefix = '', suffix = '', decimals }) {
  const numeric = typeof value === 'number';
  // Static render for strings.
  if (!numeric) return <span>{prefix}{value}{suffix}</span>;
  const isFrac = decimals != null ? decimals : (value % 1 !== 0 ? 1 : 0);
  return <span>{prefix}{value.toFixed(isFrac)}{suffix}</span>;
}

// Infinite marquee that auto-loops. Duplicates children inline.
// `reverse` makes it scroll right-to-left (default is left-to-right).
function Marquee({ speed = 40, children, gap = 48, className = '', style = {}, reverse = false }) {
  const trackRef = useRef(null);
  return (
    <div className={`lr-marquee ${className}`} style={{ overflow: 'hidden', ...style }}>
      <div
        ref={trackRef}
        className="lr-marquee-track"
        style={{
          display: 'flex',
          gap,
          width: 'max-content',
          animation: `lr-marquee ${speed}s linear infinite`,
          animationDirection: reverse ? 'reverse' : 'normal',
        }}
      >
        {children}
        {children}
      </div>
    </div>
  );
}

// Single asterisk glyph — used as logo / spacer / divider across directions.
function Aster({ size = 16, color = 'currentColor', spin = false, style = {} }) {
  return (
    <svg
      width={size}
      height={size}
      viewBox="0 0 24 24"
      fill="none"
      style={{
        display: 'inline-block',
        animation: spin ? 'lr-spin 12s linear infinite' : 'none',
        ...style,
      }}
    >
      <path
        d="M12 2v20M3.34 6.5l17.32 10M3.34 17.5l17.32-10"
        stroke={color}
        strokeWidth="2.2"
        strokeLinecap="round"
      />
    </svg>
  );
}

// Custom cursor — only inside artboards in focus mode (full size). Hidden otherwise.
function CustomCursor({ accent = '#C5FF3D', label = '' }) {
  const [pos, setPos] = useState({ x: -100, y: -100 });
  const [hov, setHov] = useState(false);
  const [host, setHost] = useState(null);
  useEffect(() => {
    // Only activate when the page is shown in focus mode / full size.
    // Heuristic: if the element is in a real viewport (not inside .dc-card scaled),
    // turn it on.
    const el = document.querySelector('[data-lr-cursor-host]');
    if (!el) return;
    setHost(el);
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      setPos({ x: e.clientX - r.left, y: e.clientY - r.top });
      const t = e.target;
      setHov(!!t.closest && !!t.closest('a, button, [data-hover]'));
    };
    el.addEventListener('mousemove', onMove);
    return () => el.removeEventListener('mousemove', onMove);
  }, []);
  if (!host) return null;
  return (
    <>
      <div
        style={{
          position: 'absolute',
          left: pos.x,
          top: pos.y,
          width: hov ? 56 : 12,
          height: hov ? 56 : 12,
          background: accent,
          borderRadius: '50%',
          transform: 'translate(-50%, -50%)',
          mixBlendMode: 'difference',
          transition: 'width .25s cubic-bezier(.2,.7,.3,1), height .25s cubic-bezier(.2,.7,.3,1)',
          pointerEvents: 'none',
          zIndex: 9999,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          fontSize: 9,
          fontWeight: 600,
          color: '#000',
          letterSpacing: '.06em',
          textTransform: 'uppercase',
        }}
      >
        {hov && label}
      </div>
    </>
  );
}

// Generic SVG client wordmark — synthesizes a unique mark per brand name
// (no real logos, just text marks styled distinctly).
function ClientMark({ name, opacity = 0.7, color = 'currentColor' }) {
  const initial = name[0];
  const styles = useMemo(() => {
    // Pseudo-random but deterministic style per name
    let h = 0;
    for (let i = 0; i < name.length; i++) h = (h * 31 + name.charCodeAt(i)) | 0;
    const styleIdx = Math.abs(h) % 4;
    return styleIdx;
  }, [name]);

  const fonts = [
    { fontFamily: 'Instrument Serif, serif', fontStyle: 'italic', fontWeight: 400, letterSpacing: '-.02em' },
    { fontFamily: 'Manrope, sans-serif', fontWeight: 800, letterSpacing: '-.04em', textTransform: 'uppercase' },
    { fontFamily: 'JetBrains Mono, monospace', fontWeight: 500, letterSpacing: '.1em', textTransform: 'uppercase' },
    { fontFamily: 'Newsreader, serif', fontWeight: 500, letterSpacing: '-.01em' },
  ];

  return (
    <span
      style={{
        color,
        opacity,
        whiteSpace: 'nowrap',
        fontSize: 'inherit',
        ...fonts[styles],
      }}
    >
      {name}
    </span>
  );
}

// Brand logo: PNG isotype + "LA REAL" wordmark in Nexa.
// height controls visual size; showWordmark toggles the text.
function LRLogo({ height = 28, color = 'currentColor', showWordmark = true, gap = 10 }) {
  return (
    <span
      style={{
        display: 'inline-flex',
        alignItems: 'center',
        gap,
        color,
        lineHeight: 1,
        whiteSpace: 'nowrap',
      }}
    >
      <img
        src="assets/isotipo-lr.png"
        alt=""
        style={{
          height,
          width: height,
          display: 'block',
          objectFit: 'contain',
        }}
      />
      {showWordmark && (
        <span
          style={{
            fontFamily: "'Nexa', 'Geist', sans-serif",
            fontWeight: 900,
            fontSize: height * 0.7,
            letterSpacing: '0.02em',
          }}
        >
          LA REAL
        </span>
      )}
    </span>
  );
}

window.LR = { useReveal, useCount, Counter, Marquee, Aster, CustomCursor, ClientMark, Logo: LRLogo };
