// hooks.jsx — shared hooks + tiny utilities
const { useState, useEffect, useRef, useCallback, createContext, useContext } = React;

const SiteCtx = createContext(null);

// IntersectionObserver-driven reveal hook
function useReveal(opts = {}) {
  const ref = useRef(null);
  const [shown, setShown] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    if (!("IntersectionObserver" in window)) { setShown(true); return; }
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting) { setShown(true); io.disconnect(); }
      });
    }, { threshold: opts.threshold || 0.15, rootMargin: opts.rootMargin || "0px" });
    io.observe(ref.current);
    return () => io.disconnect();
  }, []);
  return [ref, shown];
}

// Tracks current page based on scroll position within snap-root
function useCurrentPage(rootRef, pageIds) {
  const [current, setCurrent] = useState(pageIds[0]);
  useEffect(() => {
    const root = rootRef.current;
    if (!root) return;
    const onScroll = () => {
      const y = root.scrollTop + window.innerHeight / 2;
      let best = pageIds[0];
      for (const id of pageIds) {
        const el = document.getElementById(id);
        if (!el) continue;
        const top = el.offsetTop;
        if (y >= top) best = id;
      }
      setCurrent(best);
    };
    onScroll();
    root.addEventListener("scroll", onScroll, { passive: true });
    return () => root.removeEventListener("scroll", onScroll);
  }, [rootRef, pageIds.join(",")]);
  return current;
}

// CountUp number with ease-out
function CountUp({ target, duration = 1100, suffix = "", motion = true }) {
  const [val, setVal] = useState(motion ? 0 : target);
  const ref = useRef(null);
  const [started, setStarted] = useState(!motion);
  useEffect(() => {
    if (!ref.current || !motion) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) { setStarted(true); io.disconnect(); } });
    }, { threshold: 0.4 });
    io.observe(ref.current);
    return () => io.disconnect();
  }, [motion]);
  useEffect(() => {
    if (!started || !motion) { setVal(target); return; }
    const start = performance.now();
    let raf;
    const tick = (t) => {
      const p = Math.min(1, (t - start) / duration);
      const eased = 1 - Math.pow(1 - p, 3);
      setVal(Math.round(target * eased));
      if (p < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [started, target, duration, motion]);
  const formatted = val >= 1000 ? val.toLocaleString() : val.toString();
  return <span ref={ref}>{formatted}{suffix}</span>;
}

// I18N (kept minimal, EN/ZH for nav + key copy)
const I18N = {
  en: {
    nav_home: "Home", nav_cases: "Case Studies", nav_projects: "Projects", nav_resume: "Resume", nav_chat: "Ask AI",
    lang: "中",
    home_eyebrow: "AI Product Manager · Available 2026",
    home_tagline_a: "I build things ",
    home_tagline_b: "and evaluate",
    home_tagline_c: " them.",
    home_sub: "AI Product Manager at Chinadaas, working on qibook.com (a B2B business-intelligence product for banks and investors). I write about evals, agent workflows, and the side projects I ship after work.",
    cta_cases: "Read the case studies",
    cta_chat: "Ask my AI clone →",
    scroll_hint: "Scroll",
    cases_eyebrow: "Case Studies",
    cases_title: "Seven projects, seven writeups.",
    cases_sub: "Each one hit something the plan didn't account for. These are the post-mortems.",
    projects_eyebrow: "Side Projects",
    projects_title: "Things I built after work.",
    projects_sub: "Small tools I made for myself — prototype, ship to Vercel, see what comes back. Click to open.",
    resume_eyebrow: "Resume",
    resume_title: "One page. Print or download.",
    resume_sub: "Same content as candidate.md, formatted for paper.",
    download: "Download PDF",
    print: "Print",
    chat_eyebrow: "Ask AI",
    chat_title: "Talk to my AI clone.",
    chat_sub: "It's read everything on this site and answers in my voice. Pick a frame — CEO, HR, or founder — to tilt the answer toward what you care about.",
    chat_persona_ceo_name: "CEO Mode",
    chat_persona_ceo_desc: "Strategic fit, business impact, ROI.",
    chat_persona_hr_name: "HR Mode",
    chat_persona_hr_desc: "Culture, communication, growth trajectory.",
    chat_persona_founder_name: "Founder Mode",
    chat_persona_founder_desc: "Builder energy, 0→1 instinct, urgency.",
    chat_suggestions: "Suggested questions",
    chat_placeholder: "Ask why you should hire Ming…",
    chat_send: "Send",
    fab: "Why hire me?",
  },
  zh: {
    nav_home: "首页", nav_cases: "案例", nav_projects: "Demo", nav_resume: "简历", nav_chat: "AI 对话",
    lang: "EN",
    home_eyebrow: "AI 产品经理 · 2026 可入职",
    home_tagline_a: "炼",
    home_tagline_b: "创造",
    home_tagline_c: "，也炼评估",
    home_sub: "AI 产品经理。最近在中数智汇做 qibook.com——一款服务银行和投资机构的 B2B 商业智能产品。这里记录我做过的项目、写过的复盘，和下班时间搭的一些小东西。",
    cta_cases: "看完整案例 →",
    cta_chat: "和我的 AI 分身聊聊 →",
    scroll_hint: "向下滚",
    cases_eyebrow: "案例复盘",
    cases_title: "七个项目，七篇复盘。",
    cases_sub: "每一个都撞到了计划里没提过的东西。这是事后复盘。",
    projects_eyebrow: "Side Project",
    projects_title: "下班搭的小东西。",
    projects_sub: "自己用着方便做的几个小工具——做原型，上 Vercel，看数据。点开看。",
    resume_eyebrow: "简历",
    resume_title: "一页纸。打印或下载。",
    resume_sub: "和 candidate.md 内容一致，按 A4 排版。",
    download: "下载 PDF",
    print: "打印",
    chat_eyebrow: "AI 对话",
    chat_title: "和我的 AI 分身聊。",
    chat_sub: "它读过这个站点的所有内容，用我的口吻回答。选一个视角——CEO、HR、或者创始人——能让回答更贴近你想了解的方向。",
    chat_persona_ceo_name: "CEO 模式",
    chat_persona_ceo_desc: "战略契合度、业务影响、ROI。",
    chat_persona_hr_name: "HR 模式",
    chat_persona_hr_desc: "文化、沟通、成长轨迹。",
    chat_persona_founder_name: "创始人模式",
    chat_persona_founder_desc: "Builder 能量、0→1 直觉、紧迫感。",
    chat_suggestions: "建议问题",
    chat_placeholder: "问问为什么应该雇慕铭……",
    chat_send: "发送",
    fab: "为什么雇我？",
  },
};

window.MM_HOOKS = { SiteCtx, useReveal, useCurrentPage, CountUp, I18N };
