// Cinematic primitives for the Ventrin promo.
// Cursor, toast, stat counter, camera frame, vignette, key hint, etc.

// ── Animated cursor ────────────────────────────────────────────────────────
// path = [{x, y, at}] keyframes in absolute stage coords + scene-local seconds.
// Optional click events: clicks = [{at, decay}]
function Cursor({ path, clicks = [], color = '#1a1d21' }) {
  const { localTime } = useSprite();

  // Position via interpolate over keyframes
  let x = path[0].x, y = path[0].y;
  for (let i = 0; i < path.length - 1; i++) {
    const a = path[i], b = path[i + 1];
    if (localTime >= a.at && localTime <= b.at) {
      const span = b.at - a.at;
      const t = span <= 0 ? 1 : (localTime - a.at) / span;
      const eased = Easing.easeInOutCubic(t);
      x = a.x + (b.x - a.x) * eased;
      y = a.y + (b.y - a.y) * eased;
      break;
    }
    if (localTime > b.at) { x = b.x; y = b.y; }
  }

  // Click pulse (a quick ring that expands and fades)
  const activeClick = clicks.find(c => localTime >= c.at && localTime < c.at + (c.decay || 0.6));

  return (
    <>
      {activeClick && (() => {
        const cp = (localTime - activeClick.at) / (activeClick.decay || 0.6);
        return (
          <div style={{
            position: 'absolute',
            left: x, top: y,
            width: 8 + cp * 60, height: 8 + cp * 60,
            marginLeft: -(8 + cp * 60) / 2,
            marginTop: -(8 + cp * 60) / 2,
            border: `2px solid ${color}`,
            borderRadius: '50%',
            opacity: 1 - cp,
            pointerEvents: 'none',
            zIndex: 99,
          }}/>
        );
      })()}
      <svg
        viewBox="0 0 24 24"
        width="28" height="28"
        style={{
          position: 'absolute',
          left: x, top: y,
          marginLeft: -3, marginTop: -3,
          filter: 'drop-shadow(0 2px 4px rgba(0,0,0,0.25))',
          pointerEvents: 'none',
          zIndex: 100,
        }}
      >
        <path d="M5.5 3.2 L5.5 18.6 L9.4 14.9 L11.8 20.3 L14 19.4 L11.6 14 L17 13.6 Z"
          fill={color} stroke="#fff" strokeWidth="1.4" strokeLinejoin="round"/>
      </svg>
    </>
  );
}

// ── Notification toast ─────────────────────────────────────────────────────
// Slides in from the right, holds, slides out.
function Toast({
  start, end, x, y,
  width = 360,
  icon = 'alert',
  title, subtitle, source,
  variant = 'alert', // 'alert' | 'slack' | 'compliance' | 'system'
}) {
  const { localTime } = useSprite();
  if (localTime < start || localTime > end + 0.4) return null;
  const inP = clamp((localTime - start) / 0.4, 0, 1);
  const outP = clamp((localTime - end) / 0.4, 0, 1);
  const eIn = Easing.easeOutBack(inP);
  const opacity = clamp(inP * 2, 0, 1) * (1 - outP);
  const tx = (1 - eIn) * 40 - outP * 12;

  const palette = {
    alert:      { bg: '#1a1d21', ink: '#f3f1ec', accent: '#a86e1a', tint: '#f6ead4' },
    slack:      { bg: '#fff',    ink: '#1a1d21', accent: '#4870a8', tint: '#dce5ef' },
    compliance: { bg: '#1a1d21', ink: '#f3f1ec', accent: '#8a2f2f', tint: '#f1dcdc' },
    system:     { bg: '#fff',    ink: '#1a1d21', accent: '#2c4a6a', tint: '#dce5ef' },
  }[variant];

  return (
    <div style={{
      position: 'absolute',
      left: x, top: y, width,
      transform: `translateX(${tx}px)`,
      opacity,
      background: palette.bg,
      color: palette.ink,
      border: `1px solid ${variant === 'slack' || variant === 'system' ? '#d8d3c8' : '#20262d'}`,
      borderRadius: 10,
      padding: '14px 16px',
      display: 'flex', gap: 12,
      alignItems: 'flex-start',
      boxShadow: '0 20px 40px -16px rgba(0,0,0,0.35), 0 4px 12px -4px rgba(0,0,0,0.18)',
      fontFamily: V.sans,
      zIndex: 50,
    }}>
      <span style={{
        flex: '0 0 32px',
        width: 32, height: 32, borderRadius: 6,
        background: palette.tint, color: palette.accent,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        fontWeight: 700,
      }}>
        {icon === 'slack' ? '#' : icon === 'shield' ? '⛨' : '!'}
      </span>
      <div style={{ flex: 1, minWidth: 0 }}>
        {source && (
          <div style={{
            fontSize: 11, fontWeight: 600, letterSpacing: '0.16em',
            textTransform: 'uppercase', color: palette.accent, marginBottom: 4,
          }}>{source}</div>
        )}
        <div style={{ fontSize: 15, fontWeight: 600, lineHeight: 1.35 }}>{title}</div>
        {subtitle && (
          <div style={{
            fontSize: 13, color: variant === 'slack' || variant === 'system' ? '#5a6069' : '#a7acb4',
            marginTop: 4, lineHeight: 1.4,
          }}>{subtitle}</div>
        )}
      </div>
    </div>
  );
}

// ── Stat counter ───────────────────────────────────────────────────────────
// Counts from `from` to `to` between scene-local times `start` and `end`.
function StatCounter({ from = 0, to = 100, start = 0, end = 1, prefix = '', suffix = '', format }) {
  const { localTime } = useSprite();
  const p = clamp((localTime - start) / Math.max(0.001, end - start), 0, 1);
  const eased = Easing.easeOutCubic(p);
  const value = from + (to - from) * eased;
  const display = format ? format(value) : Math.round(value).toLocaleString();
  return <span>{prefix}{display}{suffix}</span>;
}

// ── Camera frame ───────────────────────────────────────────────────────────
// Wraps children in a transformable container that pans/zooms over time.
// keyframes = [{at, x, y, scale}] in scene-local seconds
function Camera({ keyframes, origin = '50% 50%', children }) {
  const { localTime } = useSprite();
  let x = keyframes[0].x ?? 0;
  let y = keyframes[0].y ?? 0;
  let s = keyframes[0].scale ?? 1;
  for (let i = 0; i < keyframes.length - 1; i++) {
    const a = keyframes[i], b = keyframes[i + 1];
    if (localTime >= a.at && localTime <= b.at) {
      const span = b.at - a.at;
      const t = span <= 0 ? 1 : (localTime - a.at) / span;
      const eased = Easing.easeInOutCubic(t);
      x = (a.x ?? 0) + ((b.x ?? 0) - (a.x ?? 0)) * eased;
      y = (a.y ?? 0) + ((b.y ?? 0) - (a.y ?? 0)) * eased;
      s = (a.scale ?? 1) + ((b.scale ?? 1) - (a.scale ?? 1)) * eased;
      break;
    }
    if (localTime > b.at) { x = b.x ?? 0; y = b.y ?? 0; s = b.scale ?? 1; }
  }
  return (
    <div style={{
      position: 'absolute', inset: 0,
      transform: `translate(${x}px, ${y}px) scale(${s})`,
      transformOrigin: origin,
      willChange: 'transform',
    }}>{children}</div>
  );
}

// ── Letterbox bars for cinematic moments ───────────────────────────────────
function Letterbox({ visible = true, height = 96, color = '#0c1014' }) {
  const { localTime, duration } = useSprite();
  // Auto-fade based on visibility flag and sprite range
  const p = visible ? clamp(localTime / 0.4, 0, 1) : 0;
  return (
    <>
      <div style={{
        position: 'absolute', top: 0, left: 0, right: 0,
        height, background: color,
        transform: `translateY(${(1 - p) * -height}px)`,
        zIndex: 90,
      }}/>
      <div style={{
        position: 'absolute', bottom: 0, left: 0, right: 0,
        height, background: color,
        transform: `translateY(${(1 - p) * height}px)`,
        zIndex: 90,
      }}/>
    </>
  );
}

// ── Subtle scanline overlay ────────────────────────────────────────────────
function Vignette({ strength = 0.35 }) {
  return (
    <div style={{
      position: 'absolute', inset: 0,
      background: `radial-gradient(ellipse at center, transparent 55%, rgba(12,16,20,${strength}) 100%)`,
      pointerEvents: 'none',
      zIndex: 95,
    }}/>
  );
}

// ── Pulse ring at a point (good for "detected!" beats) ─────────────────────
function PulseRing({ x, y, start, color = '#8a2f2f', count = 2, period = 0.6, size = 60 }) {
  const { localTime } = useSprite();
  const dots = [];
  for (let i = 0; i < count; i++) {
    const localStart = start + i * (period / count);
    const p = clamp((localTime - localStart) / period, 0, 1);
    if (p <= 0 || p >= 1) continue;
    const r = size * p;
    dots.push(
      <div key={i} style={{
        position: 'absolute',
        left: x - r, top: y - r,
        width: r * 2, height: r * 2,
        border: `2px solid ${color}`,
        borderRadius: '50%',
        opacity: 1 - p,
        pointerEvents: 'none',
      }}/>
    );
  }
  return <>{dots}</>;
}

// ── Caption / lower-third title card ──────────────────────────────────────
function Caption({ start, end, text, x = 160, y, color = '#1a1d21' }) {
  const { localTime } = useSprite();
  if (localTime < start || localTime > end + 0.3) return null;
  const inP = clamp((localTime - start) / 0.35, 0, 1);
  const outP = clamp((localTime - end) / 0.3, 0, 1);
  const opacity = inP * (1 - outP);
  return (
    <div style={{
      position: 'absolute',
      left: x, top: y,
      opacity,
      transform: `translateY(${(1 - inP) * 12}px)`,
      fontFamily: V.serif, fontWeight: 500,
      fontSize: 48, lineHeight: 1.15, letterSpacing: '-0.02em',
      color, maxWidth: 900,
    }}>{text}</div>
  );
}

// ── Keystroke hint ────────────────────────────────────────────────────────
function KeyHint({ keys }) {
  return (
    <div style={{
      display: 'inline-flex', gap: 6, alignItems: 'center',
      fontFamily: V.mono, fontSize: 13, color: V.ink3,
    }}>
      {keys.map((k, i) => (
        <React.Fragment key={i}>
          {i > 0 && <span style={{ color: V.ink4 }}>+</span>}
          <span style={{
            background: V.bg0, border: `1px solid ${V.line}`,
            borderRadius: 4, padding: '3px 8px',
            color: V.ink2, fontWeight: 500,
            boxShadow: `0 1px 0 ${V.line}`,
          }}>{k}</span>
        </React.Fragment>
      ))}
    </div>
  );
}

Object.assign(window, {
  Cursor, Toast, StatCounter, Camera, Letterbox, Vignette, PulseRing, Caption, KeyHint,
});
