/* global React, Reveal, Counter, BarChart, Magnetic, DragScroll, Icon,
   MARQUEE, FACTS, WORK, SKILL_CATS, SKILLS, ACHIEVEMENTS */
const { useState, useEffect, useRef } = React;

const LINKS = {
  email: "mailto:nreghunandanan@gmail.com",
  linkedin: "https://www.linkedin.com/in/nimishareghunandanan",
  cv: "https://drive.google.com/file/d/176lZNI09q0Xna_1Hx6CYWGFsWq3gFYTj/view?usp=share_link",
  cal: "https://www.cal.eu/nimishar/30min",
};

/* ===================== NAV ===================== */
function Nav() {
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const f = () => setScrolled(window.scrollY > 40);
    f(); window.addEventListener("scroll", f, { passive: true });
    return () => window.removeEventListener("scroll", f);
  }, []);
  return (
    <nav className={`nav ${scrolled ? "scrolled" : ""}`}>
      <a href="#top" className="logo">Nimisha</a>
      <div className="links">
        <a href="#about">About</a>
        <a href="#services">Services</a>
        <a href="#skills">Skills</a>
        <a href="#highlights">Highlights</a>
      </div>
      <a href="#contact" className="btn btn-dark" style={{ padding: "9px 18px", fontSize: 13.5 }}>
        <span className="dot" /> Contact
      </a>
    </nav>
  );
}

/* ===================== HERO NAME ===================== */
function HeroName() {
  const elRef = useRef(null);
  useEffect(() => {
    const el = elRef.current;
    if (!el) return;

    // ── Constants ─────────────────────────────────────────────────
    const ENTRANCE_MS   = 900;   // entrance animation duration
    const TRANSITION_PX = 350;   // scroll distance for phase 2
    const END_TOP    = 24;       // 1.5rem — final logo top
    const END_LEFT   = 32;       // 2rem   — final logo left
    const END_SIZE   = 20;       // ~1.25rem — logo font-size
    const W_HERO     = 800;      // font-weight in hero / entrance
    const W_LOGO     = 500;      // font-weight as nav logo
    const LS_HERO    = -0.02;    // letter-spacing (em) at hero size
    const LS_LOGO    = 0.02;     // letter-spacing (em) at logo size
    const FILL       = 0.96;     // fraction of vw to fill
    const START_FRAC = 0.15;     // entrance start size as fraction of largePx
    const START_CY   = 0.70;     // entrance start vertical-center as fraction of vh

    let raf = null;
    let phase = "waiting";       // "waiting" | "entering" | "scrolling"
    let enterStart = 0;
    let largePx = 200;
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

    const ease = (p) =>          // cubic ease-in-out
      p < 0.5 ? 4 * p * p * p : 1 - Math.pow(-2 * p + 2, 3) / 2;

    // ── Nav helper ─────────────────────────────────────────────────
    const setNav = (opacity, interactive) => {
      const nav = document.querySelector(".nav");
      if (!nav) return;
      nav.style.opacity = String(opacity);
      nav.style.pointerEvents = interactive ? "auto" : "none";
    };

    // ── Fill-width measurement ─────────────────────────────────────
    // Sets hero styles, measures, leaves element in hero state.
    // Entire read/write sequence is synchronous — no paint in between.
    const measureLarge = () => {
      el.style.fontSize = "200px";
      el.style.fontVariationSettings = `"wght" ${W_HERO}`;
      el.style.letterSpacing = LS_HERO + "em";
      const w = el.getBoundingClientRect().width;
      largePx = 200 * (window.innerWidth * FILL) / w;
    };

    // ── Phase 1: entrance ─────────────────────────────────────────
    const runEntrance = (now) => {
      const elapsed = now - enterStart;
      const p = Math.min(elapsed / ENTRANCE_MS, 1);
      const t = ease(p);

      const vw = window.innerWidth;
      const vh = window.innerHeight;
      const startSize = largePx * START_FRAC;
      const fs = startSize + (largePx - startSize) * t;

      el.style.fontSize = fs + "px";
      el.style.fontVariationSettings = `"wght" ${W_HERO}`;
      el.style.letterSpacing = LS_HERO + "em";
      el.style.opacity = "1";

      const { width: w, height: h } = el.getBoundingClientRect();
      // Horizontal: always centred
      el.style.left = ((vw - w) / 2) + "px";
      // Vertical: centre rises from START_CY → 0.5 (viewport centre)
      const cy = (START_CY + (0.5 - START_CY) * t) * vh;
      el.style.top = (cy - h / 2) + "px";

      if (p < 1) {
        raf = requestAnimationFrame(runEntrance);
      } else {
        // Entrance complete — unlock scroll, hand off to scroll driver
        document.body.style.overflow = "";
        phase = "scrolling";
        window.addEventListener("scroll", onScroll, { passive: true });
        // Snap to the exact large-centred state before any scroll
        scrollUpdate();
      }
    };

    // ── Phase 2: scroll-driven ─────────────────────────────────────
    const scrollUpdate = () => {
      raf = null;
      const p = Math.min(window.scrollY / TRANSITION_PX, 1);
      const t = ease(p);

      const vw = window.innerWidth;
      const vh = window.innerHeight;

      // Font size
      const fs = largePx + (END_SIZE - largePx) * t;
      el.style.fontSize = fs + "px";

      // Weight: 800 → 500
      const w = W_HERO + (W_LOGO - W_HERO) * t;
      el.style.fontVariationSettings = `"wght" ${Math.round(w)}`;

      // Letter-spacing: tight → open
      el.style.letterSpacing = (LS_HERO + (LS_LOGO - LS_HERO) * t) + "em";

      // Position: centred → top-left
      const { width: ew, height: eh } = el.getBoundingClientRect();
      el.style.top  = ((vh - eh) / 2 + (END_TOP  - (vh - eh) / 2) * t) + "px";
      el.style.left = ((vw - ew) / 2 + (END_LEFT - (vw - ew) / 2) * t) + "px";

      // Nav fades in over the same eased progress
      setNav(t, t >= 0.99);
    };

    const onScroll = () => { if (!raf) raf = requestAnimationFrame(scrollUpdate); };

    const onResize = () => {
      measureLarge();
      if (phase === "scrolling" && !raf) raf = requestAnimationFrame(scrollUpdate);
    };

    // ── Boot: wait for real font before starting ───────────────────
    document.body.style.overflow = "hidden"; // block scroll during wait + entrance

    document.fonts.ready.then(() => {
      measureLarge();

      if (reduce) {
        // Skip all animation, jump straight to logo state
        el.style.fontSize = END_SIZE + "px";
        el.style.fontVariationSettings = `"wght" ${W_LOGO}`;
        el.style.letterSpacing = LS_LOGO + "em";
        el.style.top  = END_TOP  + "px";
        el.style.left = END_LEFT + "px";
        el.style.opacity = "1";
        document.body.style.overflow = "";
        phase = "scrolling";
        setNav(1, true);
        window.addEventListener("scroll", onScroll, { passive: true });
        window.addEventListener("resize", onResize);
        return;
      }

      window.addEventListener("resize", onResize);
      phase = "entering";
      enterStart = performance.now();
      raf = requestAnimationFrame(runEntrance);
    });

    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onResize);
      if (raf) cancelAnimationFrame(raf);
      document.body.style.overflow = "";
    };
  }, []);

  return (
    <a ref={elRef} className="hero-name"
       href="#"
       onClick={(e) => { e.preventDefault(); window.scrollTo({ top: 0, behavior: "smooth" }); }}>
      NIMISHA
    </a>
  );
}

/* ===================== HERO ===================== */
function Hero() {
  return (
    <header className="hero wrap" id="top">
      <div className="hero-grid">
        <Reveal>
          <h1 style={{ marginTop: 24 }}>
            Stories that make brands impossible to <span className="italic clay">scroll&nbsp;past.</span>
          </h1>
          <p className="sub">
            Social, content and community leader with 7+ years building audiences that show up — driving sell-out launches and record-breaking moments for global houses.
          </p>
          <div className="cta-row">
            <Magnetic className="btn btn-dark" strength={0.35} onClick={() => document.getElementById("services").scrollIntoView()}>
              View services <Icon.arrow />
            </Magnetic>

          </div>
        </Reveal>
        <Reveal delay={120}>
          <div className="hero-photo">
            <span className="ring" />
            <img src={(typeof window !== "undefined" && window.__resources && window.__resources.heroPhoto) || "assets/nimisha.png"} alt="Nimisha Reghunandanan" />
          </div>
        </Reveal>
      </div>

      <div className="marquee">
        <div className="marquee-track">
          {[...MARQUEE, ...MARQUEE].map((b, i) => <span key={i}>{b}</span>)}
        </div>
      </div>
    </header>
  );
}

/* ===================== ABOUT ===================== */
function About() {
  const platforms = ["Meta", "TikTok", "YouTube", "X", "LinkedIn", "Pinterest", "Snap"];
  const eastPlatforms = ["WeChat", "Little Red Book", "Weibo", "KakaoTalk", "LINE"];
  return (
    <section className="section wrap" id="about">
      <div className="about-grid">
        <Reveal className="about-left">
          <h2>Fluent in strategy and the work itself.</h2>
          <p className="about-lead">Audience behaviour and performance data direct what gets produced — equally at home in strategy and hands-on execution, whether that's content, copy or art direction.</p>
          <div className="platforms">
            {platforms.map((p) => <span className="chip" key={p}>{p}</span>)}
          </div>
          <div className="platforms" style={{ marginTop: 8 }}>
            {eastPlatforms.map((p) => <span className="chip" key={p}>{p}</span>)}
          </div>
        </Reveal>
        <Reveal className="about-body" delay={90}>
          <p>Seven-plus years building audiences that show up, driving sell-out launches and breaking sales records for global brands. Work spans Meta, TikTok, YouTube, X, LinkedIn, Pinterest and Snap, across the US, EMEA and APAC — shaping brand voice, programming content and running creator and ambassador networks.</p>
          <p>Currently deep in creative AI tools to prototype campaigns, generate variants and produce content at speed — embedded in the scenes forming around them.</p>
        </Reveal>
      </div>
    </section>
  );
}

/* ===================== FACTS ===================== */
function Facts() {
  return (
    <section className="wrap" style={{ padding: "20px 40px 0" }}>
      <Reveal className="facts">
        <div className="facts-grid">
          {FACTS.map((f, i) => (
            <div className="fact" key={i}>
              <Counter value={f.value} prefix={f.prefix || ""} suffix={f.suffix || ""} dur={1400 + i * 150} />
              <div className="lbl">{f.label}</div>
            </div>
          ))}
        </div>
      </Reveal>
    </section>
  );
}

/* ===================== SERVICES ===================== */
function StackFolder({ item, i, onOpen }) {
  const open = () => onOpen(i);
  return (
    <div className="folder" style={{ "--i": i, zIndex: i + 1 }} onClick={open} role="button" tabIndex={0}
      aria-label={`Open ${item.name}`}
      onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); open(); } }}>
      <div className="folder-head">
        <span className="folder-tab" />
        <div>
          <div className="folder-role">{item.name}</div>
          <div className="folder-brand">{item.tag}</div>
        </div>
      </div>
      <div className="folder-content">
        <div className="folder-teaser">
          <div className="ft-main">
            <p className="ft-overview">{item.overview}</p>
            <div className="ft-tags">
              {item.tags.map((t) => <span className="ft-tag" key={t}>{t}</span>)}
            </div>
            <span className="ft-open">Open folder <Icon.arrow /></span>
          </div>
          <div className="ft-side">
            <div className="svc-stat">
              <div className="svc-stat-val">{item.stat.value}</div>
              <div className="svc-stat-lbl">{item.stat.label}</div>
            </div>
            <div className="ft-brands">
              {item.brands.slice(0, 5).map((b) => <span className="chan" key={b}>{b}</span>)}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

function Services({ onOpen }) {
  const stackRef = useRef(null);
  useEffect(() => {
    const stack = stackRef.current;
    if (!stack) return;
    const cards = Array.from(stack.querySelectorAll(".folder"));
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    let raf = null;
    const peek = () => (window.innerWidth <= 760 ? 54 : 70);
    const base = () => (window.innerWidth <= 760 ? 74 : 96);
    const RANGE = 300;
    const update = () => {
      raf = null;
      const p0 = peek(), b0 = base();
      let activeIdx = 0;
      cards.forEach((el, i) => {
        const next = cards[i + 1];
        let prog = 0;
        if (next) {
          const nextPinned = b0 + (i + 1) * p0;
          const nextTop = next.getBoundingClientRect().top;
          prog = Math.min(Math.max(1 - (nextTop - nextPinned) / RANGE, 0), 1);
        }
        if (!reduce) el.style.setProperty("--p", prog.toFixed(3));
        const stacked = prog > 0.5;
        el.classList.toggle("stacked", stacked);
        if (stacked) activeIdx = i + 1;
      });
      activeIdx = Math.min(activeIdx, cards.length - 1);
      cards.forEach((el, i) => el.classList.toggle("active", i === activeIdx));
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(update); };
    update();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
      if (raf) cancelAnimationFrame(raf);
    };
  }, []);
  return (
    <section className="section wrap" id="services" style={{ paddingBottom: 0 }}>
      <Reveal className="section-head">
        <h2>How I can help you grow.</h2>
        <p>Five ways I work with brands — scroll to flip through the folders, then open any one for the full case study.</p>
      </Reveal>
      <div className="folder-stack" ref={stackRef}>
        {SERVICES.map((item, i) => (
          <StackFolder key={i} item={item} i={i} onOpen={onOpen} />
        ))}
      </div>
    </section>
  );
}

/* ===================== SKILLS ===================== */
function Skills() {
  const [active, setActive] = useState("strategy");
  const colorOf = (cat) => (SKILL_CATS.find((c) => c.id === cat) || {}).color || "#8C8775";
  return (
    <section className="section wrap" id="skills" style={{ background: "var(--cream)", borderRadius: 28, paddingTop: 56, paddingBottom: 16 }}>
      <div style={{ padding: "8px 0" }}>
        <Reveal className="section-head">
          <h2>What I bring to the table.</h2>
          <p style={{ whiteSpace: "nowrap" }}>Filter by focus — strategy, creative, leadership, the tools I run on, and the AI stack I build with.</p>
        </Reveal>
        <Reveal>
          <div className="skill-filter">
            {SKILL_CATS.map((c) => (
              <button key={c.id} className={`fbtn ${active === c.id ? "active" : ""}`} onClick={() => setActive(c.id)}>
                {c.label}
              </button>
            ))}
          </div>
          <div className="skill-grid">
            {SKILLS.map((s, i) => {
              const show = active === "all" || s.cat === active;
              return (
                <div className={`skill ${show ? "" : "hide"}`} key={i}>
                  <span className="sk-dot" style={{ background: colorOf(s.cat) }} />
                  <span>{s.name}</span>
                </div>
              );
            })}
          </div>
        </Reveal>
      </div>
    </section>
  );
}

/* ===================== ACHIEVEMENTS ===================== */
function Achievements() {
  return (
    <section className="section" id="highlights">
      <div className="wrap">
        <Reveal className="gallery-head">
          <div className="section-head" style={{ margin: 0 }}>
            <h2>Moments I'm proud of.</h2>
          </div>
          <div className="gallery-hint"><Icon.drag /> Drag to explore</div>
        </Reveal>
      </div>
      <div className="wrap" style={{ paddingRight: 0 }}>
        <DragScroll className="gallery">
          {ACHIEVEMENTS.map((a, i) => (
            <div className={`gcard ${a.tone}`} key={i}>
              <div className="g-tag">{a.tag}</div>
              <div className="g-num" style={{ marginTop: 14 }}>{a.num}</div>
              <div className="g-title">{a.title}</div>
              <div className="g-desc">{a.desc}</div>
            </div>
          ))}
          <div style={{ flex: "0 0 40px" }} />
        </DragScroll>
      </div>
    </section>
  );
}

/* ===================== CONTACT ===================== */
function Contact() {
  const ref = useRef(null);
  const glowRef = useRef(null);
  const onMove = (e) => {
    const r = ref.current.getBoundingClientRect();
    const x = ((e.clientX - r.left) / r.width) * 100;
    const y = ((e.clientY - r.top) / r.height) * 100;
    glowRef.current.style.background = `radial-gradient(500px circle at ${x}% ${y}%, rgba(176,101,74,0.20), transparent 60%)`;
  };
  return (
    <section className="contact" id="contact" ref={ref} onMouseMove={onMove}>
      <div className="glow" ref={glowRef} style={{ background: "radial-gradient(500px circle at 50% 30%, rgba(176,101,74,0.16), transparent 60%)" }} />
      <div className="wrap contact-inner">
        <Reveal>
          <h2>Have a brand worth<br />following? <span className="italic clay">Let's talk.</span></h2>
          <p className="contact-sub">Open to senior social, content and community roles — and the occasional good idea over coffee.</p>
        </Reveal>
        <Reveal delay={80}>
          <div className="magnet-wrap">
            <a href={LINKS.cal} target="_blank" rel="noopener">
              <Magnetic className="magnet" strength={0.5}><Icon.cal /> Book a 30-min call</Magnetic>
            </a>
          </div>
          <div className="contact-links">
            <a className="clink" href={LINKS.email}><Icon.mail /> Email me</a>
            <a className="clink" href={LINKS.linkedin} target="_blank" rel="noopener"><Icon.linkedin /> LinkedIn</a>
            <a className="clink" href={LINKS.cv} target="_blank" rel="noopener"><Icon.download /> Download CV</a>
          </div>
        </Reveal>
        <div className="contact-foot">
          <span>Nimisha Reghunandanan</span>
          <span>Working across US, EMEA and APAC</span>
        </div>
      </div>
    </section>
  );
}

/* ===================== STICKY FAB ===================== */
function ContactFab() {
  const [show, setShow] = useState(false);
  const [near, setNear] = useState(false);
  useEffect(() => {
    const f = () => {
      setShow(window.scrollY > 600);
      const c = document.getElementById("contact");
      if (c) {
        const r = c.getBoundingClientRect();
        setNear(r.top < window.innerHeight * 0.9);
      }
    };
    f(); window.addEventListener("scroll", f, { passive: true });
    return () => window.removeEventListener("scroll", f);
  }, []);
  return (
    <button className={`fab ${show ? "show" : ""} ${near ? "hide-near" : ""}`}
      onClick={() => document.getElementById("contact").scrollIntoView({ behavior: "smooth" })}>
      <span style={{ display: "inline-flex" }}><Icon.mail /></span> Contact
    </button>
  );
}

/* ===================== MOBILE NAV ===================== */
function MobileNav() {
  const [active, setActive] = useState("");
  useEffect(() => {
    const ids = ["about", "services", "skills", "contact"];
    const io = new IntersectionObserver(
      (entries) => { entries.forEach((e) => { if (e.isIntersecting) setActive(e.target.id); }); },
      { threshold: 0.3 }
    );
    ids.forEach((id) => { const el = document.getElementById(id); if (el) io.observe(el); });
    return () => io.disconnect();
  }, []);
  const go = (id) => document.getElementById(id)?.scrollIntoView({ behavior: "smooth" });
  const items = [
    { id: "about", label: "About" },
    { id: "services", label: "Work" },
    { id: "skills", label: "Skills" },
    { id: "contact", label: "Contact" },
  ];
  return (
    <nav className="mobile-nav" aria-label="Section navigation">
      {items.map(({ id, label }) => (
        <button key={id} className={`mnav-btn ${active === id ? "active" : ""}`} onClick={() => go(id)}>
          {label}
        </button>
      ))}
    </nav>
  );
}

/* ===================== APP ===================== */
function App() {
  const [active, setActive] = useState(null);
  const savedScroll = useRef(0);

  const open = (i) => {
    savedScroll.current = window.scrollY;
    document.body.style.overflow = "hidden";
    setActive(i);
    history.pushState({ svc: i }, "", `#service-${SERVICES[i].no}`);
  };
  const close = () => {
    const y = savedScroll.current;
    document.body.style.overflow = "";
    if ((location.hash || "").indexOf("#service-") === 0) history.back();
    else setActive(null);
    requestAnimationFrame(() => window.scrollTo({ top: y, behavior: "instant" }));
  };
  useEffect(() => {
    const sync = () => {
      const m = (location.hash || "").match(/#service-(\d+)/);
      if (m) {
        const idx = SERVICES.findIndex((s) => s.no === m[1]);
        setActive(idx >= 0 ? idx : null);
      } else {
        setActive(null);
        document.body.style.overflow = "";
      }
    };
    window.addEventListener("popstate", sync);
    sync();
    return () => window.removeEventListener("popstate", sync);
  }, []);

  /* "Wait, come back" tab title */
  useEffect(() => {
    const original = "Nimisha Reghunandanan — Social, Content & Community";
    document.title = original;
    const onHide = () => { if (document.hidden) document.title = "Wait, come back 🥺"; else document.title = original; };
    document.addEventListener("visibilitychange", onHide);
    return () => document.removeEventListener("visibilitychange", onHide);
  }, []);
  return (
    <>
      <Nav />
      <Hero />
      <About />
      <Facts />
      <Services onOpen={open} />
      <Skills />
      <Achievements />
      <Contact />
      <ContactFab />
      <MobileNav />
      <DetailOverlay index={active} onClose={close} />
    </>
  );
}

Object.assign(window, { App });
