// scene4_matrix.jsx — Matrix reveals: performance × compa-ratio grid materializes, dots flow into cells

// Matrix cell values (performance × compa band). France anchor 3.3%.
const MATRIX_ROWS = ['High', 'Meets', 'Low'];
const MATRIX_COLS = [
  { label: 'Below', sub: '<0.85', },
  { label: 'Low',   sub: '0.85–0.95' },
  { label: 'On',    sub: '0.95–1.05' },
  { label: 'High',  sub: '1.05–1.15' },
  { label: 'Above', sub: '>1.15' },
];

// recommended_pct = 3.3 × perf_factor × compa_factor
// perf:  High 1.35, Meets 0.85, Low 0.40
// compa: <0.85 1.25, 0.85–0.95 1.10, 0.95–1.05 1.00, 1.05–1.15 0.85, >1.15 0.40
const MATRIX = (() => {
  const perf = { High: 1.35, Meets: 0.85, Low: 0.40 };
  const compa = [1.25, 1.10, 1.00, 0.85, 0.40];
  const anchor = 3.3;
  return MATRIX_ROWS.map(tier =>
    compa.map(cf => +(anchor * perf[tier] * cf).toFixed(2))
  );
})();

function heatColor(v) {
  // v in ~0..5.5+. Map to ultraviolet-tint intensity
  const t = clamp(v / 6.0, 0, 1);
  // Interpolate between accent-tint and accent
  const lerp = (a,b,t) => Math.round(a + (b-a)*t);
  const r1=243,g1=238,b1=249; // #f3eef9
  const r2=127,g2=53,b2=178;  // #7f35b2
  return `rgb(${lerp(r1,r2,t)},${lerp(g1,g2,t)},${lerp(b1,b2,t)})`;
}

function Scene4Matrix() {
  const { localTime, duration } = useSprite();

  // Beats ~12s
  //  0.0–1.0  title
  //  0.5–2.5  empty matrix draws in
  //  2.0–5.5  cells fill with % values sequentially
  //  5.0–8.5  dots flow in from left, land in their cells
  //  8.0–10.5 budget bar at bottom calibrates
  //  10.5–12  caption settles

  const titleP = clamp(localTime / 0.6, 0, 1);
  const gridP  = clamp((localTime - 0.5) / 1.4, 0, 1);
  const cellsP = clamp((localTime - 2.0) / 3.0, 0, 1);
  const dotsP  = clamp((localTime - 5.0) / 2.8, 0, 1);
  // After dots finish landing, the matrix grid fades to 20% so dots
  // read clearly on top. gridFadeP ramps 0 → 1 across the tail of dotsP.
  const gridFadeP = clamp((localTime - 7.2) / 0.9, 0, 1);
  const budgetP= clamp((localTime - 8.0) / 2.5, 0, 1);
  const enterP = clamp(localTime / 1.5, 0, 1);          // scene fade-in 0 → 1.5s
  const exitP  = clamp((localTime - 25.7) / 1.5, 0, 1); // scene fade-out 25.7 → 27.2s

  const W = 1920, H = 1080;
  const matrixLeft = 640, matrixTop = 200;
  const cellW = 190, cellH = 130;
  const matrixW = cellW * 5, matrixH = cellH * 3;

  return (
    <div style={{
      position: 'absolute', inset: 0,
      background: ASI_COLORS.canvas,
      overflow: 'hidden',
      opacity: enterP * (1 - exitP),
      transform: `scale(${1 + exitP * 0.08})`, // exit: zoom in
      filter: `brightness(${1 + exitP * 0.4})`,
    }}>
      {/* Title */}
      <div style={{
        position: 'absolute', top: 72, left: 96, width: 480,
        opacity: titleP,
      }}>
        <div style={{
          fontSize: 16, fontWeight: 600, letterSpacing: '0.06em',
          textTransform: 'uppercase', color: ASI_COLORS.accent,
          marginBottom: 12,
        }}>The new engine</div>
        <div style={{
          fontSize: 56, fontWeight: 600, letterSpacing: '-0.02em',
          color: ASI_COLORS.ink, lineHeight: 1.05,
        }}>
          Merit Matrix
        </div>
        <div style={{
          marginTop: 16, fontSize: 20, color: ASI_COLORS.inkSoft,
          lineHeight: 1.5,
        }}>
          Two axes: <strong style={{color:ASI_COLORS.ink}}>performance</strong> &times; <strong style={{color:ASI_COLORS.ink}}>compa-ratio</strong>.
          Each cell proposes a <strong style={{color:ASI_COLORS.ink}}>recommended %</strong> grounded in the
          country anchor rate and budget.
        </div>

        {/* Anchor chip */}
        <div style={{
          marginTop: 22, display: 'inline-flex', alignItems: 'center', gap: 8,
          background: '#fff', padding: '10px 14px', borderRadius: 10,
          boxShadow: '0 1px 3px rgba(0,0,0,0.04)',
          opacity: clamp((localTime - 1.0) / 0.5, 0, 1),
        }}>
          <span style={{ fontSize: 16, fontWeight: 600, letterSpacing: '0.04em',
                         textTransform:'uppercase', color: ASI_COLORS.inkMuted }}>
            FR · MKT_P50
          </span>
          <span style={{ fontSize: 22, fontWeight: 600, color: ASI_COLORS.accent,
                         fontVariantNumeric: 'tabular-nums' }}>3.30%</span>
          <span style={{ fontSize: 16, color: ASI_COLORS.inkSoft }}>country anchor</span>
        </div>
      </div>

      {/* Matrix */}
      <div style={{
        position: 'absolute', left: matrixLeft, top: matrixTop,
      }}>
        {/* Column headers */}
        <div style={{
          display: 'grid',
          gridTemplateColumns: `80px repeat(5, ${cellW}px)`,
          opacity: clamp(gridP * 1.4, 0, 1),
        }}>
          <div/>
          {MATRIX_COLS.map((c, i) => (
            <div key={i} style={{
              padding: '0 0 10px 0', textAlign: 'center',
            }}>
              <div style={{
                fontSize: 16, fontWeight: 600, letterSpacing: '0.04em',
                textTransform: 'uppercase', color: ASI_COLORS.inkMuted,
              }}>{c.label}</div>
              <div style={{
                fontSize: 16, color: ASI_COLORS.inkMuted, marginTop: 3,
                fontFamily: 'JetBrains Mono, monospace',
                fontVariantNumeric: 'tabular-nums',
              }}>{c.sub}</div>
            </div>
          ))}
        </div>

        {/* Rows */}
        {MATRIX_ROWS.map((tier, rIdx) => (
          <div key={tier} style={{
            display: 'grid',
            gridTemplateColumns: `80px repeat(5, ${cellW}px)`,
            gap: 6,
            marginBottom: 6,
          }}>
            {/* Row label */}
            <div style={{
              display: 'flex', alignItems: 'center', justifyContent: 'flex-end',
              gap: 8, paddingRight: 12,
              opacity: clamp(gridP * 1.4 - rIdx * 0.15, 0, 1),
            }}>
              <TierGlyph tier={tier} size={16}/>
              <span style={{
                fontSize: 20, fontWeight: 600, color: ASI_COLORS.ink,
              }}>{tier}</span>
            </div>

            {/* Cells */}
            {MATRIX[rIdx].map((v, cIdx) => {
              const cellOrder = rIdx * 5 + cIdx;
              const cellAppear = clamp(cellsP * 17 - cellOrder * 0.8, 0, 1);
              const fillAppear = clamp(cellsP * 17 - cellOrder * 0.8 - 0.3, 0, 1);
              const eased = Easing.easeOutCubic(cellAppear);
              const baseColor = v > 3.5 ? '#ffffff' : ASI_COLORS.accentDark;
              return (
                <div key={cIdx} style={{
                  height: cellH,
                  borderRadius: 10,
                  background: heatColor(v),   // original heat-map tint, unmodified
                  opacity: eased,
                  transform: `scale(${0.88 + 0.12 * eased})`,
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                  flexDirection: 'column', gap: 4,
                  position: 'relative',
                  overflow: 'hidden',
                }}>
                  {/* Flat light-purple wash — fades in as dots arrive so the
                      heat-map reads as a quiet, population-ready backdrop.
                      Using a simple overlay avoids color-mix() and channel math. */}
                  <div style={{
                    position: 'absolute', inset: 0,
                    background: 'rgba(225, 215, 242, 0.72)',
                    opacity: gridFadeP,
                    pointerEvents: 'none',
                  }}/>
                  <div style={{
                    fontSize: 30, fontWeight: 700,
                    color: baseColor,
                    fontVariantNumeric: 'tabular-nums',
                    letterSpacing: '-0.01em',
                    opacity: fillAppear * (1 - 0.55 * gridFadeP),
                    position: 'relative', // sit above the overlay
                  }}>{v.toFixed(2)}%</div>
                </div>
              );
            })}
          </div>
        ))}

        {/* Axis label below */}
        <div style={{
          textAlign: 'center', marginTop: 16,
          fontSize: 16, fontWeight: 600, letterSpacing: '0.04em',
          textTransform: 'uppercase', color: ASI_COLORS.inkMuted,
          opacity: gridP,
          paddingLeft: 80,
        }}>Compa-ratio band →</div>
      </div>

      {/* Dots flowing in (simulate population distributing to cells) */}
      <MatrixDots
        progress={dotsP}
        matrixLeft={matrixLeft}
        matrixTop={matrixTop}
        cellW={cellW}
        cellH={cellH}
      />

      {/* Budget calibration bar */}
      <BudgetBar
        progress={budgetP}
        left={640}
        top={850}
        width={950}
        opacity={clamp(budgetP * 2, 0, 1)}
      />
    </div>
  );
}

function MatrixDots({ progress, matrixLeft, matrixTop, cellW, cellH }) {
  // Generate ~70 employees that fly through the matrix and settle into cells.
  // Each dot follows a curved path that overshoots past its cell, then settles in.
  const dots = React.useMemo(() => {
    const rnd = SeededRandom(17);
    const out = [];
    // Distribution: more in Meets × middle bands
    const tiers = ['High','Meets','Meets','Meets','Meets','Low'];
    const cBias = [0,1,1,2,2,2,2,3,3,4];
    for (let i = 0; i < 72; i++) {
      const tier = tiers[Math.floor(rnd() * tiers.length)];
      const rIdx = tier === 'High' ? 0 : tier === 'Meets' ? 1 : 2;
      const cIdx = cBias[Math.floor(rnd() * cBias.length)];
      const cellX = matrixLeft + 80 + cIdx * cellW + cellW * 0.5;
      const cellY = matrixTop + 48 + rIdx * (cellH + 6) + cellH * 0.5;
      // Scatter tightly inside cell
      const dx = (rnd() - 0.5) * (cellW - 56);
      const dy = (rnd() - 0.5) * (cellH - 52);
      // Start far off-screen — top or left edge — so they fly dramatically
      const fromTop = rnd() > 0.5;
      const startX = fromTop ? (rnd() * 1920) : (-120 - rnd() * 200);
      const startY = fromTop ? (-120 - rnd() * 200) : (rnd() * 1080);
      // Mid-point control for curve (between start and target, slightly off-axis)
      const endX = cellX + dx;
      const endY = cellY + dy;
      const midX = (startX + endX) / 2 + (rnd() - 0.5) * 400;
      const midY = (startY + endY) / 2 + (rnd() - 0.5) * 260;
      out.push({
        id: i, tier, rIdx, cIdx,
        startX, startY, midX, midY, endX, endY,
        delay: rnd() * 1.1,
        sizeFinal: 11 + rnd() * 3, // dots stay at their original, small size
      });
    }
    return out;
  }, []);

  return (
    <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
      {dots.map(d => {
        const local = clamp((progress - d.delay * 0.35) / 0.75, 0, 1);
        const eased = Easing.easeInOutCubic(local);
        // Quadratic bezier: (1-t)² P0 + 2(1-t)t P1 + t² P2
        const t = eased;
        const omt = 1 - t;
        const x = omt*omt*d.startX + 2*omt*t*d.midX + t*t*d.endX;
        const y = omt*omt*d.startY + 2*omt*t*d.midY + t*t*d.endY;
        // Size: small in transit, grows as it lands (overshoot + settle)
        const sizeP = clamp((local - 0.65) / 0.35, 0, 1);
        const arrive = Easing.easeOutBack(sizeP);
        // Subtle breathing once the dot has arrived on the grid — reads as a
        // living population. Each dot has its own phase so the cluster shimmers
        // instead of pulsing in lockstep.
        const landed = sizeP >= 1 ? 1 : 0;
        const pulseAmp   = 0.08 * landed;
        const pulsePhase = (d.id * 0.37) % (Math.PI * 2);
        const pulse = 1 + pulseAmp * Math.sin(progress * 6.0 + pulsePhase);
        const size = (8 + (d.sizeFinal - 8) * arrive) * pulse;
        const opacity = clamp(local * 3, 0, 1);
        const glow = sizeP > 0.1 ? sizeP : 0;
        return (
          <div key={d.id} style={{
            position: 'absolute', left: x, top: y,
            transform: `translate(-50%,-50%) scale(${(0.6 + 0.4 * arrive) * pulse})`,
            opacity,
            filter: glow > 0 ? `drop-shadow(0 0 ${6 * glow}px rgba(127,53,178,${0.4 * glow}))` : 'none',
          }}>
            <TierGlyph tier={d.tier} size={size}/>
          </div>
        );
      })}
    </div>
  );
}

function BudgetBar({ progress, left, top, width, opacity }) {
  // modeled spend animates toward target (3.30%)
  // spend starts overshooting at 3.46% then scales down
  const overshoot = 3.46;
  const target = 3.30;
  const p = progress;
  // 0→0.5 fill to overshoot, 0.5→1 scale back to target
  let value;
  if (p < 0.5) value = 3.30 * (p / 0.5) + (overshoot - 3.30) * Easing.easeOutCubic(clamp(p/0.5,0,1));
  else value = overshoot - (overshoot - target) * Easing.easeInOutCubic(clamp((p-0.5)/0.5, 0, 1));

  // Map to bar width: 0..5% range
  const barMax = 5;
  const targetX = (target / barMax) * width;
  const valueX  = (clamp(value, 0, barMax) / barMax) * width;

  return (
    <div style={{
      position: 'absolute', left, top, width,
      opacity,
    }}>
      <div style={{
        display: 'flex', alignItems: 'baseline', gap: 12, marginBottom: 12,
      }}>
        <span style={{
          fontSize: 16, fontWeight: 600, letterSpacing: '0.04em',
          textTransform: 'uppercase', color: ASI_COLORS.inkMuted,
        }}>Budget calibration · France</span>
        <span style={{ flex: 1 }}/>
        <span style={{
          fontSize: 20, color: ASI_COLORS.inkSoft,
        }}>Target <strong style={{color: ASI_COLORS.ink, fontVariantNumeric:'tabular-nums'}}>{target.toFixed(2)}%</strong></span>
        <span style={{
          fontSize: 20, color: ASI_COLORS.inkSoft,
        }}>Modeled <strong style={{
          color: Math.abs(value - target) < 0.05 ? ASI_COLORS.safe : ASI_COLORS.warn,
          fontVariantNumeric:'tabular-nums',
        }}>{value.toFixed(2)}%</strong></span>
      </div>

      {/* Bar */}
      <div style={{
        position: 'relative', height: 28, borderRadius: 8,
        background: ASI_COLORS.paper,
        overflow: 'hidden',
      }}>
        {/* fill */}
        <div style={{
          position: 'absolute', left: 0, top: 0, bottom: 0,
          width: valueX,
          background: Math.abs(value - target) < 0.05
            ? `linear-gradient(to right, ${ASI_COLORS.accent}, ${ASI_COLORS.accent})`
            : `linear-gradient(to right, ${ASI_COLORS.accent}, ${ASI_COLORS.warn})`,
          transition: 'background 200ms',
        }}/>
        {/* target line */}
        <div style={{
          position: 'absolute', left: targetX - 1, top: -4, bottom: -4,
          width: 2, background: ASI_COLORS.ink,
        }}/>
        <div style={{
          position: 'absolute', left: targetX + 6, top: -22,
          fontSize: 16, fontWeight: 600, color: ASI_COLORS.ink,
          fontVariantNumeric: 'tabular-nums',
        }}>{target.toFixed(2)}%</div>
      </div>

      <div style={{
        marginTop: 10, fontSize: 20, color: ASI_COLORS.inkSoft,
        opacity: clamp((progress - 0.5) / 0.3, 0, 1),
      }}>
        Scale factor <strong style={{
          fontFamily: 'JetBrains Mono, monospace', color: ASI_COLORS.accent,
        }}>{(target/value).toFixed(3)}×</strong> applied automatically · matrix stays within budget.
      </div>
    </div>
  );
}

Object.assign(window, { Scene4Matrix, MATRIX, MATRIX_ROWS, MATRIX_COLS });
