/* Blueprint scene — pinned scroll-scrubbed cinematic.
   Pins for ~3 viewport heights and scrubs a single timeline across three acts:
     ACT I  · FRAGMENTED — sources fade/slide in
     ACT II · UNIFIED    — connector lines sketch via stroke-dashoffset,
                           hub assembles, brackets pop, pulse rings
     ACT III · CLARITY   — beam grows, output card slides in, bars rise
                           with elastic ease, coral pop on the result
   Packets travelling each connector are achieved with a continuously
   shifting strokeDashoffset on a dashed coral overlay path — a free,
   universal technique that needs no paid plugins. */

const SOURCE_LABELS = [
  "PMS", "Finance", "Energy", "CRM", "Customer Exp", "Short Stay", "BTR Ledger",
];

function Blueprint() {
  const sectionRef = React.useRef(null);

  React.useEffect(() => {
    const section = sectionRef.current;
    if (!section) return;

    const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    // On narrow viewports the wide 1600×700 SVG is unreadable when squeezed
    // into a 100vh pinned letterbox, so we drop pinning + scrubbing and play
    // the timeline as a one-shot when the section enters view. The CSS lets
    // the section grow to its natural height so the SVG can render at a
    // usable scale without horizontal cropping.
    const narrow = window.matchMedia('(max-width: 768px)').matches;
    const noPin = reduce || narrow;

    const ctx = gsap.context(() => {
      // Initial states. Act chips are pure CSS now (always visible) and
      // get an .is-active class toggled by the scroll callbacks below —
      // GSAP no longer touches their opacity, which was causing them to
      // vanish when the timeline state was ambiguous.
      gsap.set('.bp-source', { opacity: 0, x: -10 });
      gsap.set('.bp-line', { strokeDashoffset: 1 });
      gsap.set('.bp-flow', { opacity: 0 });
      gsap.set('.bp-hub-frame', { opacity: 0, scale: 0.96, transformOrigin: 'center center' });
      gsap.set('.bp-hub-fill', { opacity: 0, scale: 0.94, transformOrigin: 'center center' });
      gsap.set('.bp-hub-bracket', { opacity: 0, scale: 0.4, transformOrigin: 'center center' });
      gsap.set('.bp-hub-text', { opacity: 0, y: 8 });
      gsap.set('.bp-hub-msg', { opacity: 0, y: 14 });
      gsap.set('.bp-hub-pulse', { scale: 0, opacity: 0, transformOrigin: 'center center' });
      gsap.set('.bp-beam', { scaleX: 0, transformOrigin: 'left center' });
      gsap.set('.bp-output-frame', { opacity: 0, x: 30 });
      gsap.set('.bp-output-bar', { scaleY: 0, transformOrigin: 'center bottom' });
      gsap.set('.bp-output-label', { opacity: 0 });
      gsap.set('.bp-closing', { opacity: 0 });
      gsap.set('.bp-rule-1, .bp-rule-2, .bp-rule-3', { opacity: 0 });

      const tl = gsap.timeline({
        scrollTrigger: {
          trigger: section,
          start: noPin ? 'top 80%' : 'top top',
          end: '+=180%',
          // Lenis already lerp-smooths the scroll; using `scrub: true` (instant)
          // avoids a double-lerp that was making pinned sections judder.
          scrub: noPin ? false : true,
          pin: !noPin,
          pinSpacing: !noPin,
          anticipatePin: 1,
          invalidateOnRefresh: true,
          // Drive the act-chip highlight purely via a class — opacity is left
          // alone so the chips can never "vanish" on us due to GSAP state.
          onUpdate: (self) => {
            const p = self.progress;
            const acts = section.querySelectorAll('.blueprint__act');
            // Three acts mapped across [0..1]: act 1 owns 0–0.33, act 2 owns
            // 0.33–0.66, act 3 owns 0.66–1.
            const idx = p < 0.33 ? 0 : p < 0.66 ? 1 : 2;
            acts.forEach((el, i) => el.classList.toggle('is-active', i === idx));
          },
        },
        defaults: { ease: 'power2.out' },
      });

      // ACT I — Fragmented
      tl.to('.bp-rule-1', { opacity: 0.3, duration: 0.4 }, 0)
        .to('.bp-source', { opacity: 1, x: 0, duration: 0.5, stagger: 0.06 }, 0.05);

      // ACT II — Unified
      tl.to('.bp-rule-2',    { opacity: 0.3, duration: 0.4 }, 1.0)
        .to('.bp-line',      { strokeDashoffset: 0, duration: 1.0, stagger: 0.06, ease: 'power1.inOut' }, 1.1)
        .to('.bp-flow',      { opacity: 1, duration: 0.4 }, 1.7)
        .to('.bp-hub-frame', { opacity: 1, scale: 1, duration: 0.55, ease: 'expo.out' }, 1.5)
        .to('.bp-hub-fill',  { opacity: 0.92, scale: 1, duration: 0.6, ease: 'expo.out' }, 1.7)
        .to('.bp-hub-bracket', { opacity: 1, scale: 1, duration: 0.45, stagger: 0.06, ease: 'back.out(2.2)' }, 1.85)
        .to('.bp-hub-text',  { opacity: 1, y: 0, duration: 0.55 }, 2.05)
        .to('.bp-hub-pulse', { scale: 1, opacity: 1, duration: 0.6, ease: 'expo.out' }, 2.2)
        .to('.bp-hub-pulse', { scale: 1.8, opacity: 0, duration: 1.0, ease: 'power2.out' }, 2.45)
        // Chat bubbles pop in one at a time — feels like the conversation is
        // actually unfolding rather than the whole window arriving in one shot.
        .to('.bp-hub-msg-user',    { opacity: 1, y: 0, duration: 0.45, ease: 'back.out(1.6)' }, 2.25)
        .to('.bp-hub-msg-agent',   { opacity: 1, y: 0, duration: 0.45, ease: 'back.out(1.6)' }, 2.6)
        .to('.bp-hub-msg-insight', { opacity: 1, y: 0, duration: 0.45, ease: 'back.out(1.6)' }, 2.95);

      // ACT III — Clarity
      tl.to('.bp-rule-3',      { opacity: 0.3, duration: 0.4 }, 2.6)
        .to('.bp-beam',        { scaleX: 1, duration: 0.7, ease: 'power2.inOut' }, 2.7)
        .to('.bp-output-frame',{ opacity: 1, x: 0, duration: 0.55, ease: 'expo.out' }, 3.0)
        .to('.bp-output-label',{ opacity: 1, duration: 0.4 }, 3.1)
        .to('.bp-output-bar',  { scaleY: 1, duration: 0.6, stagger: 0.06, ease: 'elastic.out(1, 0.55)' }, 3.25)
        .to('.bp-closing',     { opacity: 1, duration: 0.5 }, 3.5);

      // Continuous packet flow — animate strokeDashoffset of the coral dashed
      // overlay so dashes appear to travel from source → hub
      if (!reduce) {
        gsap.to('.bp-flow', {
          strokeDashoffset: -16,
          duration: 1.0,
          ease: 'none',
          repeat: -1,
        });
      }
    }, section);

    return () => ctx.revert();
  }, []);

  // Geometry
  const SRC_X = 220;
  const HUB_X = 800;
  const OUT_X = 1380;
  const W = 1600, H = 700;
  const srcY = SOURCE_LABELS.map((_, i) => 130 + i * 60);

  return (
    <section
      ref={sectionRef}
      id="blueprint"
      className="blueprint blueprint--pinned"
      aria-hidden="true"
    >
      <div className="blueprint__stage">
        <div className="blueprint__chapter">
          <span className="num">FIG · 01</span>
          <span>From fragmentation to clarity</span>
        </div>

        {/* Act chips — same .bp-act / .bp-act-N classes the GSAP timeline
            already targets, so the existing fade-in per act still works. */}
        <div className="blueprint__acts" aria-hidden="true">
          <div className="blueprint__act bp-act bp-act-1">
            <span className="blueprint__act-num">I</span>
            <span className="blueprint__act-name">Fragmented</span>
          </div>
          <div className="blueprint__act bp-act bp-act-2">
            <span className="blueprint__act-num">II</span>
            <span className="blueprint__act-name">Unified</span>
          </div>
          <div className="blueprint__act bp-act bp-act-3">
            <span className="blueprint__act-num">III</span>
            <span className="blueprint__act-name">Clarity</span>
          </div>
        </div>

        <div className="blueprint__svg-wrap">
        <svg className="blueprint__svg" viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="xMidYMid meet">
          <defs>
            <pattern id="bp-grid" width="32" height="32" patternUnits="userSpaceOnUse">
              <circle cx="1" cy="1" r="0.7" fill="currentColor" opacity="0.18" />
            </pattern>
          </defs>

          <rect x="0" y="0" width={W} height={H} fill="url(#bp-grid)" />

          {/* Act labels rendered as HTML below — see .blueprint__acts */}

          {/* Vertical chapter rules */}
          <line className="bp-rule-1" x1={SRC_X - 110} y1="80" x2={SRC_X - 110} y2={H - 50}
                stroke="currentColor" strokeWidth="0.5" />
          <line className="bp-rule-2" x1={HUB_X - 240} y1="80" x2={HUB_X - 240} y2={H - 50}
                stroke="currentColor" strokeWidth="0.5" strokeDasharray="2 4" />
          <line className="bp-rule-3" x1={HUB_X + 240} y1="80" x2={HUB_X + 240} y2={H - 50}
                stroke="currentColor" strokeWidth="0.5" strokeDasharray="2 4" />

          {/* Sources + connectors */}
          {SOURCE_LABELS.map((label, i) => {
            const cy = srcY[i];
            const pathD = `M ${SRC_X + 60} ${cy} C ${SRC_X + 220} ${cy} ${HUB_X - 280} 360 ${HUB_X - 180} 360`;
            return (
              <g key={i} className="bp-source">
                <rect x={SRC_X - 60} y={cy - 14} width="120" height="28" fill="none" stroke="currentColor" strokeWidth="0.5" opacity="0.5" />
                <circle cx={SRC_X - 50} cy={cy} r="2.4" fill="#E8513A" />
                <text x={SRC_X - 40} y={cy + 4} fontFamily="Space Mono, monospace" fontSize="10" letterSpacing="1.5" fill="currentColor">
                  {label.toUpperCase()}
                </text>

                {/* Base line — drawn in via strokeDashoffset */}
                <path
                  className="bp-line"
                  d={pathD}
                  stroke="#E8513A"
                  strokeWidth="0.8"
                  strokeOpacity="0.55"
                  fill="none"
                  pathLength="1"
                  strokeDasharray="1 1"
                />
                {/* Flow overlay — coral dashes that "travel" along the line */}
                <path
                  className="bp-flow"
                  d={pathD}
                  stroke="#E8513A"
                  strokeWidth="1.6"
                  fill="none"
                  strokeLinecap="round"
                  strokeDasharray="1 15"
                />
              </g>
            );
          })}

          {/* HUB — BODE rendered as a live agent chat window so the role of
              "intelligence layer" reads as an active, conversational system.
              Window enlarged + type bumped so the chat is readable at the
              viewport scale the SVG renders at. */}
          <g>
            {/* Window frame + body — 360 × 360 with a 38px title bar. */}
            <rect className="bp-hub-frame" x={HUB_X - 180} y="180" width="360" height="360"
                  rx="6" fill="none" stroke="currentColor" strokeWidth="1.2" />
            <rect className="bp-hub-fill" x={HUB_X - 172} y="188" width="344" height="344"
                  rx="5" fill="#0B0D10" />

            {/* Window title bar */}
            <rect className="bp-hub-text" x={HUB_X - 172} y="188" width="344" height="38"
                  rx="5" fill="rgba(255,255,255,0.04)" />
            <line className="bp-hub-text"
                  x1={HUB_X - 172} y1="226" x2={HUB_X + 172} y2="226"
                  stroke="rgba(255,255,255,0.08)" strokeWidth="0.8" />
            {/* Traffic light dots */}
            <g className="bp-hub-text">
              <circle cx={HUB_X - 156} cy="207" r="4.5" fill="#3a3d42" />
              <circle cx={HUB_X - 142} cy="207" r="4.5" fill="#3a3d42" />
              <circle cx={HUB_X - 128} cy="207" r="4.5" fill="#3a3d42" />
            </g>
            {/* Window title */}
            <text className="bp-hub-text" x={HUB_X} y="212" textAnchor="middle"
                  fontFamily="Space Mono, monospace" fontSize="14" letterSpacing="2.5"
                  fill="rgba(243,246,247,0.85)">
              BODE · AGENT
            </text>
            {/* Live status: a hard dot that always reads + the existing pulse
                ring that pings once when Act II arrives. */}
            <circle className="bp-hub-text" cx={HUB_X + 152} cy="207" r="4" fill="#E8513A">
              <animate attributeName="opacity" values="1;0.35;1" dur="1.6s" repeatCount="indefinite" />
            </circle>
            <circle className="bp-hub-pulse" cx={HUB_X + 152} cy="207" r="9"
                    fill="none" stroke="#E8513A" strokeWidth="1" />

            {/* User query bubble — right aligned, coral tint */}
            <g className="bp-hub-msg bp-hub-msg-user">
              <rect x={HUB_X - 10} y="246" width="172" height="56"
                    rx="6" fill="rgba(232,81,58,0.22)" stroke="rgba(232,81,58,0.4)" strokeWidth="0.8" />
              <text x={HUB_X + 152} y="268" textAnchor="end"
                    fontFamily="Host Grotesk" fontWeight="500" fontSize="17"
                    fill="#F3F6F7">Show occupancy</text>
              <text x={HUB_X + 152} y="290" textAnchor="end"
                    fontFamily="Host Grotesk" fontWeight="500" fontSize="17"
                    fill="#F3F6F7">by region.</text>
            </g>

            {/* Agent response bubble — left aligned, neutral */}
            <g className="bp-hub-msg bp-hub-msg-agent">
              <rect x={HUB_X - 162} y="318" width="260" height="96"
                    rx="6" fill="rgba(255,255,255,0.04)" stroke="rgba(255,255,255,0.10)" strokeWidth="0.8" />
              <text x={HUB_X - 150} y="338"
                    fontFamily="Space Mono, monospace" fontSize="11" letterSpacing="2"
                    fill="rgba(243,246,247,0.6)">QUERYING 7 SOURCES</text>
              {/* typing → result. The dots fade out as result fades in. */}
              <g>
                {[0,1,2].map(i => (
                  <circle key={i} cx={HUB_X - 144 + i * 12} cy="358" r="2.4" fill="#E8513A">
                    <animate attributeName="opacity" values="0.25;1;0.25"
                             dur="1.1s" begin={`${i * 0.18}s`} repeatCount="indefinite" />
                  </circle>
                ))}
              </g>
              <text x={HUB_X - 150} y="380"
                    fontFamily="Host Grotesk" fontWeight="500" fontSize="16"
                    fill="#F3F6F7">North 82% · South 76%</text>
              <text x={HUB_X - 150} y="402"
                    fontFamily="Host Grotesk" fontWeight="500" fontSize="16"
                    fill="#F3F6F7">East 91% · West 68%</text>
            </g>

            {/* Insight ready pill */}
            <g className="bp-hub-msg bp-hub-msg-insight">
              <rect x={HUB_X - 120} y="432" width="240" height="30"
                    rx="15" fill="none" stroke="#E8513A" strokeWidth="1" />
              <circle cx={HUB_X - 100} cy="447" r="3.5" fill="#E8513A">
                <animate attributeName="opacity" values="1;0.35;1" dur="1.6s" repeatCount="indefinite" />
              </circle>
              <text x={HUB_X - 86} y="452"
                    fontFamily="Space Mono, monospace" fontSize="12" letterSpacing="2.5"
                    fill="#E8513A">INSIGHT READY · 2.3S</text>
            </g>

            {/* Subtle BODE watermark inside the window's lower band */}
            <text className="bp-hub-text" x={HUB_X} y="498" textAnchor="middle"
                  fontFamily="Host Grotesk" fontWeight="800" fontSize="28"
                  letterSpacing="-0.02em" fill="rgba(243,246,247,0.12)">
              BODE
            </text>
            <text className="bp-hub-text" x={HUB_X} y="518" textAnchor="middle"
                  fontFamily="Space Mono, monospace" fontSize="9" letterSpacing="2.5"
                  fill="rgba(232,81,58,0.6)">
              INTELLIGENCE LAYER
            </text>

            {/* Bracket flares — at the new larger corners. */}
            {[[-180, 180, 1, 1],[180, 180, -1, 1],[-180, 540, 1, -1],[180, 540, -1, -1]].map((b, i) => (
              <g key={i} className="bp-hub-bracket" stroke="#E8513A" strokeWidth="1.8" fill="none">
                <line x1={HUB_X + b[0]} y1={b[1]} x2={HUB_X + b[0] + b[2] * 22} y2={b[1]} />
                <line x1={HUB_X + b[0]} y1={b[1]} x2={HUB_X + b[0]} y2={b[1] + b[3] * 22} />
              </g>
            ))}
          </g>

          {/* Beam from hub to output */}
          <line className="bp-beam"
                x1={HUB_X + 180} y1="360"
                x2={OUT_X - 110} y2="360"
                stroke="#E8513A" strokeWidth="2" />

          {/* OUTPUT */}
          <g className="bp-output-frame">
            <rect x={OUT_X - 110} y="240" width="220" height="220" fill="none" stroke="currentColor" strokeWidth="1" />
            <text className="bp-output-label" x={OUT_X} y="280" textAnchor="middle"
                  fontFamily="Space Mono, monospace" fontSize="10" letterSpacing="2" fill="#E8513A">
              INTEGRATED INSIGHT
            </text>
            {[36, 64, 110, 84, 56].map((h, i) => (
              <rect key={i} className="bp-output-bar"
                    x={OUT_X - 80 + i * 32} y={440 - h}
                    width="22" height={h}
                    fill={i === 2 ? '#E8513A' : 'currentColor'}
                    opacity={i === 2 ? 1 : 0.6} />
            ))}
            <line x1={OUT_X - 90} y1="440" x2={OUT_X + 90} y2="440" stroke="currentColor" strokeWidth="0.5" />
          </g>

          {/* Closing measure */}
          <g className="bp-closing">
            <line x1={SRC_X - 110} y1={H - 80} x2={OUT_X + 110} y2={H - 80}
                  stroke="currentColor" strokeWidth="0.5" strokeDasharray="2 4" />
            <text x={SRC_X - 96} y={H - 60} fontFamily="Space Mono, monospace" fontSize="9" letterSpacing="1.5" fill="currentColor" opacity="0.7">7+ SOURCES</text>
            <text x={HUB_X} y={H - 60} textAnchor="middle" fontFamily="Space Mono, monospace" fontSize="9" letterSpacing="1.5" fill="#E8513A">→ ONE LAYER →</text>
            <text x={OUT_X + 110} y={H - 60} textAnchor="end" fontFamily="Space Mono, monospace" fontSize="9" letterSpacing="1.5" fill="currentColor" opacity="0.7">∞ CLARITY</text>
            <rect x={OUT_X + 100} y={H - 88} width="10" height="10" fill="#E8513A" />
          </g>
        </svg>
        </div>

        <div className="blueprint__caption">
          <span className="num">SCROLL</span>
          <span>to render the unified layer</span>
        </div>

        {/* Mobile: vertical re-imagining of the blueprint. The wide landscape
            SVG above is hidden under 768px; this compact vertical layout
            tells the same sources → agent → output story top-to-bottom so
            nothing is cropped or needs horizontal panning. */}
        <BlueprintMobile />
      </div>
    </section>
  );
}

function BlueprintMobile() {
  return (
    <div className="bp-mobile" aria-hidden="true">
      {/* Sources — 2-col grid up top so all 7 fit without scrolling. */}
      <div className="bp-mobile-stage bp-mobile-stage--sources">
        <div className="bp-mobile-stage-label"><span>I</span> Sources</div>
        <div className="bp-mobile-sources">
          {SOURCE_LABELS.map((label, i) => (
            <div className="bp-mobile-source" key={i}>
              <span className="dot"></span>
              <span>{label.toUpperCase()}</span>
            </div>
          ))}
        </div>
      </div>

      {/* Converging connectors. A small SVG draws coral lines from the row
          of sources above into a single point, with a travelling dash so it
          reads as live data. */}
      <svg className="bp-mobile-converge" viewBox="0 0 200 80" preserveAspectRatio="none" aria-hidden="true">
        {[20, 50, 80, 110, 140, 170, 100].map((x, i) => (
          <line key={i} x1={x} y1="0" x2="100" y2="80"
                stroke="#E8513A" strokeWidth="0.6" strokeOpacity="0.55" />
        ))}
        <line x1="100" y1="0" x2="100" y2="80"
              stroke="#E8513A" strokeWidth="1.2" strokeDasharray="2 6" strokeOpacity="0.85">
          <animate attributeName="stroke-dashoffset" values="0;-16" dur="1.2s" repeatCount="indefinite" />
        </line>
      </svg>

      {/* Hub — agent chat window. Same conceit as the SVG hub but rendered
          natively in HTML so the type stays crisp at any viewport width. */}
      <div className="bp-mobile-stage bp-mobile-stage--hub">
        <div className="bp-mobile-stage-label"><span>II</span> Unified</div>
        <div className="bp-mobile-hub">
          <div className="bp-mobile-hub__bar">
            <span className="bp-mobile-hub__lights"><span></span><span></span><span></span></span>
            <span className="bp-mobile-hub__title">BODE · AGENT</span>
            <span className="bp-mobile-hub__live"></span>
          </div>
          <div className="bp-mobile-hub__body">
            <div className="bp-mobile-hub__msg bp-mobile-hub__msg--user">Show occupancy by region.</div>
            <div className="bp-mobile-hub__msg bp-mobile-hub__msg--agent">
              <div className="bp-mobile-hub__meta">QUERYING 7 SOURCES</div>
              <div className="bp-mobile-hub__dots"><span></span><span></span><span></span></div>
              <div className="bp-mobile-hub__answer">North 82% · South 76%</div>
              <div className="bp-mobile-hub__answer">East 91% · West 68%</div>
            </div>
            <div className="bp-mobile-hub__pill">
              <span className="bp-mobile-hub__pill-dot"></span>
              <span>INSIGHT READY · 2.3S</span>
            </div>
          </div>
        </div>
      </div>

      {/* Beam connecting hub → output. Coral line with a travelling dash. */}
      <svg className="bp-mobile-beam" viewBox="0 0 20 60" preserveAspectRatio="none" aria-hidden="true">
        <line x1="10" y1="0" x2="10" y2="60" stroke="#E8513A" strokeWidth="1" strokeOpacity="0.5" />
        <line x1="10" y1="0" x2="10" y2="60" stroke="#E8513A" strokeWidth="2"
              strokeDasharray="3 8" strokeLinecap="round">
          <animate attributeName="stroke-dashoffset" values="0;-22" dur="1.4s" repeatCount="indefinite" />
        </line>
      </svg>

      {/* Output — bars rendered as flex children, the active bar coral. */}
      <div className="bp-mobile-stage bp-mobile-stage--output">
        <div className="bp-mobile-stage-label"><span>III</span> Clarity</div>
        <div className="bp-mobile-output">
          <div className="bp-mobile-output__label">Integrated Insight</div>
          <div className="bp-mobile-output__bars">
            {[36, 64, 110, 84, 56].map((h, i) => (
              <div key={i}
                   className={`bp-mobile-output__bar${i === 2 ? ' is-active' : ''}`}
                   style={{ height: `${(h / 110) * 100}%` }} />
            ))}
          </div>
        </div>
      </div>

      <div className="bp-mobile-closing">
        <span>7+ SOURCES</span>
        <span className="bp-mobile-closing__mid">→ ONE LAYER →</span>
        <span>∞ CLARITY</span>
      </div>
    </div>
  );
}

window.Blueprint = Blueprint;
