// components/segment-rotator.jsx
//
// Rotating "Is this you?" question that cycles through audience segments
// every 1.25s. The container reserves the width of the longest phrase
// (an invisible measurement span) so the line never jitters. The active
// phrase sits absolutely positioned on top; incoming/outgoing phrases
// translate vertically with a sharp easing curve — scoreboard-tick feel.
//
// Accessibility:
//   - aria-live="polite" so screen readers announce phrase changes
//     without interrupting other content
//   - prefers-reduced-motion: freeze on the first phrase, no rotation
//   - phrases are real text in the DOM (not pseudo-element content)

function SegmentRotator({ phrases, intervalMs = 2000, colors = ["#FF8A50"], className = "", holdFirstUntilVisible = false, initialDwellMultiplier = 1 }) {
  const [idx, setIdx] = React.useState(0);
  const [reduced, setReduced] = React.useState(false);
  const wrapperRef = React.useRef(null);
  // When holdFirstUntilVisible is true, we wait for the rotator wrapper to
  // enter the viewport before starting the cycle. This prevents the
  // jarring "snap" feeling where the rotator has already cycled past the
  // first phrase by the time the user scrolls to it.
  const [armed, setArmed] = React.useState(!holdFirstUntilVisible);

  React.useEffect(() => {
    if (!holdFirstUntilVisible || armed) return;
    if (!wrapperRef.current) return;
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((entry) => {
          if (entry.isIntersecting) {
            setArmed(true);
            io.disconnect();
          }
        });
      },
      { threshold: 0.4 }
    );
    io.observe(wrapperRef.current);
    return () => io.disconnect();
  }, [holdFirstUntilVisible, armed]);

  React.useEffect(() => {
    const m = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)");
    if (m && m.matches) {
      setReduced(true);
      return;
    }
    if (!armed) return;
    // First rotation can be held longer (initialDwellMultiplier * intervalMs)
    // so the reader actually gets to inhabit the first phrase before it
    // changes. After the first tick, fall back to the normal interval.
    let timeoutId;
    let intervalId;
    const firstDelay = intervalMs * Math.max(1, initialDwellMultiplier);
    timeoutId = setTimeout(() => {
      setIdx((i) => (i + 1) % phrases.length);
      intervalId = setInterval(() => {
        setIdx((i) => (i + 1) % phrases.length);
      }, intervalMs);
    }, firstDelay);
    return () => {
      clearTimeout(timeoutId);
      if (intervalId) clearInterval(intervalId);
    };
  }, [phrases.length, intervalMs, colors.length, armed, initialDwellMultiplier]);

  // Longest phrase used as an invisible width-reserver so layout doesn't
  // shift as phrases cycle.
  const longest = phrases.reduce((a, b) => (a.length > b.length ? a : b), "");

  return (
    <span
      className={"segment-rotator " + className}
      aria-live="polite"
      aria-atomic="true"
      ref={wrapperRef}
    >
      {/* Visible: only the active phrase animates in/out. Each phrase is
          rendered with its index in the keying so React mounts/unmounts
          for clean enter/exit transitions. Color is indexed against the
          phrase position so the order is deterministic — the colors prop
          is treated as a parallel array to phrases. If colors is shorter
          than phrases, it loops via modulo. */}
      <span
        className="segment-rotator-active"
        key={idx}
        style={{ color: colors[idx % colors.length] || colors[0] }}
      >
        {phrases[idx]}
      </span>
      {/* Invisible measurer — reserves the layout width of the longest
          phrase so the surrounding paragraph never jumps. */}
      <span className="segment-rotator-measure" aria-hidden="true">
        {longest}
      </span>
    </span>
  );
}

window.SegmentRotator = SegmentRotator;
