/* global React, playMenuTick, playSelect */
const { useState, useEffect, useRef } = React;

// Selected-work projects. Swap `img` for real screenshots later
// (drop files in assets/ and set img:"assets/xxx.jpg").
const PROJECTS = [
{ title: "SOCIAL MEDIA × AIGC", en: "AI账号运营 × 衍生品经营", tag: "自营系统 · AI账号 + 衍生品经营 · 2026", grp: "SELF-RUN SYSTEM", slug: "silicon-angel", img: "assets/sa-poster.png", grad: "linear-gradient(135deg,#241f3a 0%,#7c5cff 120%)" },
{ title: "GLOBAL BRAND CONTENT", en: "国际品牌内容与商业传播", tag: "商业 · 品牌内容与商业传播 · 2025", grp: "COMMERCIAL WORK", slug: "international-brands", img: "assets/lh-cover.png", grad: "linear-gradient(135deg,#1a1623 0%,#d8aaff 130%)" },
{ title: "LIVE & SPORTS CONCEPTS", en: "赛事活动 × 线下体验策划", tag: "商业 · 赛事活动 × 线下体验策划 · 2025", grp: "COMMERCIAL WORK", slug: "live-sports", img: "assets/sports/live-sports-cover.png", grad: "linear-gradient(135deg,#10243a 0%,#2cf0ff 130%)" },
{ title: "COMMERCIAL SYSTEM", en: "商业 AIGC 创意应用合集", tag: "商业 · AIGC 创意应用合集 · 2024", grp: "COMMERCIAL WORK", slug: "aigc-commercial", img: "assets/aigc/cover.png", grad: "linear-gradient(135deg,#3a1d2a 0%,#ff3d6e 130%)" },
{ title: "COMPLEX BRIEFS", en: "精选策划案例", tag: "商业 · 复杂 Brief 的清晰表达 · 2021–2024", grp: "COMMERCIAL WORK", slug: "complex-briefs", img: "assets/cbcc/cover.png", grad: "linear-gradient(135deg,#3a443a 0%,#8fae90 130%)" },
{ title: "PROTOTYPE LAB", en: "个人工具实验室", tag: "自营系统 · 个人工具与产品原型 · 2024", grp: "SELF-RUN SYSTEM", slug: "prototype-lab", img: "assets/lab/prototype-lab-cover.png", grad: "linear-gradient(135deg,#1a1623 0%,#7c5cff 130%)" }];


const VH_PER_FRAME = 58; // how much vertical scroll turns the reel one frame

function WorkReel() {
  // pos = which frame is centred (0 .. n-1). Driven by CLICK / ARROWS only — never by scroll.
  const [pos, setPos] = useState(0);
  const n = PROJECTS.length;
  const GAP = 264; // px between frame centers — = frame width → continuous strip
  const CURVE = 24; // px the strip bows back per step² (parabolic arc)
  const TILT = 15; // deg each frame fans inward
  const pinRef = useRef(null);
  const headRef = useRef(null);
  const stageRef = useRef(null);
  const [reelScale, setReelScale] = useState(1);
  const posRef = useRef(0);
  const scaleRef = useRef(1);
  const draggedRef = useRef(false);   // true right after a real drag → suppress click-open
  useEffect(() => { posRef.current = pos; }, [pos]);
  useEffect(() => { scaleRef.current = reelScale; }, [reelScale]);
  const tick = () => {try {playMenuTick && playMenuTick();} catch (e) {}};

  const active = Math.max(0, Math.min(n - 1, Math.round(pos)));

  // fit the reel to the stage band — recomputed on resize only (no scroll work)
  useEffect(() => {
    function fit() {
      const vh = window.innerHeight || 1;
      const band = stageRef.current ? stageRef.current.offsetHeight : vh * 0.5;
      setReelScale(Math.max(0.22, Math.min(1.18, band * 1.04 / 392)));
    }
    fit();
    window.addEventListener("resize", fit);
    const t = setTimeout(fit, 300); // after fonts / layout settle
    return () => {window.removeEventListener("resize", fit);clearTimeout(t);};
  }, []);

  // step the centred frame (click arrows / keyboard). Pure state — CSS transitions do the motion.
  const go = (d) => {
    setPos((p) => {
      const next = Math.max(0, Math.min(n - 1, Math.round(p) + d));
      if (next !== Math.round(p)) tick();
      return next;
    });
  };
  const goTo = (k) => {
    setPos((p) => {
      const next = Math.max(0, Math.min(n - 1, k));
      if (next !== Math.round(p)) tick();
      return next;
    });
  };

  // keyboard ← → while the reel is on screen
  useEffect(() => {
    function onKey(e) {
      const el = pinRef.current;if (!el) return;
      const r = el.getBoundingClientRect();
      const onscreen = r.top < window.innerHeight * 0.5 && r.bottom > window.innerHeight * 0.5;
      if (!onscreen) return;
      if (e.key === "ArrowRight") {e.preventDefault();go(1);}
      if (e.key === "ArrowLeft") {e.preventDefault();go(-1);}
    }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [pos]);

  // LEFT-RIGHT drag / swipe on the reel — one swipe = one frame, same as the INDEX tapes.
  // While dragging we kill the .frame CSS transition so the strip tracks the finger 1:1,
  // then re-enable it so the release snaps with the normal ease.
  useEffect(() => {
    const stage = stageRef.current;
    if (!stage) return;
    let dragging = false, startX = 0, startY = 0, startPos = 0, moved = false;
    const spacingPx = () => Math.max(120, GAP * (scaleRef.current || 1)); // on-screen px per frame
    function down(e) {
      if (e.button != null && e.button !== 0) return;
      dragging = true; moved = false;
      startX = e.clientX; startY = e.clientY; startPos = posRef.current;
      // NOTE: do NOT capture the pointer here — capturing on pointerdown reroutes the
      // subsequent click to the stage and breaks clicking a project. Capture only once a
      // real drag begins (in move()).
    }
    function move(e) {
      if (!dragging) return;
      const dx = e.clientX - startX;
      const dy = e.clientY - startY;
      if (Math.max(Math.abs(dx), Math.abs(dy)) > 4 && !moved) {
        moved = true;
        stage.classList.add("dragging");
        stage.setPointerCapture && stage.setPointerCapture(e.pointerId);
      }
      if (!moved) return;                         // below threshold → leave it as a click
      // follow whichever axis the user is dragging — horizontal OR vertical swipe steps the reel
      const drive = Math.abs(dx) >= Math.abs(dy) ? dx : dy;
      let p = startPos - drive / spacingPx();
      p = Math.max(startPos - 1.15, Math.min(startPos + 1.15, p));   // one swipe = one frame
      p = Math.max(0, Math.min(n - 1, p));
      setPos(p);
    }
    function up() {
      if (!dragging) return; dragging = false;
      stage.classList.remove("dragging");
      const delta = posRef.current - startPos;
      let dir = 0;
      if (delta > 0.16) dir = 1; else if (delta < -0.16) dir = -1;
      const land = Math.max(0, Math.min(n - 1, Math.round(startPos) + dir));
      if (land !== Math.round(startPos)) tick();
      setPos(land);
      if (moved) { draggedRef.current = true; setTimeout(() => { draggedRef.current = false; }, 60); }
    }
    stage.addEventListener("pointerdown", down);
    window.addEventListener("pointermove", move);
    window.addEventListener("pointerup", up);
    return () => {
      stage.removeEventListener("pointerdown", down);
      window.removeEventListener("pointermove", move);
      window.removeEventListener("pointerup", up);
    };
  }, []);

  // ===== "THIS SCREEN ONLY SCROLLS SIDEWAYS" =====
  // When PROJECTS fills the viewport, vertical wheel steps ONE frame; only running past
  // the last/first frame releases the page to the neighbouring section. Wheel-only
  // (data-lenis-prevent-wheel) so touch / mobile scroll-out is untouched.
  useEffect(() => {
    const sec = pinRef.current;
    if (!sec) return;
    let engaged = false, acc = 0, cd = 0, lock = 0;
    function evalEngage(){
      if (performance.now() < lock) return;       // frozen during a release so attr stays ON
      const r = sec.getBoundingClientRect();
      const vh = window.innerHeight || 1;
      const cover = Math.max(0, Math.min(r.bottom, vh) - Math.max(r.top, 0)) / vh;
      const next = cover >= 0.8;
      if (next !== engaged){
        engaged = next;
        if (engaged){
          sec.setAttribute("data-lenis-prevent-wheel", "");
          // rising edge: kill leftover momentum + settle into the viewport so the reel
          // locks in place instead of drifting past.
          if (window.__lenis && performance.now() > lock){
            lock = performance.now() + 620;
            window.__lenis.scrollTo(sec, { offset:0, duration:0.55, lock:true });
          }
        } else sec.removeAttribute("data-lenis-prevent-wheel");
      }
    }
    if (window.__lenis) window.__lenis.on("scroll", evalEngage);
    window.addEventListener("scroll", evalEngage, { passive: true });
    window.addEventListener("resize", evalEngage);
    evalEngage();
    const leave = (dir) => {
      // hold a lock across the release: engagement frozen (attr stays ON) so Lenis keeps
      // ignoring inertia and we can't overshoot the neighbouring section.
      lock = performance.now() + 900;
      const stops = Array.prototype.slice.call(sec.parentElement.children).filter((c) => c.nodeType === 1 && c.offsetParent !== null);
      const t = stops[stops.indexOf(sec) + dir];
      if (t) { if (window.__lenis) window.__lenis.scrollTo(t, { offset: 0 }); else { const y = window.scrollY + t.getBoundingClientRect().top; window.scrollTo({ top: y, behavior: "smooth" }); } }
      setTimeout(evalEngage, 940);
    };
    function onWheel(e) {
      const now = performance.now();
      if (now < lock) { e.preventDefault(); return; }   // attr still ON → Lenis ignores; block native too
      if (!engaged) return;
      const d = Math.abs(e.deltaX) > Math.abs(e.deltaY) ? e.deltaX : e.deltaY;
      if (Math.abs(d) < 2) return;
      e.preventDefault();
      const dir = d > 0 ? 1 : -1;
      const idx = Math.round(posRef.current);
      if ((dir > 0 && idx >= n - 1) || (dir < 0 && idx <= 0)) { leave(dir); return; }
      if (now < cd) return;
      acc += d;
      if (Math.abs(acc) > 40) { go(dir); acc = 0; cd = now + 340; }
    }
    window.addEventListener("wheel", onWheel, { passive: false });
    return () => {
      if (window.__lenis) window.__lenis.off("scroll", evalEngage);
      window.removeEventListener("scroll", evalEngage);
      window.removeEventListener("resize", evalEngage);
      window.removeEventListener("wheel", onWheel);
      sec.removeAttribute("data-lenis-prevent-wheel");
    };
  }, []);

  const cur = PROJECTS[active];

  return (
    <section className="work-pin" id="work" ref={pinRef} style={{ height: "100vh" }} data-screen-label="05 · PROJECTS">
      <div className="work-sticky">
        <div className="work-head" ref={headRef} data-cine>
          <div className="weyebrow">04 <span className="sep">·</span> PROJECTS</div>
          <div className="wtitle" style={{ fontWeight: "800" }}>精选作品</div>
          <div className="work-current" key={active}>
            <div className="wc-idx">{String(active + 1).padStart(2, "0")} / {String(n).padStart(2, "0")}</div>
            <div className="wc-en">{cur.title}</div>
            <div className="wc-zh">{cur.en}</div>
          </div>
        </div>

        <div className="work-stage" ref={stageRef}>
          <div className="reel" style={{ transform: `translateY(-84px) rotateX(5deg) rotateZ(-3.5deg) scale(${reelScale})` }}>
            {PROJECTS.map((p, i) => {
              const rel = i - pos; // continuous offset from center
              const ar = Math.abs(rel);
              const hidden = ar > 3.4;
              // centre frame pops ~15% larger; neighbours recede faster so the focus is unmistakable
              const sc = ar < 0.5 ? 1.15 : Math.max(0.74, 1.0 - Math.min(ar, 3) * 0.1);
              const op = hidden ? 0 : ar < 0.5 ? 1 : ar < 1.5 ? 0.42 : ar < 2.5 ? 0.26 : 0.42;
              return (
                <div key={p.title}
                className={"frame" + (i === active ? " is-active" : "")}
                style={{ transform: `translateX(${rel * GAP}px) translateZ(${-rel * rel * CURVE}px) rotateY(${-rel * TILT}deg) scale(${sc})`,
                  opacity: op,
                  pointerEvents: hidden ? "none" : "auto",
                  zIndex: 100 - Math.round(ar) }}
                onClick={(e) => {
                  if (draggedRef.current) return;   // ignore the click that ends a drag
                  if (i === active && p.slug) {try {playSelect && playSelect();} catch (_) {};if (window.__openProject) window.__openProject(p.slug, e.currentTarget);} else
                  {goTo(i);}
                }}>
                  <div className="film">
                    <div className="holes top" />
                    <div className="pic" style={p.img ? { backgroundImage: `url(${p.img})` } : { background: p.grad }}>
                      <span className="num">{String(i + 1).padStart(2, "0")} / {String(n).padStart(2, "0")}</span>
                      <span className="cellname">{p.title}</span>
                    </div>
                    <div className="holes bottom" />
                  </div>
                </div>);

            })}
          </div>
          <button className="reel-arrow left" onClick={() => go(-1)} aria-label="Previous">←</button>
          <button className="reel-arrow right" onClick={() => go(1)} aria-label="Next">→</button>
        </div>

        <div className="work-mobile">
          {PROJECTS.map((p, i) =>
          <button className="wm-card" key={p.title}
          onClick={() => {try {playSelect && playSelect();} catch (_) {};if (p.slug && window.__openProject) window.__openProject(p.slug);}}>
              <div className="wm-cover" style={p.img ? { backgroundImage: `url(${p.img})` } : { background: p.grad }}>
                <span className="wm-num">{String(i + 1).padStart(2, "0")} / {String(n).padStart(2, "0")}</span>
              </div>
              <div className="wm-body">
                <div className="wm-title">{p.title}</div>
                <div className="wm-zh">{p.en}</div>
                <div className="wm-tag">{p.tag}</div>
                <div className="wm-link">{p.slug ? "View project →" : "Coming soon"}</div>
              </div>
            </button>
          )}
        </div>
      </div>
    </section>);

}

Object.assign(window, { WorkReel, PROJECTS });