// Projects — Figma 69:4041 layout
// Full-screen background image + left project-list panel + right detail panel
(function () {
  const { useState, useEffect, useRef, useCallback, useMemo } = React;

  // ── Scroll geometry for the pinned Works panel ──────────────────────────
  // Section height is STEP_VH per step plus a TAIL_VH run-out, so the last
  // step is still fully readable before the panel unpins.
  const STEP_VH = 80;   // viewport heights of scroll spent on each step
  const TAIL_VH = 40;   // extra run-out after the final step
  // Progress→index is floor(progress * steps + STEP_BIAS). The bias advances
  // the switch a hair early so a step flips as its slot is entered rather than
  // a few pixels after; it is a fraction of one step, not a scroll distance,
  // so it is unaffected by STEP_VH.
  const STEP_BIAS = 0.04;

  // Fields shown in the details panel for one step, derived the same way for
  // both the scroll-jacked and the reduced-motion layouts.
  function panelFields(item) {
    const { project: proj, sub } = item;
    const firstSubSlug = proj.subProjects?.[0]?.slug;
    return {
      company: proj.company,
      // main steps now carry a title too — the group name only appeared in the
      // left-hand list before, so the details panel had no heading at all
      title: sub ? sub.title : proj.title,
      chips: sub ? sub.chips : null,
      // sub-projects have their own one-line conclusion; only fall through to
      // the group description on a main step
      desc: sub ? (sub.desc || null) : proj.description,
      metrics: sub ? sub.metrics : (proj.metrics?.length ? proj.metrics : null),
      metricsTitle: sub ? null : proj.metricsTitle,
      link: sub ? sub.slug : (proj.link && proj.link !== '#' ? proj.link : firstSubSlug || '#'),
      // a sub may ship its own cover; groups without one fall back to the
      // parent's (and to the placeholder when the parent has none either)
      cover: (sub && sub.coverImage) || proj.coverImage || '',
      isSub: !!sub,
    };
  }

  const METRIC_SYM_RE = /([+%→↗↘↑↓←])/g;
  const METRIC_ARROW_RE = /^[→↗↘↑↓←]$/;
  function renderMetricValue(val) {
    if (val == null) return null;
    const parts = String(val).split(METRIC_SYM_RE);
    return parts.map((part, idx) => {
      if (idx % 2 === 1) {
        let cls = 'pscroll__metric-sym';
        if (part === '+') cls += ' pscroll__metric-sym--plus';
        else if (METRIC_ARROW_RE.test(part)) cls += ' pscroll__metric-sym--arrow';
        return <span className={cls} key={idx}>{part}</span>;
      }
      return part;
    });
  }

  const METRIC_CAP_PLAIN_RE = /([A-Za-z0-9]+)/g;
  function renderMetricCap(text) {
    if (text == null) return null;
    const parts = String(text).split(METRIC_CAP_PLAIN_RE);
    return parts.map((part, idx) =>
      idx % 2 === 1
        ? <span className="pscroll__metric-cap-plain" key={idx}>{part}</span>
        : part
    );
  }

  function WorkDetails({ f }) {
    const hasMetrics = f.metrics?.length > 0;
    const ctaEl = (
      <a
        href={f.link || '#'}
        className="pscroll__cta"
        aria-label={f.isSub ? '看子案例' : '看完整案例'}
      >
        <span className="pscroll__cta-arrow">→</span>
      </a>
    );
    return (
      <>
        {(f.company || (f.chips && f.chips.length > 0)) && (
          <div className="pscroll__chips">
            {f.company && <span className="chip chip--accent">{f.company}</span>}
            {f.chips && f.chips.map((c) => <span className="chip" key={c}>{c}</span>)}
          </div>
        )}
        {f.title && <h3 className="pscroll__sub-title">{f.title}</h3>}
        {f.desc && <p className="pscroll__desc">{f.desc}</p>}
        <div className="pscroll__footer">
          {hasMetrics && (
            <div className="pscroll__metrics">
              {f.metrics.map((m, i) => (
                <div className={`pscroll__metric${m.alignLeft ? ' pscroll__metric--left' : ''}`} key={i}>
                  <span className={`pscroll__metric-num${m.shiftLeft4 ? ' pscroll__metric-num--shift-l4' : ''}`}>
                    {m.label && <span className="pscroll__metric-label">{m.label} </span>}
                    <span className="pscroll__metric-value">{renderMetricValue(m.num)}</span>
                    {m.unit && <span className="pscroll__metric-unit">{m.unit}</span>}
                  </span>
                  <span className="pscroll__metric-cap">{renderMetricCap(m.caption || m.desc)}</span>
                </div>
              ))}
            </div>
          )}
          {ctaEl}
        </div>
      </>
    );
  }

  // prefers-reduced-motion: no pin, no scroll-jack. Every step is laid out in
  // normal document flow so the whole list is reachable by ordinary scrolling.
  function StaticProjects({ items }) {
    return (
      <section className="pscroll pscroll--static" id="projects">
        <div className="eyebrow-exact pscroll-static__eyebrow">
          <div className="dot" />
          <div className="text">SELECTED WORK</div>
        </div>
        <ol className="pscroll-static__list">
          {items.map((it, i) => {
            const f = panelFields(it);
            const isVideo = /\.(mp4|webm)$/i.test(f.cover);
            return (
              <li className="pscroll-static__item" key={i}>
                <div className="pscroll-static__counter">
                  {String(i + 1).padStart(2, '0')} / {String(items.length).padStart(2, '0')}
                </div>
                <a href={f.link || '#'} className="pscroll-static__media">
                  {f.cover
                    ? (isVideo
                      // no autoplay here: motion is exactly what the user opted out of
                      ? <video src={f.cover} muted loop playsInline preload="metadata" controls />
                      : <img src={f.cover} alt="" />)
                    : <div className="pscroll__media-placeholder" />}
                </a>
                <div className="pscroll-static__body">
                  <WorkDetails f={f} />
                </div>
              </li>
            );
          })}
        </ol>
      </section>
    );
  }

  function Projects() {
    const data = window.PORTFOLIO_DATA.projects;

    // Flat scroll steps: each main project + its sub-projects
    const items = useMemo(() => {
      const list = [];
      data.forEach((proj) => {
        list.push({ type: 'main', project: proj, sub: null });
        (proj.subProjects || []).forEach((sub) => {
          list.push({ type: 'sub', project: proj, sub });
        });
      });
      return list;
    }, [data]);

    const sectionRef = useRef(null);
    const [activeIdx, setActiveIdx] = useState(0);

    const reduceMotion = useMemo(
      () => typeof window !== 'undefined' &&
            window.matchMedia('(prefers-reduced-motion: reduce)').matches,
      []
    );

    // 3.2 Work Section — Card Hover / Video Autoplay (hover pauses, leave plays)
    const [mediaHover, setMediaHover] = useState(false);
    const frameRef = useRef(null);
    const videoRef = useRef(null);
    const isTouch = useMemo(
      () => typeof window !== 'undefined' && window.matchMedia('(hover: none)').matches,
      []
    );
    // Motion tokens (DESIGN_SPEC §2) — reference the CSS variables so the
    // whole site shares one source of truth
    const EASE_IN_OUT = 'var(--ease-in-out)';
    const DUR_BASE = 'var(--duration-base)';

    const onScroll = useCallback(() => {
      const section = sectionRef.current;
      if (!section) return;
      const rect = section.getBoundingClientRect();
      const total = section.offsetHeight - window.innerHeight;
      if (total <= 0) return;
      const progress = Math.max(0, Math.min(1, -rect.top / total));
      const idx = Math.min(items.length - 1,
        Math.floor(progress * items.length + STEP_BIAS));
      setActiveIdx(idx);
    }, [items.length]);

    useEffect(() => {
      if (reduceMotion) return;   // static layout has nothing to scrub
      window.addEventListener('scroll', onScroll, { passive: true });
      onScroll();
      return () => window.removeEventListener('scroll', onScroll);
    }, [onScroll, reduceMotion]);

    const activeItem = items[activeIdx];
    const proj = activeItem.project;
    const sub = activeItem.sub;

    const isActiveProject = (p) => p.id === proj.id;
    const isActiveSub = (p, s) => p.id === proj.id && sub && s.num === sub.num;

    // Single source for the current step's content — the same helper the
    // reduced-motion layout uses, so the two cannot drift apart. (The old
    // rp* locals duplicated this and were left unused by the WorkDetails
    // refactor; the media below still read proj.coverImage directly, which is
    // why sub-level covers never showed.)
    const fields = panelFields(activeItem);
    const coverImage = fields.cover;
    const coverIsVideo = /\.(mp4|webm)$/i.test(coverImage);

    // Keep hover state in sync if the keyed media frame remounts during scroll.
    useEffect(() => {
      if (isTouch) return;
      const el = frameRef.current;
      if (!el) return;
      const hovered = el.matches(':hover');
      setMediaHover((prev) => (prev === hovered ? prev : hovered));
    }, [coverImage, proj.id, isTouch]);

    // Autoplay by default; pause while pointer is hovering the media frame.
    useEffect(() => {
      const v = videoRef.current;
      if (!v || !coverIsVideo) return;
      if (!isTouch && mediaHover) {
        v.pause();
      } else {
        v.play().catch(() => { });
      }
    }, [coverImage, coverIsVideo, isTouch, mediaHover]);

    // All hooks above run unconditionally; only the output branches.
    if (reduceMotion) return <StaticProjects items={items} />;

    return (
      <section
        className="pscroll"
        id="projects"
        ref={sectionRef}
        style={{ height: `calc(${items.length} * ${STEP_VH}vh + ${TAIL_VH}vh)` }}
      >
        <div className="pscroll__sticky">

          {/* ── Dark backdrop ── */}
          <div className="pscroll__bg" aria-hidden="true" />

          {/* ── LEFT panel: project name list ── */}
          <div className="pscroll__left">
            <ul className="pscroll__titles" aria-label="Projects">
              {data.map((p) => {
                const mainActive = isActiveProject(p) && !sub;
                const parentOfSub = p.id === proj.id && sub !== null;
                // Each title links to its detail page (proj.link, else first sub slug)
                const projHref = (p.link && p.link !== '#')
                  ? p.link
                  : (p.subProjects?.[0]?.slug || null);

                return (
                  <li key={p.id} className="pscroll__group">
                    {p.company && (
                      <a
                        href={projHref || undefined}
                        className={[
                          'pscroll__title-item',
                          'pscroll__title-item--co',
                          projHref ? 'is-link' : '',
                          mainActive ? 'is-active' : '',
                          parentOfSub ? 'is-parent' : '',
                        ].filter(Boolean).join(' ')}>
                        <span className="pscroll__title-co">{p.company}</span>
                      </a>
                    )}
                    <a
                      href={projHref || undefined}
                      className={[
                        'pscroll__title-item',
                        projHref ? 'is-link' : '',
                        mainActive ? 'is-active' : '',
                        parentOfSub ? 'is-parent' : '',
                      ].filter(Boolean).join(' ')}>
                      {/* left rail uses the short label; the details panel
                          shows the full title */}
                      <span className="pscroll__title-text">{p.navLabel || p.title}</span>
                    </a>


                    {/* Sub-projects only under the active parent */}
                    {p.id === proj.id && (p.subProjects || []).map((s) => {
                      const subActive = isActiveSub(p, s);
                      const subHref = s.slug || null;
                      return (
                        <a
                          key={s.num}
                          href={subHref || undefined}
                          className={`pscroll__sub-item${subActive ? ' is-active' : ''}${subHref ? ' is-link' : ''}`}
                        >
                          <span className="pscroll__sub-arrow" aria-hidden="true">↳</span>
                          <span className="pscroll__sub-text">{s.navLabel || s.title}</span>

                        </a>
                      );
                    })}
                  </li>
                );
              })}
            </ul>
          </div>

          {/* ── CENTER: framed media showcase — card hover / video autoplay (§3.2) ── */}
          <div className="pscroll__media">
            <a
              ref={frameRef}
              href={fields.link || '#'}
              className="pscroll__media-frame"
              key={coverImage || proj.id}
              onMouseEnter={() => {
                setMediaHover(true);
                if (!isTouch && coverIsVideo && videoRef.current) {
                  videoRef.current.pause();
                }
              }}
              onMouseLeave={() => {
                setMediaHover(false);
                if (coverIsVideo && videoRef.current) {
                  videoRef.current.play().catch(() => { });
                }
              }}
              style={{
                // hover: scale up ~2% — noticeable but not exaggerated
                transform: (mediaHover && !isTouch) ? 'scale(1.02)' : 'scale(1)',
                transition: `transform ${DUR_BASE} ${EASE_IN_OUT}`,
              }}
            >
              {coverImage
                ? (coverIsVideo
                  ? <video
                    ref={videoRef}
                    src={coverImage}
                    autoPlay
                    muted
                    loop
                    playsInline
                    preload="auto"
                  />
                  : <img src={coverImage} alt="" />)
                : <div className="pscroll__media-placeholder" />
              }
            </a>
          </div>

          {/* ── RIGHT panel: project details ── */}
          <div className="pscroll__right">
            <div className="pscroll__desc-wrap" key={activeIdx}>
              <WorkDetails f={fields} />
            </div>
          </div>
        </div>
      </section>
    );
  }

  window.Projects = Projects;
})();
