// Shared UI primitives for the promo video.
// Reuses the design language of aitutors.me homepage:
//   warm paper, navy ink, spark-green accent, serif + mono + sans.

const palette = {
  paper:      'oklch(0.965 0.012 78)',
  paper2:     'oklch(0.945 0.018 90)',
  card:       'oklch(0.992 0.006 85)',
  ink:        'oklch(0.24 0.060 254)',
  inkDeep:    'oklch(0.21 0.080 254)',
  inkSoft:    'oklch(0.42 0.040 250)',
  muted:      'oklch(0.55 0.022 245)',
  quiet:      'oklch(0.68 0.014 240)',
  hair:       'oklch(0.87 0.020 230)',
  hairStrong: 'oklch(0.78 0.022 235)',
  accent:     'oklch(0.55 0.135 150)',
  accentDeep: 'oklch(0.42 0.135 150)',
  accentSoft: 'oklch(0.92 0.050 150)',
  go:         'oklch(0.58 0.115 145)',
  amber:      'oklch(0.72 0.155 75)',
  stop:       'oklch(0.58 0.175 28)',
  onDark:     'oklch(0.96 0.015 100)',
  onDark2:    'oklch(0.80 0.030 200)',
  cambridge:  'oklch(0.45 0.155 25)',
};

const fonts = {
  serif: '"Source Serif 4", "Iowan Old Style", Georgia, serif',
  sans:  '"Geist", "Inter", system-ui, sans-serif',
  mono:  '"Geist Mono", "JetBrains Mono", ui-monospace, monospace',
};

// ─────────────────────────────────────────────────────────────────────────────
// SparkGlyph — the 8-point star used in the brand wordmark.
function SparkGlyph({ size = 12, color = palette.accent, spin = 0 }) {
  return (
    <svg
      viewBox="-12 -12 24 24"
      width={size}
      height={size}
      style={{ transform: `rotate(${spin}deg)`, display: 'inline-block', verticalAlign: 'middle' }}
    >
      <path
        d="M0 -11 L2.2 -2.5 L11 0 L2.2 2.5 L0 11 L-2.2 2.5 L-11 0 L-2.2 -2.5 Z"
        fill={color}
      />
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// BrandMark — animated "aitutors★me" wordmark.
function BrandMark({ size = 80, sparkBeat = true }) {
  const t = useTime();
  const sparkScale = sparkBeat
    ? 1 + 0.12 * Math.sin(t * 2.4) + 0.04 * Math.sin(t * 5.1)
    : 1;
  const sparkSpin = sparkBeat ? Math.sin(t * 1.1) * 14 : 0;
  return (
    <div style={{
      fontFamily: fonts.serif,
      fontSize: size,
      fontWeight: 500,
      color: palette.inkDeep,
      letterSpacing: '-0.022em',
      display: 'inline-flex',
      alignItems: 'center',
      gap: 0,
      lineHeight: 1,
    }}>
      <span>aitutors</span>
      <span style={{
        display: 'inline-block',
        width: size * 0.55,
        height: size * 0.55,
        margin: `0 ${size * 0.04}px`,
        transform: `scale(${sparkScale}) rotate(${sparkSpin}deg)`,
        transformOrigin: 'center',
      }}>
        <SparkGlyph size={size * 0.55} color={palette.accent} />
      </span>
      <span>me</span>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// ChatHeader — the warm header strip that says "PROFESSOR PI · MATHS · 18 MIN".
function ChatHeader({ name = 'PROFESSOR PI', subject = 'MATHS', meta = '18 MIN' }) {
  return (
    <div style={{
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'space-between',
      padding: '20px 28px',
      borderBottom: `1px solid ${palette.hair}`,
      background: palette.paper2,
      fontFamily: fonts.mono,
      fontSize: 16,
      letterSpacing: '0.08em',
      color: palette.muted,
      textTransform: 'uppercase',
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
        <span style={{
          width: 10, height: 10, borderRadius: '50%',
          background: palette.go,
          boxShadow: `0 0 0 4px ${palette.go.replace('oklch', 'oklch').replace(')', ' / 0.18)')}`,
        }} />
        <span>{name}</span>
        <span style={{ opacity: 0.5 }}>·</span>
        <span>{subject}</span>
        <span style={{ opacity: 0.5 }}>·</span>
        <span>{meta}</span>
      </div>
      <div style={{ display: 'flex', gap: 8 }}>
        <i style={{ width: 8, height: 8, borderRadius: '50%', background: palette.hairStrong, display: 'inline-block' }} />
        <i style={{ width: 8, height: 8, borderRadius: '50%', background: palette.hairStrong, display: 'inline-block' }} />
        <i style={{ width: 8, height: 8, borderRadius: '50%', background: palette.hairStrong, display: 'inline-block' }} />
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// ChatBubble — a single styled message (tutor / kid).
// `appearAt` = seconds into the scene when bubble fades in.
function ChatBubble({
  who = 'tutor', name = 'PROFESSOR PI', avatar = 'Pi',
  appearAt = 0, dwell = Infinity, children, exitAt,
  width = 'auto', alignRight,
}) {
  const { localTime } = useSprite();
  const isKid = who === 'kid';
  const t0 = appearAt;
  const t1 = exitAt != null ? exitAt : t0 + dwell;
  let opacity = 0, ty = 14;
  if (localTime >= t0) {
    const e = Math.min(1, (localTime - t0) / 0.45);
    const eased = Easing.easeOutBack(e);
    opacity = e;
    ty = (1 - eased) * 14;
  }
  if (localTime > t1) {
    const e = Math.min(1, (localTime - t1) / 0.4);
    opacity = 1 - e;
  }
  if (opacity <= 0) return null;

  const containerStyle = {
    display: 'grid',
    gridTemplateColumns: isKid || alignRight ? '1fr 44px' : '44px 1fr',
    gap: 14,
    alignItems: 'flex-end',
    justifyContent: isKid || alignRight ? 'flex-end' : 'flex-start',
    width: '100%',
    opacity,
    transform: `translateY(${ty}px)`,
    transition: 'none',
  };

  const avatarEl = (
    <div style={{
      width: 44, height: 44, borderRadius: '50%',
      display: 'grid', placeItems: 'center',
      fontFamily: fonts.serif,
      fontStyle: 'italic',
      fontSize: 18,
      color: isKid ? palette.inkDeep : palette.accentDeep,
      background: isKid ? palette.paper2 : palette.accentSoft,
      border: `1px solid ${isKid ? palette.hair : 'oklch(0.55 0.135 150 / 0.35)'}`,
      flex: 'none',
      gridColumn: isKid || alignRight ? '2' : '1',
    }}>
      {avatar}
    </div>
  );

  const bubbleEl = (
    <div style={{
      gridColumn: isKid || alignRight ? '1' : '2',
      background: isKid ? palette.inkDeep : palette.paper2,
      color: isKid ? palette.onDark : palette.inkDeep,
      padding: '20px 26px',
      borderRadius: 18,
      borderBottomRightRadius: isKid ? 6 : 18,
      borderBottomLeftRadius: isKid ? 18 : 6,
      fontFamily: fonts.sans,
      fontSize: 26,
      lineHeight: 1.45,
      maxWidth: width === 'auto' ? '85%' : width,
      justifySelf: isKid || alignRight ? 'end' : 'start',
    }}>
      <div style={{
        fontFamily: fonts.mono,
        fontSize: 13,
        letterSpacing: '0.08em',
        color: isKid ? palette.onDark2 : palette.accentDeep,
        textTransform: 'uppercase',
        marginBottom: 8,
      }}>
        {name}
      </div>
      <div>{children}</div>
    </div>
  );

  return (
    <div style={containerStyle}>
      {avatarEl}
      {bubbleEl}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// ChatFrame — the rounded card with header, body, optional footer.
function ChatFrame({ children, header, footer, width = 1080, padBody = 28 }) {
  return (
    <div style={{
      width,
      background: palette.card,
      border: `1px solid ${palette.hair}`,
      borderRadius: 20,
      overflow: 'hidden',
      boxShadow: '0 1px 0 ' + palette.hair + ', 0 40px 80px -40px rgba(0,0,0,0.2)',
      display: 'flex', flexDirection: 'column',
    }}>
      {header}
      <div style={{
        padding: padBody,
        display: 'flex', flexDirection: 'column',
        gap: 18,
        minHeight: 380,
      }}>
        {children}
      </div>
      {footer}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// InlineCode — for ${3(x+4)}-style math chips inside messages.
function InlineCode({ children, dark }) {
  return (
    <code style={{
      fontFamily: fonts.mono,
      fontSize: '0.86em',
      background: dark ? 'oklch(0.30 0.020 70)' : 'oklch(0.91 0.020 80)',
      color: dark ? palette.onDark : palette.inkDeep,
      padding: '2px 8px',
      borderRadius: 6,
      margin: '0 2px',
    }}>{children}</code>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// CaptionBar — persistent subtitle band at bottom of canvas.
function CaptionBar({ scenes }) {
  const t = useTime();
  // Find which scene we're in
  const active = scenes.find(s => t >= s.start && t < s.end);
  const text = active?.caption || '';

  const fadeIn = active ? Math.min(1, (t - active.start) / 0.35) : 0;
  const fadeOut = active ? Math.max(0, 1 - Math.min(1, (active.end - t) / 0.4)) : 0;
  const opacity = active ? Math.min(fadeIn, 1 - fadeOut) : 0;

  return (
    <div style={{
      position: 'absolute',
      bottom: 48,
      left: 0, right: 0,
      display: 'flex', justifyContent: 'center',
      pointerEvents: 'none',
      zIndex: 50,
    }}>
      <div style={{
        opacity,
        transition: 'opacity 200ms',
        background: 'oklch(0.18 0.05 254 / 0.92)',
        color: palette.onDark,
        fontFamily: fonts.sans,
        fontWeight: 400,
        fontSize: 28,
        letterSpacing: '-0.005em',
        padding: '14px 28px',
        borderRadius: 10,
        maxWidth: 1100,
        textAlign: 'center',
        backdropFilter: 'blur(6px)',
        boxShadow: '0 8px 32px -12px rgba(0,0,0,0.4)',
        lineHeight: 1.35,
      }}>
        {text}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// SceneNumber — small "§ 03 / 08" eyebrow shown top-left during a scene.
function SceneNumber({ idx, total = 8, label }) {
  const { localTime, duration } = useSprite();
  const fadeIn = Math.min(1, localTime / 0.6);
  const fadeOut = Math.max(0, 1 - Math.min(1, (duration - localTime) / 0.5));
  const opacity = Math.min(fadeIn, 1 - fadeOut);
  return (
    <div style={{
      position: 'absolute',
      top: 56, left: 80,
      opacity,
      fontFamily: fonts.mono,
      fontSize: 14,
      letterSpacing: '0.1em',
      textTransform: 'uppercase',
      color: palette.muted,
      display: 'flex', alignItems: 'center', gap: 14,
      whiteSpace: 'nowrap',
      zIndex: 40,
    }}>
      <span style={{ color: palette.accent }}>§</span>
      <span>{String(idx).padStart(2, '0')} / {String(total).padStart(2, '0')}</span>
      <span style={{ width: 80, height: 1, background: palette.hair }} />
      <span>{label}</span>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// PaperBackground — top-frame chrome (timestamp + brand mark) for non-CTA scenes
function PaperChrome({ time }) {
  return (
    <div style={{
      position: 'absolute',
      top: 56, right: 80,
      fontFamily: fonts.mono,
      fontSize: 13,
      letterSpacing: '0.08em',
      textTransform: 'uppercase',
      color: palette.muted,
      display: 'flex', alignItems: 'center', gap: 14,
      whiteSpace: 'nowrap',
      zIndex: 40,
    }}>
      <span>{time}</span>
      <span style={{ width: 1, height: 14, background: palette.hair }} />
      <span style={{ color: palette.inkDeep, fontFamily: fonts.serif, fontStyle: 'italic', textTransform: 'none', fontSize: 16, letterSpacing: '-0.01em' }}>
        aitutors<SparkGlyph size={9} color={palette.accent} />me
      </span>
    </div>
  );
}

Object.assign(window, {
  palette, fonts,
  SparkGlyph, BrandMark,
  ChatHeader, ChatBubble, ChatFrame, InlineCode,
  CaptionBar, SceneNumber, PaperChrome,
});
