// Productivity Journey — pinned scrollytelling with persistent left rail.
// 3 stages: Manual (1×) → Software (1.5×) → AI-powered (4–10×)
// Pin distance is short on purpose: ~220vh total so the pinned canvas
// never falls off the viewport.

const { useState: useStateJY, useEffect: useEffectJY, useRef: useRefJY } = React;

const STAGES = [
  {
    key: 'manual',
    num: '01',
    eyebrow: 'The baseline',
    name: 'Manual',
    mult: '1×',
    multNum: 1,
    tagline: 'Doing everything by hand.',
    desc: 'Spreadsheets. Copy-paste. Email threads. The work gets done — but it pulls your best people away from the work that actually requires them.',
    company: 'acme-co.ops',
    heartbeat: '—',
    lanes: [
      { label: 'Intake', start: 0, width: 20, color: 'manual', note: '3h · by hand' },
      { label: 'Scheduling', start: 20, width: 16, color: 'manual', note: '2h · by hand' },
      { label: 'Data entry', start: 36, width: 24, color: 'manual', note: '5h · by hand' },
      { label: 'Follow-ups', start: 60, width: 20, color: 'manual', note: '3h · by hand' },
      { label: 'Reporting', start: 80, width: 20, color: 'manual', note: '4h · by hand' },
    ],
    totalLabel: 'Throughput / week',
    totalValue: '1 unit',
    stats: [
      { label: 'Hrs / wk manual', value: '17h' },
      { label: 'Error rate', value: '8.4%' },
      { label: 'After-hours coverage', value: '0' },
    ],
  },
  {
    key: 'software',
    num: '02',
    eyebrow: 'The middle road',
    name: 'Software-enhanced',
    mult: '4×',
    multNum: 4,
    tagline: 'Productivity tools, limited gains.',
    desc: 'Your team has SaaS now. A CRM, a ticketing tool, a scheduling app. Each tool saves a little time — but the handoffs between them are still manual, and nobody owns the whole picture.',
    company: 'acme-co.ops',
    heartbeat: 'saas · stack',
    lanes: [
      { label: 'Intake', start: 0, width: 12, color: 'software', note: '1.5h · CRM' },
      { label: 'Scheduling', start: 12, width: 10, color: 'software', note: '1h · tool' },
      { label: 'Data entry', start: 22, width: 18, color: 'software-partial', note: '3h · manual bridge' },
      { label: 'Follow-ups', start: 40, width: 14, color: 'software', note: '1.5h · sequences' },
      { label: 'Reporting', start: 54, width: 14, color: 'software-partial', note: '2.5h · spreadsheet' },
    ],
    totalLabel: 'Throughput / week',
    totalValue: '~4 units',
    stats: [
      { label: 'Hrs / wk manual', value: '9h' },
      { label: 'Error rate', value: '5.1%' },
      { label: 'After-hours coverage', value: 'Partial' },
    ],
  },
  {
    key: 'ai',
    num: '03',
    eyebrow: 'Where we take you',
    name: 'AI-powered',
    mult: '10×',
    multNum: 10,
    tagline: 'Same team. Dramatically more output.',
    desc: 'AI agents and automated pipelines absorb the work that shouldn\u2019t require human judgment. Your people spend their time on strategy, relationships, and the decisions that actually move the business.',
    company: 'acme-co.ops',
    heartbeat: 'agents · live',
    lanes: [
      { label: 'Intake', start: 0, width: 3, color: 'ai', note: 'voice agent' },
      { label: 'Scheduling', start: 3, width: 2, color: 'ai', note: 'scheduling agent' },
      { label: 'Data entry', start: 5, width: 4, color: 'ai', note: 'doc pipeline' },
      { label: 'Follow-ups', start: 9, width: 3, color: 'ai', note: 'cx agent' },
      { label: 'Reporting', start: 12, width: 4, color: 'ai', note: 'auto-report' },
    ],
    totalLabel: 'Throughput / week',
    totalValue: '4–10 units',
    stats: [
      { label: 'Hrs / wk manual', value: '< 2h' },
      { label: 'Error rate', value: '0.6%' },
      { label: 'After-hours coverage', value: 'Overflow' },
    ],
  },
];

window.ProductivityJourney = function ProductivityJourney() {
  const [active, setActive] = useStateJY(0);
  const [progress, setProgress] = useStateJY(0); // 0..1 across the whole journey
  const [isMobile, setIsMobile] = useStateJY(
    typeof window !== 'undefined' && window.matchMedia
      ? window.matchMedia('(max-width: 900px)').matches
      : false
  );
  const containerRef = useRefJY(null);
  // While the user is clicking a rail stop, ignore scroll-driven `active`
  // overrides — the smooth scroll fires dozens of scroll events en route
  // and the click should win until the scroll settles.
  const clickLockUntil = useRefJY(0);

  // Track viewport so we can switch to an unpinned mobile layout.
  useEffectJY(() => {
    if (!window.matchMedia) return;
    const mq = window.matchMedia('(max-width: 900px)');
    const onChange = () => setIsMobile(mq.matches);
    if (mq.addEventListener) mq.addEventListener('change', onChange);
    else mq.addListener(onChange);
    return () => {
      if (mq.removeEventListener) mq.removeEventListener('change', onChange);
      else mq.removeListener(onChange);
    };
  }, []);

  useEffectJY(() => {
    if (isMobile) return; // No scroll hijacking on mobile
    const onScroll = () => {
      // If the user clicked a rail stop recently, freeze BOTH active and
      // progress to the clicked values until the lock expires. Anything
      // else (including the big morph number) would flicker as the page
      // scrolls past the clicked stage's range.
      if (performance.now() < clickLockUntil.current) return;

      const container = containerRef.current;
      if (!container) return;
      const rect = container.getBoundingClientRect();
      const total = container.offsetHeight - window.innerHeight;
      const scrolled = -rect.top;
      const p = Math.max(0, Math.min(1, scrolled / total));
      setProgress(p);

      const idx = Math.min(STAGES.length - 1, Math.floor(p * STAGES.length * 0.999));
      setActive(idx);
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener('scroll', onScroll);
  }, [isMobile]);

  const stage = STAGES[active];

  // Interpolate the big multiplier so it visibly morphs as you scroll.
  const lerp = (a, b, t) => a + (b - a) * t;
  const segT = Math.min(1, Math.max(0, progress * STAGES.length - active));
  const nextStage = STAGES[Math.min(STAGES.length - 1, active + 1)];
  const animMult = lerp(stage.multNum, nextStage.multNum, segT);

  const jumpTo = (i) => {
    const container = containerRef.current;
    if (!container) return;
    // Click-to-select behavior: update the stage content IN PLACE. We do NOT
    // scroll the page to the stage's scroll slice — doing so used to send
    // the user past the pinned visual (so they'd lose sight of what they
    // just clicked). Instead we freeze the scroll-driven updates for a few
    // seconds so the clicked stage stays locked-in until the user decides
    // to scroll again.
    setActive(i);
    setProgress((i + 0.5) / STAGES.length);
    clickLockUntil.current = performance.now() + 5000;

    // If the journey-scroll container is entirely below the viewport (user
    // hasn't reached it yet), bring its top to the viewport top so the
    // pinned panel is actually visible. If they're already inside or past
    // it, leave scroll alone.
    //
    // Note: container.offsetTop is relative to offsetParent (journey-section),
    // NOT the page, so we compute absolute page offset from the bounding
    // rect + current scrollY.
    const rect = container.getBoundingClientRect();
    const pageTop = rect.top + window.scrollY;
    const topEdge = rect.top;
    if (topEdge > 80) {
      window.scrollTo({ top: pageTop - 16, behavior: 'smooth' });
    }
  };

  // Any user-initiated wheel / touch / keyboard scroll releases the click-lock
  // so scrolling resumes driving the stage state.
  useEffectJY(() => {
    if (isMobile) return;
    const release = () => {
      if (performance.now() < clickLockUntil.current) clickLockUntil.current = 0;
    };
    window.addEventListener('wheel', release, { passive: true });
    window.addEventListener('touchmove', release, { passive: true });
    window.addEventListener('keydown', (e) => {
      if (['ArrowDown','ArrowUp','PageDown','PageUp','Space',' '].includes(e.key)) release();
    });
    return () => {
      window.removeEventListener('wheel', release);
      window.removeEventListener('touchmove', release);
    };
  }, [isMobile]);

  return (
    <section className="journey-section" id="journey" data-section-nav="The Transformation">
      <div className="container" style={{ marginBottom: 40 }}>
        <div className="section-head left">
          <span className="kicker">The Transformation</span>
          <h2 style={{ marginTop: 20 }}>
            From <span className="serif">doing everything by hand</span> — to a team that moves 4&ndash;10&times; faster.
          </h2>
          <p style={{ maxWidth: 640 }}>
            Three stages most companies travel through. We shorten the trip, and land you somewhere most never reach on their own.
          </p>
        </div>
      </div>

      {isMobile ? (
        /* ---- Mobile: plain vertical stack of all 3 stages ---- */
        <div className="journey-mobile">
          {STAGES.map((s, i) => (
            <article key={s.key} className="journey-mobile-card">
              <header className="journey-mobile-card-head">
                <span className="journey-mobile-card-num mono">Stage {s.num}</span>
                <span className="journey-mobile-card-mult gradient-text">{s.mult}</span>
              </header>
              <div className="journey-mobile-card-eyebrow mono">{s.eyebrow}</div>
              <h3 className="journey-mobile-card-name">{s.tagline}</h3>
              <p className="journey-mobile-card-desc">{s.desc}</p>
              <div className="workflow">
                <div className="workflow-bar">
                  <div className="workflow-bar-left">
                    <div className="workflow-bar-dots">
                      <span className="workflow-bar-dot" /><span className="workflow-bar-dot" /><span className="workflow-bar-dot" />
                    </div>
                    <span>{s.company}</span>
                  </div>
                  <div className="workflow-bar-right">
                    <span className="tag-dot" />
                    <span>{s.heartbeat}</span>
                  </div>
                </div>
                <div className="workflow-body">
                  {s.lanes.map((lane) => (
                    <div className="lane" key={lane.label}>
                      <div className="lane-label">{lane.label}</div>
                      <div className="lane-track">
                        <div
                          className={`lane-block lane-block-${lane.color}`}
                          style={{ left: `${lane.start}%`, width: `${lane.width}%` }}
                          aria-hidden="true"
                        />
                      </div>
                      <div className={`lane-note lane-note-${lane.color} mono`}>
                        {lane.note}
                      </div>
                    </div>
                  ))}
                  <div className="workflow-total">
                    <span className="workflow-total-label">{s.totalLabel}</span>
                    <span className="workflow-total-value">{s.totalValue}</span>
                  </div>
                </div>
              </div>
              <div className="stage-stats">
                {s.stats.map(stat => (
                  <div className="stage-stat" key={stat.label}>
                    <div className="stage-stat-label">{stat.label}</div>
                    <div className="stage-stat-value">{stat.value}</div>
                  </div>
                ))}
              </div>
            </article>
          ))}
        </div>
      ) : (
        /* ---- Desktop: pinned scrollytelling. Total section height capped
               at ~2000px so the pin never has a blank-viewport gap between
               stages. 3 stages × ~55vh of scroll runway each + a little
               head/tail = 180vh total. ---- */
        <div
          ref={containerRef}
          className="journey-scroll"
          style={{ height: `${30 + STAGES.length * 50}vh`, position: 'relative' }}
        >
        <div className="journey-pin">
          <div className="journey-canvas">
            {/* Persistent rail — sits inside the pinned area so it never scrolls away */}
            <aside className="journey-rail-persistent" aria-label="Journey stages">
              <div className="journey-rail-head">
                <span className="mono" style={{ fontSize: 11, letterSpacing: '0.14em', color: 'var(--text-dim)', textTransform: 'uppercase' }}>Stage</span>
                <span className="journey-rail-progress mono">
                  {active + 1} <span style={{ color: 'var(--text-dim)' }}>/ {STAGES.length}</span>
                </span>
              </div>
              <div className="journey-rail-track">
                <div
                  className="journey-rail-fill"
                  style={{ height: `${Math.min(1, progress) * 100}%` }}
                />
                {STAGES.map((s, i) => (
                  <button
                    key={s.key}
                    onClick={() => jumpTo(i)}
                    className={`journey-rail-stop ${i <= active ? 'passed' : ''} ${i === active ? 'current' : ''}`}
                    style={{ top: `${10 + (i / (STAGES.length - 1)) * 80}%` }}
                    aria-label={`Stage ${s.num} · ${s.name}`}
                  >
                    <span className="journey-rail-stop-dot" />
                    <span className="journey-rail-stop-body">
                      <span className="journey-rail-stop-num mono">Stage {s.num}</span>
                      <span className="journey-rail-stop-name">{s.name}</span>
                    </span>
                  </button>
                ))}
              </div>
            </aside>

            {/* Big morphing number — the single signature moment */}
            <div className="journey-morph">
              <div className="journey-morph-label mono">Productivity · live</div>
              <div className="journey-morph-value">
                <span className="journey-morph-num gradient-text">
                  {animMult < 1.05 ? '1×' : animMult > 9.5 ? '10×' : `${animMult.toFixed(1).replace(/\.0$/, '')}×`}
                </span>
              </div>
              <div className="journey-morph-range mono">1× → 4× → 10×</div>
            </div>

            {/* Active stage panel */}
            <div className="journey-stage-panel">
              <div className="journey-stage-header">
                <div>
                  <div className="journey-stage-eyebrow">{stage.eyebrow}</div>
                  <h3 className="journey-stage-name">{stage.tagline}</h3>
                  <p className="journey-stage-desc">{stage.desc}</p>
                </div>
              </div>

              <div className="workflow">
                <div className="workflow-bar">
                  <div className="workflow-bar-left">
                    <div className="workflow-bar-dots">
                      <span className="workflow-bar-dot" /><span className="workflow-bar-dot" /><span className="workflow-bar-dot" />
                    </div>
                    <span>{stage.company}</span>
                  </div>
                  <div className="workflow-bar-right">
                    <span className="tag-dot" />
                    <span>{stage.heartbeat}</span>
                  </div>
                </div>
                <div className="workflow-body">
                  {stage.lanes.map((lane, i) => (
                    /* Lane layout: label | bar-track | note.
                       The note was previously an inline pill positioned
                       relative to the bar's right edge, which collided with
                       the next bar whenever the stage had contiguous lanes
                       (stage 1 and stage 2). Now the note lives in its own
                       right-aligned column so it never overlaps anything —
                       the bar is a pure visual indicator of effort, the
                       note is a consistently-placed tag. */
                    <div className="lane" key={lane.label}>
                      <div className="lane-label">{lane.label}</div>
                      <div className="lane-track">
                        <div
                          className={`lane-block lane-block-${lane.color}`}
                          style={{
                            left: `${lane.start}%`,
                            width: `${lane.width}%`,
                            transitionDelay: `${i * 60}ms`,
                          }}
                          aria-hidden="true"
                        />
                      </div>
                      <div className={`lane-note lane-note-${lane.color} mono`}>
                        {lane.note}
                      </div>
                    </div>
                  ))}
                  <div className="workflow-total">
                    <span className="workflow-total-label">{stage.totalLabel}</span>
                    <span className="workflow-total-value">{stage.totalValue}</span>
                  </div>
                </div>
              </div>

              <div className="stage-stats">
                {stage.stats.map(s => (
                  <div className="stage-stat" key={s.label}>
                    <div className="stage-stat-label">{s.label}</div>
                    <div className="stage-stat-value">{s.value}</div>
                  </div>
                ))}
              </div>
            </div>
          </div>
        </div>
        </div>
      )}
    </section>
  );
};
