/* global React, SSIcon, SendIcon */
function TravelBar() {
  const elRef = React.useRef(null);
  const [mode, setMode] = React.useState("pre");

  // Scroll handler — bar lives at viewport center by default, then fully
  // merges with each section's slot while that section is sticky-pinned.
  // The sticky pin is what creates the "stoppage": bar stays merged and the
  // section's copy stays on screen while the user scrolls a stretch.
  React.useEffect(() => {
    const sectionIds = ["ss-section-0", "ss-section-1", "ss-section-2"];
    const slotIds = ["ss-bar-0", "ss-bar-1", "ss-bar-2", "cta-bar-anchor"];
    let lastMode = "pre";
    let frame = 0;

    const compute = () => {
      const el = elRef.current;
      if (!el) return;
      const sections = sectionIds.map((id) => document.getElementById(id));
      const slots = slotIds.map((id) => document.getElementById(id));
      if (sections.some((s) => !s) || slots.some((s) => !s)) return;

      const vh = window.innerHeight || 1;
      const scrollY = window.scrollY || window.pageYOffset || 0;
      const barH = el.offsetHeight || 68;
      const lastIdx = slotIds.length - 1;

      // Anchor viewport y for each slot — where the bar should sit when fully merged.
      // For scrollstory slots: their position within the sticky inner (constant
      // during sticky, so the bar visibly "stops" there). For CTA: its current
      // position (the section isn't sticky, so we just track it live).
      const anchorVpYs = slots.map((s, k) => {
        if (k < sections.length) {
          // offsetParent is the sticky .ss-section-inner, so offsetTop is the
          // y the slot will sit at when inner.vpTop = 0 (i.e., sticky-pinned).
          return s.offsetTop + s.offsetHeight / 2;
        }
        const r = s.getBoundingClientRect();
        return r.top + r.height / 2;
      });

      // Merge weight for each slot
      //   1.0 while the section is sticky-pinned (the "stoppage" zone)
      //   ramps down on either side over a fixed fade radius
      const fadeR = vh * 0.5;
      const weights = slots.map((s, k) => {
        if (k < sections.length) {
          const sec = sections[k];
          const sStart = sec.offsetTop;
          const sEnd = sStart + sec.offsetHeight - vh; // last scrollY where inner is pinned
          if (scrollY >= sStart && scrollY <= sEnd) return 1;
          const d = scrollY < sStart ? sStart - scrollY : scrollY - sEnd;
          return d < fadeR ? 1 - d / fadeR : 0;
        }
        // CTA — merge once viewport center reaches the slot, then stay merged
        const r = s.getBoundingClientRect();
        const slotDocCenter = r.top + scrollY + r.height / 2;
        const ref = scrollY + vh / 2;
        if (ref >= slotDocCenter) return 1;
        const d = slotDocCenter - ref;
        return d < fadeR ? 1 - d / fadeR : 0;
      });

      // Pick the strongest pull (sections can't overlap, so this is unambiguous)
      let bestIdx = -1;
      let bestWeight = 0;
      for (let k = 0; k <= lastIdx; k++) {
        if (weights[k] > bestWeight) {
          bestWeight = weights[k];
          bestIdx = k;
        }
      }

      const ws = bestWeight * bestWeight * (3 - 2 * bestWeight);

      // Blend the bar's viewport y between viewport center (= "moves with you")
      // and the active slot's anchor (= "merged with the section").
      const anchor = bestIdx >= 0 ? anchorVpYs[bestIdx] : vh / 2;
      const targetVpY = (vh / 2) * (1 - ws) + anchor * ws;
      const targetTop = targetVpY - barH / 2;

      // Content mode: track the merging slot when its pull is strong; otherwise
      // hold the last section's content so it doesn't flicker between merges.
      let nextMode;
      if (bestIdx >= 0 && bestWeight > 0.4) {
        nextMode = bestIdx === lastIdx ? "cta" : `phase${bestIdx}`;
      } else {
        let last = -1;
        for (let k = 0; k < sections.length; k++) {
          if (scrollY > sections[k].offsetTop) last = k;
          else break;
        }
        nextMode = last < 0 ? "pre" : `phase${last}`;
      }

      // Opacity envelope — fade in before the first section, fade out past CTA
      let opacity = 1;
      const sec0Start = sections[0].offsetTop;
      if (scrollY < sec0Start) {
        const d = sec0Start - scrollY;
        const fade = vh * 0.65;
        opacity = d > fade ? 0 : 1 - d / fade;
      }
      const ctaSlot = slots[lastIdx];
      const ctaRect = ctaSlot.getBoundingClientRect();
      const ctaDocCenter = ctaRect.top + scrollY + ctaSlot.offsetHeight / 2;
      const ref = scrollY + vh / 2;
      if (ref > ctaDocCenter) {
        const past = ref - ctaDocCenter;
        const fade = vh * 0.5;
        const fadeOut = past > fade ? 0 : 1 - past / fade;
        opacity = Math.min(opacity, fadeOut);
      }
      opacity = Math.max(0, Math.min(1, opacity));

      // Apply directly — no damping, so the bar tracks scroll perfectly
      el.style.transform = `translate(-50%, ${targetTop}px)`;
      el.style.opacity = opacity.toFixed(3);
      el.style.pointerEvents = opacity > 0.6 ? "auto" : "none";

      if (nextMode !== lastMode) {
        lastMode = nextMode;
        setMode(nextMode);
      }
    };

    const onScroll = () => {
      cancelAnimationFrame(frame);
      frame = requestAnimationFrame(compute);
    };
    compute();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
      cancelAnimationFrame(frame);
    };
  }, []);

  const isPanel = mode === "phase2";
  const isCta = mode === "cta";
  const isPre = mode === "pre";
  const lead = isPanel ? "spark" : "search";

  return (
    <div ref={elRef} className={`travel-bar travel-bar-${mode}`} style={{ opacity: 0 }}>
      <div className="chatbar-wrap travel-bar-wrap">
        <div className="chatbar travel-bar-inner">
          <div className="ss-chatbar-line">
            <span className="ss-chatbar-lead">
              <SSIcon kind={lead} size={18} />
            </span>
            <div className="ss-chatbar-text">
              {isCta
                ? "Describe what you want to sell..."
                : isPanel
                ? "Understanding and processing"
                : "Add context to ship a sharper store"}
            </div>
            {isPanel && (
              <div className="ss-chatbar-pills">
                <span className="ss-pill"><SSIcon kind="crawl" size={13} /> Live catalog crawl</span>
                <span className="ss-pill"><SSIcon kind="kb" size={13} /> Knowledge base</span>
                <span className="ss-pill"><SSIcon kind="web" size={13} /> Web search</span>
              </div>
            )}
            {!isPanel && (
              isCta ? (
                <button className="send" aria-label="Send"><SendIcon /></button>
              ) : (
                <button className="ss-chatbar-clip" aria-label="Attach"><SSIcon kind="file" size={16} /></button>
              )
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

window.TravelBar = TravelBar;
