/* global React */
const { useState, useEffect, useRef } = React;

// The Shift — a single large declarative statement that types itself
// out when the section scrolls into view. The closing phrase "There is
// now." lands in a muted colour as the punchline. Not interactive.
//
// Animation: ~3.5s total, fires once per page load. Main text flows
// quickly at a constant rate; a brief pause; then "There is now."
// stamps out slower.
//
// Layout reservation: the full text is always present in the DOM with
// unrevealed portions set to color: transparent. Layout is identical
// before, during, and after the animation; no content reflows.
//
// Accessibility: the entire statement is exposed to screen readers via
// aria-label on the <p>. The visible animated content is aria-hidden.

const MAIN_TEXT = "Financial services runs on judgment. Yet too much of it is still spent producing the inputs, the research, the reconciliations, the reports, the records. That was never a choice. It was a constraint. ";
const TRIGGER_TEXT = "The constraint is gone.";

const MAIN_DUR = 2600;     // ms - fast typing for the main text
const PAUSE_DUR = 150;     // ms - beat before the punchline
const TRIGGER_DUR = 800;   // ms - slower, stamped delivery
const TOTAL_DUR = MAIN_DUR + PAUSE_DUR + TRIGGER_DUR;

function WhyNow() {
  const [revealedMain, setRevealedMain] = useState(0);
  const [revealedTrigger, setRevealedTrigger] = useState(0);

  const sectionRef = useRef(null);
  const hasAnimated = useRef(false);

  // Typing animation, kicked off when the section scrolls into view.
  useEffect(() => {
    if (!sectionRef.current) return;

    const observer = new IntersectionObserver(
      ([entry]) => {
        if (!entry.isIntersecting || hasAnimated.current) return;
        hasAnimated.current = true;
        observer.disconnect();

        const startTime = performance.now();

        const tick = (now) => {
          const elapsed = now - startTime;

          if (elapsed < MAIN_DUR) {
            const p = elapsed / MAIN_DUR;
            setRevealedMain(Math.floor(p * MAIN_TEXT.length));
            requestAnimationFrame(tick);
          } else if (elapsed < MAIN_DUR + PAUSE_DUR) {
            setRevealedMain(MAIN_TEXT.length);
            requestAnimationFrame(tick);
          } else if (elapsed < TOTAL_DUR) {
            const p = (elapsed - MAIN_DUR - PAUSE_DUR) / TRIGGER_DUR;
            setRevealedMain(MAIN_TEXT.length);
            setRevealedTrigger(Math.floor(p * TRIGGER_TEXT.length));
            requestAnimationFrame(tick);
          } else {
            setRevealedMain(MAIN_TEXT.length);
            setRevealedTrigger(TRIGGER_TEXT.length);
          }
        };

        requestAnimationFrame(tick);
      },
      { threshold: 0.25 }
    );

    observer.observe(sectionRef.current);
    return () => observer.disconnect();
  }, []);

  const mainVisible = MAIN_TEXT.slice(0, revealedMain);
  const mainHidden = MAIN_TEXT.slice(revealedMain);
  const triggerVisible = TRIGGER_TEXT.slice(0, revealedTrigger);
  const triggerHidden = TRIGGER_TEXT.slice(revealedTrigger);

  return (
    <section className="section" id="why-now" ref={sectionRef}>
      <div className="page">
        <p className="shift-statement" aria-label={`${MAIN_TEXT}${TRIGGER_TEXT}`}>
          <span aria-hidden="true">
            {mainVisible}
            <span className="shift-statement__hidden">{mainHidden}</span>
            <span className="shift-statement__trigger">
              {triggerVisible}
              <span className="shift-statement__hidden">{triggerHidden}</span>
            </span>
          </span>
        </p>
      </div>
    </section>
  );
}

window.WhyNow = WhyNow;