/* Shared primitives, hooks, and data for Rishi D V's portfolio */
const { useState, useEffect, useRef, useCallback } = React;

/* ---------- Lucide icon wrapper ---------- */
function Icon({ name, size = 18, style }) {
  const ref = useRef(null);
  useEffect(() => {
    if (ref.current && window.lucide) {
      ref.current.innerHTML = "";
      const i = document.createElement("i");
      i.setAttribute("data-lucide", name);
      ref.current.appendChild(i);
      window.lucide.createIcons({ attrs: { width: size, height: size } });
    }
  }, [name, size]);
  return <span ref={ref} style={{ display: "inline-flex", alignItems: "center", ...style }} />;
}

/* ---------- useInView: fire once when element scrolls into view ----------
   Robust: does an immediate rect check (so above-the-fold content reveals
   right away even if the observer is throttled), then observes for the rest,
   with a safety fallback that guarantees content is never stuck hidden. */
function useInView(opts = {}) {
  const ref = useRef(null);
  const [inView, setInView] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    let done = false;
    const reveal = () => { if (!done) { done = true; setInView(true); } };

    // 1) immediate check — is it already in the viewport?
    const r = el.getBoundingClientRect();
    const vh = window.innerHeight || document.documentElement.clientHeight;
    if (r.top < vh * 0.95 && r.bottom > 0) { reveal(); return; }

    // 2) observe for when it scrolls in
    let io;
    if ("IntersectionObserver" in window) {
      io = new IntersectionObserver(
        ([e]) => { if (e.isIntersecting) { reveal(); io.disconnect(); } },
        { threshold: opts.threshold ?? 0.15, rootMargin: opts.rootMargin ?? "0px 0px -6% 0px" }
      );
      io.observe(el);
    } else {
      reveal();
    }
    // 3) safety net
    const t = setTimeout(reveal, 2600);
    return () => { if (io) io.disconnect(); clearTimeout(t); };
  }, []);
  return [ref, inView];
}

/* ---------- Reveal: scroll-triggered fade/slide; supports stagger via delay ---------- */
function Reveal({ children, delay = 0, dir = "up", style, as: Tag = "div", className = "", once }) {
  const [ref, inView] = useInView();
  const dirClass = dir === "left" ? "rv-l" : dir === "right" ? "rv-r" : dir === "scale" ? "rv-scale" : "rv-up";
  return (
    <Tag
      ref={ref}
      className={`rv ${dirClass} ${inView ? "in" : ""} ${className}`}
      style={{ transitionDelay: delay + "ms", ...style }}
    >
      {children}
    </Tag>
  );
}

/* ---------- WordReveal: headline that rises word-by-word on view ---------- */
function WordReveal({ text, style, wordStyle }) {
  const [ref, inView] = useInView({ threshold: 0.3 });
  const words = text.split(" ");
  return (
    <span ref={ref} style={style}>
      {words.map((w, i) => (
        <React.Fragment key={i}>
          <span className={`wword ${inView ? "in" : ""}`}>
            <span style={{ transitionDelay: 60 + i * 55 + "ms", ...wordStyle }}>{w}</span>
          </span>
          {i < words.length - 1 ? " " : null}
        </React.Fragment>
      ))}
    </span>
  );
}

/* ---------- useTypewriter: type out text once visible ---------- */
function useTypewriter(text, { speed = 26, start = true, startDelay = 0 } = {}) {
  const [out, setOut] = useState("");
  const [done, setDone] = useState(false);
  useEffect(() => {
    if (!start) return;
    // frozen/hidden timeline → show full text instantly (rAF won't advance)
    if (document.hidden || document.documentElement.classList.contains("anim-off")) {
      setOut(text); setDone(true); return;
    }
    let i = 0, raf, t0;
    const begin = () => {
      const tick = (now) => {
        if (!t0) t0 = now;
        const target = Math.floor((now - t0) / speed);
        if (target > i) { i = target; setOut(text.slice(0, i)); }
        if (i < text.length) raf = requestAnimationFrame(tick);
        else setDone(true);
      };
      raf = requestAnimationFrame(tick);
    };
    const to = setTimeout(begin, startDelay);
    return () => { clearTimeout(to); cancelAnimationFrame(raf); };
  }, [text, start, speed, startDelay]);
  return [out, done];
}

/* ---------- Magnetic: element nudges toward cursor ---------- */
function Magnetic({ children, strength = 0.35, style, className, as: Tag = "div" }) {
  const ref = useRef(null);
  const onMove = (e) => {
    const el = ref.current; if (!el) return;
    const r = el.getBoundingClientRect();
    const x = (e.clientX - (r.left + r.width / 2)) * strength;
    const y = (e.clientY - (r.top + r.height / 2)) * strength;
    el.style.transform = `translate(${x}px,${y}px)`;
  };
  const reset = () => { if (ref.current) ref.current.style.transform = "translate(0,0)"; };
  return (
    <Tag ref={ref} onMouseMove={onMove} onMouseLeave={reset} className={className}
      style={{ transition: "transform .25s var(--ease-out)", ...style }}>
      {children}
    </Tag>
  );
}

/* ---------- useScrollProgress: 0..1 across the page ---------- */
function useScrollY() {
  const [y, setY] = useState(0);
  useEffect(() => {
    const on = () => setY(window.scrollY);
    window.addEventListener("scroll", on, { passive: true });
    on();
    return () => window.removeEventListener("scroll", on);
  }, []);
  return y;
}

/* ============================================================
   DATA
   ============================================================ */

const TRAITS = [
  {
    n: "01", key: "first-principles", title: "First-principles thinker",
    line: "I go one layer deeper.",
    body: "I rarely accept vague intuition. I pull a problem apart until the mental model feels complete — why exactly, what changes, what's actually happening underneath — instead of settling for the surface-level explanation.",
  },
  {
    n: "02", key: "generalist", title: "Generalist",
    line: "Many domains, one instinct.",
    body: "My curiosity spans AI infrastructure, distributed systems, product, finance, and visual design. One moment it's consensus models and datacenter economics, the next it's a new product idea or an emerging tool worth understanding.",
  },
  {
    n: "03", key: "high-agency", title: "High-agency problem solver",
    line: "I'd rather build it than wait.",
    body: "I enjoy solving hard problems independently and exploring ideas beyond conventional boundaries. I build the smallest thing that proves an idea, put it in front of reality, and iterate from there.",
  },
  {
    n: "04", key: "systems", title: "Systems thinker",
    line: "Scale, tradeoffs, second-order effects.",
    body: "I think in terms of mechanics, scalability, and long-term implications. How does this scale? What's the real tradeoff? What breaks at the next order of magnitude? That framing shapes everything I build.",
  },
];

const PROJECTS = [
  {
    id: "claimcircle", n: "01", title: "ClaimCircle", year: "2025",
    motif: "circle",
    sub: "Circle any claim. Verify it instantly.",
    tagline: "A Chrome extension that fact-checks anything online with a circular mouse gesture.",
    role: "Solo — design & engineering",
    stack: ["Chrome Extension", "LLM tool-calling", "Search APIs", "JavaScript"],
    problem: "The internet is flooded with misinformation, AI-generated content, and unverifiable claims. Fact-checking is still slow and manual — you have to open tabs, search sources, and compare for yourself, which almost nobody does in real time.",
    build: "A browser extension where you circle any content with your mouse to verify it. It captures the selected region, extracts context, and runs a search + LLM tool-calling pipeline to identify the underlying claim, find supporting or conflicting evidence, and summarise source-backed findings instantly.",
    outcome: "Turns fact-checking from a multi-tab chore into a single gesture — circle a claim, get a source-backed verdict in seconds.",
  },
  {
    id: "captcha", n: "02", title: "Adaptive Distributed CAPTCHA", year: "2025",
    motif: "grid",
    sub: "Turning bot defense into useful computation.",
    site: "https://github.com/Rishi94523/Capstone",
    tagline: "A proof-of-work CAPTCHA that converts wasted compute into real AI workloads.",
    role: "Systems design & engineering",
    stack: ["Proof-of-work", "Distributed ML", "Inference", "Systems"],
    problem: "Modern AI bypasses traditional CAPTCHAs, forcing sites into an endless cat-and-mouse of harder, more frustrating puzzles that still fail to stop large-scale automated abuse and DoS attacks.",
    build: "A proof-of-work CAPTCHA where each request is bound to a distributed ML inference task. Clients must finish the computation before access is granted, and difficulty scales adaptively with traffic. Increasing computational complexity makes it infeasible for bad actors to spam the network. The otherwise-wasted work is redirected into useful AI workloads — data labeling, lightweight inference, and human-in-the-loop verification.",
    outcome: "Makes large-scale abuse computationally infeasible while transforming CAPTCHA solving into useful distributed computation at internet scale.",
  },
  {
    id: "headlineheist", n: "03", title: "HeadlineHeist", year: "2024",
    motif: "cards",
    sub: "Making news consumption feel like gameplay.",
    site: "https://headlineheist.com",
    tagline: "A multiplayer semantic-deduction game that turns reading the news into play.",
    role: "Game design & engineering",
    stack: ["Multiplayer", "Semantic reasoning", "Real-time", "Web"],
    problem: "News competes against platforms engineered for engagement — social feeds, streaming, games, infinite scroll. So news consumption among younger audiences keeps falling and outlets struggle to hold attention.",
    build: "A multiplayer game where players uncover real news stories by connecting semantically related fragments. Linking the right cards progressively reveals the underlying article, blending pattern recognition, contextual reasoning, and collaborative deduction into competitive play.",
    outcome: "Re-frames news discovery as something you actively play and reason about, rather than passively scroll past.",
  },
  {
    id: "memoryline", n: "04", title: "MemoryLine", year: "2024",
    motif: "timeline",
    sub: "Reconstructing human history through context.",
    site: "https://memorylyn.com",
    tagline: "A multiplayer game about ordering history by feel, not by date.",
    role: "Game design & engineering",
    stack: ["Multiplayer", "Game design", "Web"],
    problem: "Most people experience history as disconnected facts and dates. Pure memorization fails because humans are far better at relative sequence and context than at recalling exact timestamps.",
    build: "A multiplayer chronological-ranking game where players arrange culturally and historically significant images into their correct relative order — geopolitics, wars, pop culture, tech milestones, sports, internet history. You compete to prove the strongest contextual grasp of how events unfolded.",
    outcome: "Trains intuition for how the world actually unfolded, turning history from rote dates into a sense of sequence.",
  },
];

/* ChatGPT's description, split into paragraphs + pulled-out probing questions */
const GPT_INTRO = "You come across as someone who is intensely curious, analytical, and unusually interdisciplinary.";
const GPT_PARAS = [
  "The kinds of questions you ask jump across AI infrastructure, distributed systems, semiconductor economics, cloud computing, startup strategy, finance, software architecture, product thinking, emerging technologies, and even visual design — but beneath all of them lies a consistent pattern: you do not just look for answers, you try to understand systems from first principles.",
  "What stands out is the way you think through problems. You naturally gravitate toward underlying mechanics, scalability, optimization, tradeoffs, and long-term implications instead of surface-level explanations. Whether exploring GPU scaling and datacenter economics, questioning consistency models in distributed systems, understanding how Kubernetes components interact internally, analyzing SaaS businesses under AI pressure, evaluating startup opportunities, or dissecting how programming abstractions actually work at runtime — your instinct is always to go one layer deeper.",
  "Another thing that becomes obvious is that you rarely accept vague intuition. You keep pushing until the mental model feels complete.",
  "You also come across as highly adaptable and multidimensional. Your interests are not confined to one narrow domain — they span technology, business, systems, strategy, and emerging trends. There is a visible balance between technical depth and exploratory thinking: one moment you are discussing AI hardware supply chains or distributed consensus, and the next you are analyzing a new product idea, studying high-growth startups, or exploring new tools people are beginning to adopt.",
  "Even as a student, your mindset reflects someone who enjoys solving hard problems independently and exploring ideas beyond conventional boundaries. You approach learning less as memorization and more as constructing complete mental models of how things work.",
  "Overall, you come across as someone with strong first-principles thinking, intellectual flexibility, and a natural inclination toward innovation, systems thinking, and high-agency problem solving.",
];
const GPT_QUESTIONS = ["Why exactly?", "What changes?", "How does this scale?", "What's the actual tradeoff?", "Isn't this contradictory?", "What is really happening underneath?"];

const NAV = [
  { id: "gpt", label: "intro" },
  { id: "work", label: "work" },
];

Object.assign(window, {
  Icon, useInView, Reveal, WordReveal, useTypewriter, Magnetic, useScrollY,
  TRAITS, PROJECTS, GPT_INTRO, GPT_PARAS, GPT_QUESTIONS, NAV,
});
