/* GoWithMe — motion primitives. Stage manages layered page transitions;
   Stagger/Rise drive content entrance. Inert (no-op classes) when anim.css
   isn't loaded, so the capture harness renders everything static. */

/* ---------- Stage: stacked push / pop / tab transitions ----------
   Transition state is DERIVED (shownKey vs live viewKey), never stored as a
   frozen element that gets swapped — so the incoming screen mounts exactly
   once and its entrance animation completes without restarting. */
function Stage({ viewKey, navType, bg, children }) {
  const [shownKey, setShownKey] = React.useState(viewKey);
  const prevEl = React.useRef(children);   // last element of the settled screen
  const typeRef = React.useRef('none');
  const first = React.useRef(true);

  // remember the screen element + nav direction while a view is settled
  if (shownKey === viewKey) { prevEl.current = children; }
  else { typeRef.current = navType || 'push'; }

  React.useEffect(() => { first.current = false; }, []);

  const wrap = { position: 'absolute', inset: 0, overflow: 'hidden', background: bg };

  // settled — one live layer, reconciled by key (no remount on prop changes)
  if (shownKey === viewKey) {
    return (
      <div style={wrap}>
        <div key={viewKey} className={'gw-layer' + (first.current ? ' gw-fade-in' : '')} style={{ position: 'absolute', inset: 0, background: bg }}>
          {children}
        </div>
      </div>
    );
  }

  // transitioning shownKey -> viewKey
  const from = shownKey, to = viewKey, type = typeRef.current;
  const outEl = prevEl.current, inEl = children;
  const settle = () => setShownKey(viewKey);

  let layers;
  if (type === 'pop') {
    layers = [
      { key: to,   el: inEl,  cls: 'gw-pop-in',  z: 1, dim: 'out', s: true },
      { key: from, el: outEl, cls: 'gw-pop-out', z: 3 },
    ];
  } else if (type === 'tab' || type === 'replace') {
    layers = [
      { key: from, el: outEl, cls: 'gw-fade-out', z: 1 },
      { key: to,   el: inEl,  cls: 'gw-fade-in',  z: 2, s: true },
    ];
  } else { // push
    layers = [
      { key: from, el: outEl, cls: 'gw-push-under', z: 1, dim: 'in' },
      { key: to,   el: inEl,  cls: 'gw-push-in',    z: 3, s: true },
    ];
  }

  return (
    <div style={wrap}>
      {layers.map(l => (
        <div key={l.key} className={'gw-layer ' + l.cls}
          style={{ position: 'absolute', inset: 0, zIndex: l.z, background: bg }}
          onAnimationEnd={l.s ? (e) => { if (e.target === e.currentTarget) settle(); } : undefined}>
          {l.dim && <div className={l.dim === 'in' ? 'gw-dim-in' : 'gw-dim-out'}
            style={{ position: 'absolute', inset: 0, background: '#081220', zIndex: 9, pointerEvents: 'none' }} />}
          {l.el}
        </div>
      ))}
    </div>
  );
}

/* ---------- Stagger: cascade direct children up on mount ---------- */
function Stagger({ step = 52, start = 60, cap = 9, style, children }) {
  const arr = React.Children.toArray(children).filter(Boolean);
  return (
    <React.Fragment>
      {arr.map((c, i) => (
        <div key={i} className="gw-rise" style={{ animationDelay: (start + Math.min(i, cap) * step) + 'ms', ...style }}>{c}</div>
      ))}
    </React.Fragment>
  );
}

/* ---------- Rise: single element entrance ---------- */
function Rise({ delay = 0, style, children }) {
  return <div className="gw-rise" style={{ animationDelay: delay + 'ms', ...style }}>{children}</div>;
}

Object.assign(window, { Stage, Stagger, Rise });
