// pyramid-main.jsx — scroll-driven main pyramid (Direction B · Luminous Ascent).
// Tiers reveal & activate bottom->top as you scroll. Click any tier to open
// its teaser modal. Exports window.L180Pyramid.

window.l180Clip = function (topW, botW) {
  const inset = (botW - topW) / 2;
  return `polygon(${inset}px 0, ${botW - inset}px 0, 100% 100%, 0% 100%)`;
};

// hue for a tier by ascent fraction (tier1 base -> cyan, tier5 apex -> green)
window.l180TierHue = function (n) {
  if (n == null) n = 1;
  var B = window.L180_BRAND || { cyan: "#1FC9E5", green: "#24CE62" };
  const frac = (n - 1) / 4;
  return `color-mix(in oklch, ${B.cyan} ${(1 - frac) * 100}%, ${B.green} ${frac * 100}%)`;
};

function L180Pyramid({ mode, onOpenTier }) {
  const tiers = window.L180_TIERS;          // top -> bottom (tier5..tier1)
  const order = [...tiers].reverse();        // bottom -> top reveal order (tier1..tier5)
  const stepVH = 0.6;                         // viewport fraction of scroll per tier
  const startVH = 0.28;                       // scroll before the climb begins
  const [activeIdx, setActiveIdx] = React.useState(0); // index into `order`
  const [prog, setProg] = React.useState(0);  // continuous progress 0..len-1 (drives the rail)
  const [scrolled, setScrolled] = React.useState(false);
  const [fit, setFit] = React.useState(1);
  const trackRef = React.useRef(null);
  const fitRef = React.useRef(null);
  const smooth = React.useRef({ target: 0, current: 0, animating: false, raf: null, enabled: false });

  // eased smooth-scroll: lerp the real scroll position toward a wheel/click target
  React.useEffect(() => {
    const S = smooth.current;
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    const coarse = window.matchMedia("(pointer: coarse)").matches;
    S.enabled = !reduce && !coarse;
    S.target = S.current = window.scrollY;
    const maxScroll = () => document.documentElement.scrollHeight - window.innerHeight;
    S._maxScroll = maxScroll;
    function tick() {
      S.current += (S.target - S.current) * 0.13;
      if (Math.abs(S.target - S.current) < 0.4) {
        S.current = S.target; window.scrollTo(0, S.current); S.animating = false; S.raf = null; return;
      }
      window.scrollTo(0, S.current);
      S.raf = requestAnimationFrame(tick);
    }
    function start() { if (!S.animating) { S.animating = true; S.current = window.scrollY; S.raf = requestAnimationFrame(tick); } }
    S._start = start;
    function onWheel(e) {
      if (!S.enabled || e.ctrlKey) return;
      // never hijack scrolling inside an open modal / funnel overlay
      if (document.querySelector(".l180-backdrop") || document.querySelector(".l180-funnel")) return;
      e.preventDefault();
      let d = e.deltaY;
      if (e.deltaMode === 1) d *= 16; else if (e.deltaMode === 2) d *= window.innerHeight;
      S.target = Math.max(0, Math.min(maxScroll(), S.target + d));
      start();
    }
    function onScrollSync() { if (!S.animating) { S.target = window.scrollY; S.current = window.scrollY; } }
    if (S.enabled) window.addEventListener("wheel", onWheel, { passive: false });
    window.addEventListener("scroll", onScrollSync, { passive: true });
    return () => {
      window.removeEventListener("wheel", onWheel);
      window.removeEventListener("scroll", onScrollSync);
      if (S.raf) cancelAnimationFrame(S.raf);
    };
  }, []);

  React.useEffect(() => {
    function onScroll() {
      const y = window.scrollY;
      setScrolled(y > 40);
      const start = window.innerHeight * startVH;
      const step = window.innerHeight * stepVH;
      // guard: during first mount innerHeight can be 0 -> step 0 -> NaN coords
      let p = step > 0 ? (y - start) / step : 0;
      if (!Number.isFinite(p)) p = 0;
      p = Math.max(0, Math.min(order.length - 1, p));
      setProg(p);
      setActiveIdx(Math.round(p));
    }
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    return () => { window.removeEventListener("scroll", onScroll); window.removeEventListener("resize", onScroll); };
  }, [order.length]);

  // jump the scroll position so tier at reveal-index `i` becomes active
  function scrollToTier(i) {
    const start = window.innerHeight * startVH;
    const step = window.innerHeight * stepVH;
    const y = Math.max(0, start + i * step + 2);
    const S = smooth.current;
    if (S.enabled && S._start) { S.target = Math.min(S._maxScroll(), y); S._start(); }
    else window.scrollTo({ top: y, behavior: "smooth" });
  }

  // auto-fit the stage content to the viewport height
  React.useEffect(() => {
    function fitNow() {
      const el = fitRef.current;
      if (!el) return;
      const h = el.scrollHeight;
      const avail = window.innerHeight - 96; // leave room for top bar + hint
      setFit(Math.min(1, avail / h));
    }
    fitNow();
    window.addEventListener("resize", fitNow);
    const t = setTimeout(fitNow, 300); // after fonts settle
    return () => { window.removeEventListener("resize", fitNow); clearTimeout(t); };
  }, []);

  const activeTier = order[activeIdx] || order[0];

  // ---- diagonal rail geometry (block coords: 0..baseW x, 0..blockH y, y=0 top) ----
  const railBandH = 96, railGap = 8;
  const railN = order.length;
  const railBlockH = railN * railBandH + (railN - 1) * railGap;
  const railBaseW = order[0].botW;                 // widest (base)
  const railApexTopW = order[railN - 1].topW;      // narrowest (apex top edge)
  const railInset = (railBaseW - railApexTopW) / 2;
  const railEdgeGap = 32;                           // clear the pyramid edges (~20px on screen)
  function railPt(p) {                              // p: 0 = base .. railN-1 = apex
    if (!Number.isFinite(p)) p = 0;
    const yc = (railBlockH - railBandH / 2) - p * (railBandH + railGap);
    const t = 1 - yc / railBlockH;
    const xl = railInset * t;
    return { xl: xl - railEdgeGap, xr: railBaseW - xl + railEdgeGap, y: yc };
  }

  function bandStyle(tier, revealed, isActive, oi) {
    const hue = window.l180TierHue(tier.n);
    const baseScale = isActive ? 1.018 : 1;
    // "lit" = active OR already ascended-through. Once a tier is reached it keeps
    // its full color; the active tier alone gets the micro-zoom + extra bloom.
    const lit = isActive || revealed;
    return {
      width: tier.botW,
      height: 96,
      margin: "0 auto",
      clipPath: window.l180Clip(tier.topW, tier.botW),
      WebkitClipPath: window.l180Clip(tier.topW, tier.botW),
      position: "relative",
      display: "flex", alignItems: "center", justifyContent: "center",
      cursor: "pointer",
      // Always-color variant: every band carries its hue gradient at all times.
      // Reached tiers stay fully lit; not-yet-reached tiers sit at a soft preview.
      background: lit
        ? `radial-gradient(120% 170% at 50% 0%, color-mix(in oklch, ${hue} 52%, transparent), color-mix(in oklch, ${hue} 14%, transparent) 72%)`
        : `radial-gradient(120% 170% at 50% 0%, color-mix(in oklch, ${hue} 26%, transparent), color-mix(in oklch, ${hue} 6%, transparent) 74%)`,
      border: `1px solid ${lit ? `color-mix(in oklch, ${hue} 80%, transparent)` : `color-mix(in oklch, ${hue} 40%, transparent)`}`,
      boxShadow: isActive
        ? `0 0 78px color-mix(in oklch, ${hue} 52%, transparent), inset 0 1px 0 color-mix(in oklch, ${hue} 58%, transparent)`
        : lit
        ? `0 0 40px color-mix(in oklch, ${hue} 34%, transparent), inset 0 1px 0 color-mix(in oklch, ${hue} 48%, transparent)`
        : `0 0 18px color-mix(in oklch, ${hue} 14%, transparent), inset 0 1px 0 color-mix(in oklch, ${hue} 26%, transparent)`,
      opacity: isActive ? 1 : lit ? 0.98 : 0.6,
      filter: isActive ? "none" : lit ? "saturate(1) brightness(1)" : "saturate(.9) brightness(.82)",
      transform: revealed ? `translateY(0) scale(${baseScale})` : "translateY(18px) scale(.93)",
      transformOrigin: "center bottom",
      transition: "transform .55s cubic-bezier(.34,1.3,.5,1), box-shadow .6s cubic-bezier(.22,1,.36,1), background .6s ease, border-color .6s ease, filter .6s ease, opacity .5s ease",
      willChange: "transform, filter, opacity",
    };
  }

  return (
    <div style={{ position: "relative" }}>
      {/* scroll track height drives the reveal */}
      <div ref={trackRef} style={{ height: `${(startVH + (order.length - 1) * stepVH) * 100 + 130}vh` }}>
        {/* sticky stage */}
        <div style={{
          position: "sticky", top: 0, height: "100vh", overflow: "hidden",
          display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center",
          background: `radial-gradient(120% 95% at 50% 6%, #1c1c1e, ${L180_BRAND.navy} 58%, ${L180_BRAND.ink})`,
        }}>
          {/* ambient bloom — slow color wash that follows the focused tier */}
          <div style={{
            position: "absolute", inset: 0, pointerEvents: "none",
            background: `radial-gradient(72% 56% at 50% 34%, color-mix(in oklch, ${window.l180TierHue(activeTier.n)} 20%, transparent), transparent 72%)`,
            transition: "background 1.4s ease",
          }} />
          {/* base-edge counter-wash for depth, also tied to the focused tier */}
          <div style={{
            position: "absolute", inset: 0, pointerEvents: "none",
            background: `radial-gradient(120% 80% at 50% 108%, color-mix(in oklch, ${window.l180TierHue(activeTier.n)} 12%, transparent), transparent 60%)`,
            transition: "background 1.6s ease",
          }} />

          {/* fit-scaled stage content */}
          <div ref={fitRef} style={{ transform: `scale(${fit})`, transformOrigin: "center center", display: "flex", flexDirection: "column", alignItems: "center", zIndex: 2 }}>
          {/* header */}
          <div className="l180-hero-enter" style={{ textAlign: "center", marginBottom: 22, zIndex: 3, padding: "0 24px" }}>
            <div className="l180-eyebrow" style={{ display: "inline-flex", alignItems: "center", gap: 10 }}>
              {mode === "agent" ? "Agent View" : "The LIFE180 Process"}
              {mode === "agent" && <span className="l180-agentflag">● Deeper layer on</span>}
            </div>
            <h1 className="l180-h1" style={{ margin: "8px 0 0" }}>Clarity creates confidence.</h1>
            <p className="l180-sub" style={{ margin: "10px auto 0", maxWidth: 564 }}>
              {mode === "agent"
                ? "Each tier is a guided conversation. Scroll the framework, then open any tier for talking points, depth cues, and what to flag."
                : "Five tiers. Build the floor before the ceiling. Scroll to rise — click any tier to look inside."}
            </p>
          </div>

          {/* pyramid */}
          <div style={{ position: "relative", zIndex: 2 }}>
          <div style={{ display: "flex", flexDirection: "column", gap: 8, alignItems: "center" }}>
            {tiers.map((tier) => {
              const oi = order.indexOf(tier);
              const revealed = oi <= activeIdx;
              const isActive = activeTier.n === tier.n;
              return (
                <div key={tier.n} className="l180-tierband" style={{ width: tier.botW, animationDelay: `${oi * 0.11}s` }}
                     onMouseEnter={() => { setActiveIdx(oi); setProg(oi); }}
                     onClick={() => onOpenTier(tier.n)}>
                  <div style={bandStyle(tier, revealed, isActive, oi)}>
                    <div style={{ textAlign: "center", padding: "0 14px", maxWidth: tier.botW - 28, zIndex: 2 }}>
                      <div style={{
                        fontFamily: "'Montserrat',sans-serif", fontWeight: 800, fontSize: 16,
                        color: "#fff", lineHeight: 1, whiteSpace: "nowrap",
                        textShadow: "0 1px 10px rgba(0,0,0,.45)",
                      }}>
                        <span style={{ opacity: .55, fontSize: 12, marginRight: 8 }}>0{tier.n}</span>
                        {tier.name}
                      </div>
                      <div style={{
                        fontSize: 11, marginTop: 6, color: "rgba(255,255,255,.87)",
                        fontStyle: "italic", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis",
                        maxWidth: "100%",
                        opacity: isActive ? 1 : 0, maxHeight: isActive ? 18 : 0, transform: isActive ? "translateY(0)" : "translateY(-4px)",
                        transition: "opacity .55s ease .05s, transform .55s cubic-bezier(.22,1,.36,1) .05s, max-height .5s ease",
                      }}>{mode === "agent" ? tier.positioning : tier.tagline}</div>
                    </div>
                    {tier.routing && (
                      <div style={{
                        position: "absolute", right: 22, bottom: 11,
                        fontSize: 9, letterSpacing: ".14em", fontWeight: 700, fontFamily: "'Montserrat',sans-serif",
                        color: "rgba(255,255,255,.76)", border: "1px solid rgba(255,255,255,.36)",
                        borderRadius: 20, padding: "3px 9px", opacity: isActive ? 1 : 0, transition: "opacity .5s ease",
                        whiteSpace: "nowrap", pointerEvents: "none",
                      }}>ROUTING TIER</div>
                    )}
                  </div>
                </div>
              );
            })}
          </div>

          {/* diagonal ascent rails — hug both pyramid slopes, thumbs climb on scroll */}
          <svg className="l180-railsvg" viewBox={`0 0 ${railBaseW} ${railBlockH}`} preserveAspectRatio="xMidYMid meet"
               style={{ position: "absolute", inset: 0, width: "100%", height: "100%", overflow: "visible", zIndex: 4, pointerEvents: "none" }}>
            <defs>
              <linearGradient id="l180railgrad" x1="0" y1="1" x2="0" y2="0">
                <stop offset="0" stopColor="#1FC9E5" />
                <stop offset="1" stopColor="#24CE62" />
              </linearGradient>
            </defs>
            {/* faint full-slope tracks */}
            <line x1={railPt(0).xl} y1={railPt(0).y} x2={railPt(railN - 1).xl} y2={railPt(railN - 1).y} stroke="rgba(255,255,255,.2)" strokeWidth="2" strokeLinecap="round" />
            <line x1={railPt(0).xr} y1={railPt(0).y} x2={railPt(railN - 1).xr} y2={railPt(railN - 1).y} stroke="rgba(255,255,255,.2)" strokeWidth="2" strokeLinecap="round" />
            {/* progress fill from base up to current position */}
            <line x1={railPt(0).xl} y1={railPt(0).y} x2={railPt(prog).xl} y2={railPt(prog).y} stroke="url(#l180railgrad)" strokeWidth="3" strokeLinecap="round" />
            <line x1={railPt(0).xr} y1={railPt(0).y} x2={railPt(prog).xr} y2={railPt(prog).y} stroke="url(#l180railgrad)" strokeWidth="3" strokeLinecap="round" />
            {/* tier dots (clickable) */}
            {order.map((t, i) => {
              const pt = railPt(i);
              const on = Math.round(prog) === i;
              const h = window.l180TierHue(t.n);
              const r = on ? 6 : 4;
              const dotStyle = { fill: on ? h : "#0F0F10", stroke: on ? h : "rgba(255,255,255,.45)", strokeWidth: 1.5, filter: on ? `drop-shadow(0 0 6px ${h})` : "none" };
              return (
                <g key={t.n} style={{ pointerEvents: "auto", cursor: "pointer" }} onClick={() => scrollToTier(i)}>
                  <title>{`Tier 0${t.n} · ${t.name}`}</title>
                  <circle cx={pt.xl} cy={pt.y} r="14" fill="transparent" />
                  <circle cx={pt.xr} cy={pt.y} r="14" fill="transparent" />
                  <circle cx={pt.xl} cy={pt.y} r={r} style={dotStyle} />
                  <circle cx={pt.xr} cy={pt.y} r={r} style={dotStyle} />
                </g>
              );
            })}
            {/* live thumbs */}
            <circle cx={railPt(prog).xl} cy={railPt(prog).y} r="6.5" style={{ fill: window.l180TierHue(activeTier.n), stroke: "#fff", strokeWidth: 2, filter: `drop-shadow(0 0 8px ${window.l180TierHue(activeTier.n)})` }} />
            <circle cx={railPt(prog).xr} cy={railPt(prog).y} r="6.5" style={{ fill: window.l180TierHue(activeTier.n), stroke: "#fff", strokeWidth: 2, filter: `drop-shadow(0 0 8px ${window.l180TierHue(activeTier.n)})` }} />
          </svg>
          </div>

          {/* explore prompt */}
          <button className="l180-explore l180-explore-enter" style={{ zIndex: 3, marginTop: 26 }}
                  onClick={() => onOpenTier(activeTier.n)}>
            {mode === "agent" ? "Open conversation" : "Look inside"} · Tier 0{activeTier.n} · {activeTier.name}
            <span style={{ marginLeft: 8 }}>→</span>
          </button>
          {mode === "agent" && activeTier.intro && (
            <div className="l180-agentnugget" key={activeTier.n}>
              <span className="l180-agentnugget-h">Agent cue · {activeTier.streams.length} conversations to guide</span>
              <p>{activeTier.intro}</p>
            </div>
          )}
          </div>

          {/* scroll hint */}
          <div style={{
            position: "absolute", bottom: 26, left: "50%", transform: "translateX(-50%)",
            color: "rgba(255,255,255,.58)", fontSize: 11, letterSpacing: ".18em", fontFamily: "'Montserrat',sans-serif",
            fontWeight: 600, textTransform: "uppercase", zIndex: 3,
            opacity: scrolled ? 0 : 1, transition: "opacity .4s ease",
            display: "flex", flexDirection: "column", alignItems: "center", gap: 6,
          }}>
            Scroll to ascend
            <span className="l180-scrolldot" />
          </div>
        </div>
      </div>
    </div>
  );
}

window.L180Pyramid = L180Pyramid;
