// ============ SHARED HELPERS + CURSOR + NAV + BOOT ============
const { useState, useEffect, useRef, useCallback, useMemo, createContext, useContext } = React;

// ---- Language context ----
const LangCtx = createContext({ lang: 'es', setLang: () => {}, t: window.CONTENT.es });
function LangProvider({ children }) {
  const [lang, setLangState] = useState(() => {
    try { return localStorage.getItem('lang') || 'es'; } catch { return 'es'; }
  });
  const setLang = (v) => { setLangState(v); try { localStorage.setItem('lang', v); } catch {} };
  const t = window.CONTENT[lang];
  return <LangCtx.Provider value={{ lang, setLang, t }}>{children}</LangCtx.Provider>;
}
function useLang() { return useContext(LangCtx); }

// ---- reveal-on-scroll ----
function useReveal() {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) {
          el.classList.add('in');
          el.querySelectorAll('.fade-up').forEach(n => n.classList.add('in'));
          io.disconnect();
        }
      });
    }, { threshold: 0.12 });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return ref;
}

// ---- reduced motion ----
function useReducedMotion() {
  const [r, setR] = useState(() => window.matchMedia?.('(prefers-reduced-motion: reduce)').matches);
  useEffect(() => {
    const mq = window.matchMedia('(prefers-reduced-motion: reduce)');
    const h = () => setR(mq.matches);
    mq.addEventListener?.('change', h);
    return () => mq.removeEventListener?.('change', h);
  }, []);
  return r;
}

// ---- Custom cursor ----
function CustomCursor() {
  const dotRef = useRef(null);
  const ringRef = useRef(null);
  const reduce = useReducedMotion();
  useEffect(() => {
    if (reduce) return;
    if (matchMedia('(pointer:coarse)').matches) return;
    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 (dotRef.current) {
        dotRef.current.style.left = mx + 'px';
        dotRef.current.style.top = my + 'px';
      }
    };
    const loop = () => {
      rx += (mx - rx) * 0.18;
      ry += (my - ry) * 0.18;
      if (ringRef.current) {
        ringRef.current.style.left = rx + 'px';
        ringRef.current.style.top = ry + 'px';
      }
      raf = requestAnimationFrame(loop);
    };
    const onOver = (e) => {
      const r = ringRef.current; if (!r) return;
      const target = e.target;
      if (target.closest('a, button, .os-icon, .chip, .sq, [data-hover]')) r.classList.add('hover');
      else r.classList.remove('hover');
      if (target.matches('p, h1, h2, h3, h4, li, span, input, textarea')) r.classList.add('text');
      else r.classList.remove('text');
    };
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseover', onOver);
    raf = requestAnimationFrame(loop);
    return () => {
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseover', onOver);
      cancelAnimationFrame(raf);
    };
  }, [reduce]);
  if (reduce) return null;
  return (
    <>
      <div ref={dotRef} className="cursor-dot"></div>
      <div ref={ringRef} className="cursor-ring"></div>
    </>
  );
}

// ---- Magnetic button ----
function useMagnetic(strength = 12) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el || matchMedia('(pointer:coarse)').matches) 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);
      const dist = Math.hypot(x, y);
      const max = 80;
      if (dist < max) {
        const factor = (1 - dist / max) * strength;
        el.style.transform = `translate(${x / max * strength}px, ${y / max * strength}px)`;
      } else {
        el.style.transform = '';
      }
    };
    const onLeave = () => { el.style.transform = ''; };
    const parent = el.parentElement;
    parent?.addEventListener('mousemove', onMove);
    parent?.addEventListener('mouseleave', onLeave);
    return () => {
      parent?.removeEventListener('mousemove', onMove);
      parent?.removeEventListener('mouseleave', onLeave);
    };
  }, [strength]);
  return ref;
}

// ---- spotlight effect (mouse position CSS vars) ----
function useSpotlight() {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const onMove = (e) => {
      const r = el.getBoundingClientRect();
      el.style.setProperty('--mx', `${e.clientX - r.left}px`);
      el.style.setProperty('--my', `${e.clientY - r.top}px`);
    };
    el.addEventListener('mousemove', onMove);
    return () => el.removeEventListener('mousemove', onMove);
  }, []);
  return ref;
}

// ---- Nav ----
function Nav() {
  const { lang, setLang, t } = useLang();
  const [scrolled, setScrolled] = useState(false);
  const [open, setOpen] = useState(false);
  useEffect(() => {
    const h = () => setScrolled(window.scrollY > 30);
    window.addEventListener('scroll', h, { passive: true });
    return () => window.removeEventListener('scroll', h);
  }, []);
  const links = [
    { id: 'about', label: t.nav.about },
    { id: 'os', label: t.nav.os },
    { id: 'projects', label: t.nav.projects },
    { id: 'aura', label: t.nav.aura },
    { id: 'cafe', label: t.nav.cafe },
    { id: 'contact', label: t.nav.contact },
  ];
  return (
    <>
      <nav className={`nav ${scrolled ? 'scrolled' : ''}`} aria-label="Primary">
        <a href="#top" className="nav-logo">Angelo<span>.</span></a>
        <div className="nav-links">
          {links.map(l => <a key={l.id} href={`#${l.id}`}>{l.label}</a>)}
        </div>
        <div className="nav-right">
          <div className="lang-toggle" role="group" aria-label="Language">
            <button className={lang === 'es' ? 'active' : ''} onClick={() => setLang('es')}>ES</button>
            <button className={lang === 'en' ? 'active' : ''} onClick={() => setLang('en')}>EN</button>
          </div>
          <a className="nav-cta" href="https://github.com/AngeloVPerrotta" target="_blank" rel="noopener" aria-label="GitHub">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden><path d="M12 .5C5.7.5.5 5.7.5 12c0 5 3.3 9.3 7.8 10.8.6.1.8-.2.8-.6v-2.2c-3.2.7-3.9-1.4-3.9-1.4-.5-1.3-1.3-1.7-1.3-1.7-1.1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1.1 1.8 2.8 1.3 3.5 1 .1-.8.4-1.3.8-1.6-2.5-.3-5.2-1.3-5.2-5.7 0-1.3.5-2.3 1.2-3.1-.1-.3-.5-1.5.1-3.1 0 0 1-.3 3.3 1.2.9-.3 2-.4 3-.4s2.1.1 3 .4c2.3-1.5 3.3-1.2 3.3-1.2.7 1.6.2 2.9.1 3.1.7.8 1.2 1.8 1.2 3.1 0 4.5-2.7 5.4-5.2 5.7.4.3.8 1 .8 2v3c0 .3.2.7.8.6 4.5-1.5 7.8-5.8 7.8-10.8C23.5 5.7 18.3.5 12 .5z"/></svg>
            GitHub
          </a>
          <button className="nav-burger" onClick={() => setOpen(!open)} aria-label="Menu">
            <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M3 7h18M3 12h18M3 17h18"/></svg>
          </button>
        </div>
      </nav>
      <div className={`nav-drawer ${open ? 'open' : ''}`} onClick={() => setOpen(false)}>
        {links.map(l => <a key={l.id} href={`#${l.id}`}>{l.label}</a>)}
      </div>
    </>
  );
}

// ---- Boot screen ----
function BootScreen() {
  const [lines, setLines] = useState([]);
  const [gone, setGone] = useState(false);
  const reduce = useReducedMotion();
  useEffect(() => {
    if (reduce) { setGone(true); return; }
    const seq = [
      "> booting angelo.os",
      "> loading modules...",
      "> mounting filesystem [ok]",
      "> warm-up render pipeline...",
      "> ready"
    ];
    let i = 0;
    const tick = () => {
      if (i >= seq.length) {
        setTimeout(() => setGone(true), 280);
        return;
      }
      setLines(L => [...L, seq[i]]); i++;
      setTimeout(tick, 220);
    };
    tick();
  }, [reduce]);
  return (
    <div className={`boot ${gone ? 'gone' : ''}`} aria-hidden={gone}>
      <pre>
        {lines.map((l, idx) => <div key={idx}>{l}</div>)}
        <span className="cap" />
      </pre>
    </div>
  );
}

// ---- Typing rotator ----
function TypingRotator({ items, interval = 3800 }) {
  const reduce = useReducedMotion();
  const [idx, setIdx] = useState(0);
  const [text, setText] = useState(items[0]);
  const [phase, setPhase] = useState('hold');
  useEffect(() => {
    if (reduce) { setText(items[idx]); return; }
    let to;
    if (phase === 'hold') {
      to = setTimeout(() => setPhase('out'), interval);
    } else if (phase === 'out') {
      const target = items[idx];
      let len = target.length;
      const erase = () => {
        len -= 1;
        setText(target.slice(0, Math.max(0, len)));
        if (len <= 0) { setPhase('in'); setIdx((idx + 1) % items.length); }
        else to = setTimeout(erase, 18);
      };
      to = setTimeout(erase, 30);
    } else if (phase === 'in') {
      const target = items[idx];
      let len = 0;
      const type = () => {
        len += 1;
        setText(target.slice(0, len));
        if (len >= target.length) { setPhase('hold'); }
        else to = setTimeout(type, 32);
      };
      to = setTimeout(type, 40);
    }
    return () => clearTimeout(to);
  }, [phase, idx, items, interval, reduce]);
  return (
    <div className="rotator" aria-live="polite">
      <span>{text}</span><span className="caret"></span>
    </div>
  );
}

// expose
Object.assign(window, {
  LangProvider, useLang, useReveal, useReducedMotion,
  CustomCursor, useMagnetic, useSpotlight, Nav, BootScreen, TypingRotator
});
