// Atlas — S09Zoom: cinematic transition from student (Mariana) view to teacher view.
// 4 phases over ~4s, with reduced-motion fallback and Esc skip.
const { useState: _useState9, useEffect: _useEffect9, useMemo: _useMemo9 } = React;

function S09Zoom() {
  const useState = _useState9, useEffect = _useEffect9, useMemo = _useMemo9;
  const [, set] = useAtlasState();

  // Reduced motion detection
  const reducedMotion = useMemo(() => {
    try { return window.matchMedia('(prefers-reduced-motion: reduce)').matches; }
    catch (e) { return false; }
  }, []);

  // Phase state machine: 0=idle mount, 1=pull back, 2=peers emerge, 3=headline, 4=teacher morph
  const [phase, setPhase] = useState(0);
  const [skipped, setSkipped] = useState(false);

  // Advance phases via setTimeout chain
  useEffect(() => {
    if (reducedMotion || skipped) {
      // Fast-path: jump straight to the final state
      const t = setTimeout(() => setPhase(4), 50);
      return () => clearTimeout(t);
    }
    const ts = [
      setTimeout(() => setPhase(1), 300),
      setTimeout(() => setPhase(2), 1000),
      setTimeout(() => setPhase(3), 2400),
      setTimeout(() => setPhase(4), 3200),
    ];
    return () => ts.forEach(clearTimeout);
  }, [reducedMotion, skipped]);

  // Auto-navigate to t01 2.5s after the teacher morph phase
  useEffect(() => {
    if (phase < 4) return;
    const t = setTimeout(() => {
      set({ perspective: 'teacher', screen: 't01' });
    }, 2500);
    return () => clearTimeout(t);
  }, [phase]);

  // Esc to skip
  useEffect(() => {
    function onKey(e) {
      if (e.key === 'Escape') setSkipped(true);
    }
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);

  function enterTeacher() {
    set({ perspective: 'teacher', screen: 't01' });
  }

  // Deterministic peer layout on a scattered ellipse around Mariana's offset position.
  // 19 peers distributed across 3 depth rows. Mariana sits at ~65% x / 45% y after pull-back.
  const peers = useMemo(() => buildPeers(AtlasData.peerGraphCount), []);

  // Mariana scale/position transform
  // In phase 0: centered, scale 1 (roughly 80% viewport sized graph).
  // In phase 1+: scaled to ~0.4 and offset to the right-center.
  const marianaScale = phase === 0 ? 1 : 0.4;
  const marianaTx = phase === 0 ? '0%' : '18%';   // shift right
  const marianaTy = phase === 0 ? '0%' : '-4%';   // slight lift

  const reducedOrSkipped = reducedMotion || skipped;

  return (
    <div
      style={{
        position: 'absolute', inset: 0, overflow: 'hidden',
        background: `radial-gradient(ellipse at center, ${T.paper0} 0%, ${T.paper1} 70%, ${T.paper2} 100%)`,
        fontFamily: T.sans,
      }}
    >
      {/* Scoped keyframes for this screen */}
      <style>{`
        @keyframes atlas-zoom-peer-in {
          from { opacity: 0; transform: scale(var(--peer-scale-from)); }
          to   { opacity: var(--peer-opacity); transform: scale(var(--peer-scale)); }
        }
        @keyframes atlas-zoom-fade-out {
          from { opacity: 1; }
          to   { opacity: 0; }
        }
        @keyframes atlas-zoom-fade-up {
          from { opacity: 0; transform: translate(-50%, 20px); }
          to   { opacity: 1; transform: translate(-50%, 0); }
        }
      `}</style>

      {/* Top label (phase 0 → fades out by phase 2) */}
      <div
        aria-hidden={phase >= 2}
        style={{
          position: 'absolute', top: '10%', left: '50%',
          transform: 'translateX(-50%)',
          fontFamily: T.serif, fontSize: '1.125rem',
          color: T.ink7,
          fontVariationSettings: '"opsz" 18',
          letterSpacing: '-0.005em',
          opacity: reducedOrSkipped ? 0 : (phase === 0 ? 0 : phase === 1 ? 1 : 0),
          animation: (!reducedOrSkipped && phase === 0) ? 'fadeIn 300ms ease-out forwards' : undefined,
          transition: 'opacity 500ms ease-out',
          pointerEvents: 'none',
          whiteSpace: 'nowrap',
        }}
      >
        El grafo de Mariana.
      </div>

      {/* Stage — holds peers (behind) and Mariana (front). */}
      <div style={{ position: 'absolute', inset: 0 }}>
        {/* Peers layer — emerges in phase 2+ */}
        {(phase >= 2 || reducedOrSkipped) && peers.map((p, i) => (
          <PeerGraph
            key={p.id}
            peer={p}
            index={i}
            reducedMotion={reducedOrSkipped}
          />
        ))}

        {/* Mariana's graph — the focal anchor that shrinks and shifts */}
        <div
          style={{
            position: 'absolute',
            top: '50%', left: '50%',
            width: 580, height: 395,
            marginLeft: -290, marginTop: -197,
            transform: reducedOrSkipped
              ? 'translate(-42%, -30%) scale(0.32)'
              : `translate(${marianaTx}, ${marianaTy}) scale(${marianaScale})`,
            transformOrigin: 'center center',
            transition: reducedOrSkipped
              ? 'opacity 600ms ease-out'
              : 'transform 900ms cubic-bezier(.2,.6,.2,1)',
            zIndex: 20,
            filter: phase >= 3 ? 'saturate(0.92)' : 'none',
            pointerEvents: 'none',
          }}
        >
          <SVGGraph
            nodes={AtlasData.nodes}
            edges={AtlasData.edges}
            width={580}
            height={395}
            openedEdgeId={AtlasData.animEdgeId}
          />
        </div>
      </div>

      {/* Headlines layer — phase 3 (20 estudiantes) crossfades into phase 4 (Vista del profesor) */}
      <div
        style={{
          position: 'absolute',
          top: '12%', left: '50%',
          transform: 'translateX(-50%)',
          textAlign: 'center',
          pointerEvents: 'none',
          zIndex: 40,
          width: 'max-content',
          maxWidth: '90vw',
        }}
      >
        {/* "20 estudiantes" — phase 3 */}
        <div
          style={{
            opacity: reducedOrSkipped ? 0 : (phase === 3 ? 1 : 0),
            transform: (!reducedOrSkipped && phase === 3) ? 'translateY(0)' : 'translateY(10px)',
            transition: 'opacity 400ms ease-out, transform 420ms ease-out',
          }}
        >
          <div style={{
            fontFamily: T.serif, fontSize: '2rem', fontWeight: 500,
            color: T.ink9, letterSpacing: '-0.02em',
            fontVariationSettings: '"opsz" 48',
            lineHeight: 1.15,
          }}>
            20 estudiantes
          </div>
          <div style={{
            marginTop: 10,
            fontFamily: T.serif, fontSize: '1rem', fontWeight: 400,
            color: T.ink7,
            fontVariationSettings: '"opsz" 18',
          }}>
            · 1 materia · 1 grafo compartido
          </div>
        </div>

        {/* "Vista del profesor." — phase 4 */}
        <div
          style={{
            position: (!reducedOrSkipped && phase < 4) ? 'absolute' : 'relative',
            top: (!reducedOrSkipped && phase < 4) ? 0 : undefined,
            left: (!reducedOrSkipped && phase < 4) ? 0 : undefined,
            right: (!reducedOrSkipped && phase < 4) ? 0 : undefined,
            marginTop: (phase >= 4 || reducedOrSkipped) ? -60 : 0,
            opacity: phase >= 4 || reducedOrSkipped ? 1 : 0,
            transform: phase >= 4 || reducedOrSkipped ? 'translateY(0)' : 'translateY(10px)',
            transition: 'opacity 500ms ease-out 200ms, transform 500ms ease-out 200ms',
          }}
        >
          <div style={{
            fontFamily: T.serif, fontSize: '2.25rem', fontWeight: 500,
            color: T.ink9, letterSpacing: '-0.025em',
            fontVariationSettings: '"opsz" 48',
            lineHeight: 1.1,
          }}>
            Vista del profesor.
          </div>
          <div style={{
            marginTop: 14, marginLeft: 'auto', marginRight: 'auto',
            width: 48, height: 2,
            background: T.acc6,
            opacity: 0.8,
          }} />
        </div>
      </div>

      {/* Enter-teacher button — appears in phase 4, transitions from muted to primary */}
      <div
        style={{
          position: 'absolute',
          bottom: '12%', left: '50%',
          transform: 'translateX(-50%)',
          opacity: phase >= 4 || reducedOrSkipped ? 1 : 0,
          transition: 'opacity 500ms ease-out 400ms',
          zIndex: 50,
          pointerEvents: phase >= 4 || reducedOrSkipped ? 'auto' : 'none',
        }}
      >
        <EnterTeacherButton phase={phase} reducedOrSkipped={reducedOrSkipped} onClick={enterTeacher} />
      </div>

      {/* Esc hint — tiny, discreet, only visible during the cinematic */}
      {!reducedOrSkipped && phase < 4 && (
        <div style={{
          position: 'absolute', bottom: 14, right: 16,
          fontFamily: T.mono, fontSize: '0.6875rem',
          color: T.ink4, opacity: 0.65,
          pointerEvents: 'none',
        }}>
          esc — saltar
        </div>
      )}
    </div>
  );
}

// ── Sub-components ──────────────────────────────────────────────────────────

function EnterTeacherButton({ phase, reducedOrSkipped, onClick }) {
  const { useState, useEffect } = React;
  const [matured, setMatured] = useState(false);
  useEffect(() => {
    if (phase < 4 && !reducedOrSkipped) return;
    const t = setTimeout(() => setMatured(true), reducedOrSkipped ? 100 : 400);
    return () => clearTimeout(t);
  }, [phase, reducedOrSkipped]);

  const [hov, setHov] = React.useState(false);
  const bg = matured ? (hov ? T.acc7 : T.acc6) : T.paper3;
  const color = matured ? T.paper0 : T.ink5;

  return (
    <button
      onClick={onClick}
      onMouseEnter={() => setHov(true)}
      onMouseLeave={() => setHov(false)}
      style={{
        fontFamily: T.sans, fontWeight: 600, fontSize: '1rem',
        padding: '0.75rem 2rem', border: 'none', borderRadius: 6,
        cursor: 'pointer', minHeight: 44,
        background: bg, color,
        boxShadow: matured ? 'var(--atlas-shadow-sm)' : 'none',
        transition: 'background 400ms ease-out, color 400ms ease-out, box-shadow 400ms ease-out',
      }}
    >
      Entrar al panel del docente →
    </button>
  );
}

function PeerGraph({ peer, index, reducedMotion }) {
  // Row: 0=back, 1=mid, 2=front. Depth-based opacity, scale, blur.
  const depth = peer.row;
  const depthConf = [
    { scale: 0.18, opacity: 0.35, blur: 1.5 },
    { scale: 0.24, opacity: 0.55, blur: 0.5 },
    { scale: 0.30, opacity: 0.8,  blur: 0   },
  ][depth];

  // Stagger entry: 40ms × index
  const delay = reducedMotion ? 0 : 40 * index;

  return (
    <div
      style={{
        position: 'absolute',
        top: `${peer.yPct}%`, left: `${peer.xPct}%`,
        transform: `translate(-50%, -50%)`,
        width: 200, height: 140,
        marginLeft: -100, marginTop: -70,
        filter: depthConf.blur ? `blur(${depthConf.blur}px)` : 'none',
        zIndex: 5 + depth, // front row on top of back rows, still behind Mariana (z 20)
        opacity: 0,
        animation: reducedMotion
          ? `fadeIn 600ms ease-out ${delay}ms forwards`
          : `atlas-zoom-peer-in 500ms cubic-bezier(.2,.7,.3,1) ${delay}ms forwards`,
        // CSS vars for keyframe end-state
        ['--peer-scale']: depthConf.scale,
        ['--peer-scale-from']: depthConf.scale * 0.9,
        ['--peer-opacity']: depthConf.opacity,
        pointerEvents: 'none',
      }}
    >
      <PeerGraphSVG peer={peer} />
    </div>
  );
}

// Lightweight mini-SVG: 5 nodes + 4 edges, deterministic from peer.id
function PeerGraphSVG({ peer }) {
  // Varied fill palette so the cohort reads as heterogenous.
  // peer.tone determines color spread: 'cold'=at-risk, 'warm'=advanced, 'mixed'=middle.
  const palettes = {
    cold: [
      'hsl(var(--atlas-cool-700))',
      'hsl(var(--atlas-cool-500))',
      'hsl(var(--atlas-cool-400))',
      T.paper3,
      T.paper2,
    ],
    warm: [
      'hsl(var(--atlas-warm-400))',
      'hsl(var(--atlas-warm-500))',
      'hsl(var(--atlas-warm-200))',
      'hsl(var(--atlas-accent-500))',
      T.paper2,
    ],
    mixed: [
      'hsl(var(--atlas-warm-400))',
      'hsl(var(--atlas-cool-400))',
      T.paper2,
      'hsl(var(--atlas-accent-100))',
      T.paper3,
    ],
    accent: [
      'hsl(var(--atlas-accent-500))',
      'hsl(var(--atlas-warm-400))',
      'hsl(var(--atlas-accent-100))',
      T.paper2,
      T.paper3,
    ],
  };
  const fills = palettes[peer.tone] || palettes.mixed;

  // Deterministic layout seeded by peer.seed. 5 positions on a 200x140 viewbox.
  const positions = peer.positions;
  const edges = peer.edges;

  return (
    <svg viewBox="0 0 200 140" width="100%" height="100%" style={{ overflow: 'visible' }}>
      {edges.map((e, i) => {
        const a = positions[e[0]], b = positions[e[1]];
        return (
          <line
            key={i}
            x1={a[0]} y1={a[1]} x2={b[0]} y2={b[1]}
            stroke={i === 0 ? 'hsl(var(--atlas-warm-400))' : 'hsl(var(--atlas-cool-400))'}
            strokeWidth={i === 0 ? 1.6 : 1}
            opacity={0.7}
          />
        );
      })}
      {positions.map((pos, i) => (
        <circle
          key={i}
          cx={pos[0]} cy={pos[1]} r={9}
          fill={fills[i % fills.length]}
          stroke={T.paper4}
          strokeWidth={0.8}
        />
      ))}
    </svg>
  );
}

// ── Peer layout generator — deterministic, scattered around Mariana's offset ───
function buildPeers(count) {
  // Mariana's pulled-back position sits near right-center. Distribute peers around
  // an ellipse centered around (40%, 50%) — slightly left of Mariana so the cohort
  // reads as "behind and around her". 3 depth rows × counts split roughly: 8/7/4.
  const rowSplit = [8, 7, 4]; // back, mid, front = 19 total
  const peers = [];
  let idx = 0;
  const tones = ['cold', 'mixed', 'warm', 'mixed', 'accent', 'warm', 'cold', 'mixed'];

  // Base center of the cohort cluster (in viewport %)
  const cx = 40, cy = 52;

  for (let row = 0; row < 3; row++) {
    const n = rowSplit[row];
    // ellipse radii widen with front row (closer = more spread in screen space)
    const rx = 30 + row * 8;
    const ry = 22 + row * 6;
    for (let i = 0; i < n; i++) {
      // Deterministic angle with jitter from index
      const t = (i / n) * Math.PI * 2 + (row * 0.6);
      // Pseudo-jitter via sin of compound index
      const jitterX = Math.sin(idx * 12.9898 + row * 78.233) * 4;
      const jitterY = Math.cos(idx * 7.1234  + row * 3.456 ) * 3;
      let xPct = cx + Math.cos(t) * rx + jitterX;
      let yPct = cy + Math.sin(t) * ry * 0.85 + jitterY;

      // Clamp so peers stay inside the viewport
      xPct = Math.max(6, Math.min(94, xPct));
      yPct = Math.max(14, Math.min(86, yPct));

      const seed = idx * 2654435761 >>> 0;
      peers.push({
        id: `peer-${idx}`,
        row,
        xPct, yPct,
        tone: tones[idx % tones.length],
        seed,
        positions: buildPositions(seed),
        edges: buildEdges(),
      });
      idx++;
      if (idx >= count) return peers;
    }
  }
  return peers;
}

function buildPositions(seed) {
  // Deterministic-ish pseudo-random based on seed — 5 nodes in a 200x140 viewBox
  function r(s) {
    const x = Math.sin(s) * 43758.5453;
    return x - Math.floor(x);
  }
  // Anchor layout loosely resembling Mariana's graph (spread-out cluster)
  const base = [
    [40, 40], [110, 28], [150, 75], [75, 95], [170, 115],
  ];
  return base.map((p, i) => {
    const jx = (r(seed + i * 13) - 0.5) * 20;
    const jy = (r(seed + i * 29) - 0.5) * 14;
    return [p[0] + jx, p[1] + jy];
  });
}

function buildEdges() {
  // 4 edges connecting the 5 nodes — static topology reads like a tiny graph
  return [[0, 1], [1, 2], [0, 3], [2, 4]];
}

Object.assign(window, { S09Zoom });
