// shared/primitives.jsx
// Shared layout primitives, motion utilities, and chrome components.
// Reads DECK_CONFIG from window for brand-specific values.
// Assigned to window — available to all deck slides.jsx files.

const TYPE_SCALE = {
  display: 168,
  hero: 112,
  title: 76,
  subtitle: 48,
  lead: 38,
  body: 30,
  small: 22,
  micro: 16,
};

const SPACING = {
  paddingTop: 88,
  paddingBottom: 80,
  paddingX: 96,
  titleGap: 48,
};

const FONT_SANS = `'Inter Tight', system-ui, sans-serif`;
const FONT_MONO = `'Space Mono', ui-monospace, monospace`;

function darkDeckStyle() {
  const cfg = window.DECK_CONFIG || {};
  const imgUrl = cfg.bgImage || 'assets/img/bg-deck.jpg';
  const primary = (cfg.palette && cfg.palette.dark && cfg.palette.dark.primary) || '#00D4AA';
  return {
    backgroundImage: `
      linear-gradient(90deg, rgba(5,7,6,0.84) 0%, rgba(5,7,6,0.70) 48%, rgba(5,7,6,0.88) 100%),
      radial-gradient(circle at 82% 12%, ${primary}33, transparent 30%),
      url("${imgUrl}")
    `,
    backgroundSize: 'cover',
    backgroundPosition: 'center',
  };
}

// ── Motion primitives ──────────────────────────────────────────────────────

function useSlideActive(slideIndex) {
  const [active, setActive] = React.useState(false);
  const [tick, setTick] = React.useState(0);
  React.useEffect(() => {
    const stage = document.querySelector('deck-stage');
    if (!stage) return;
    const onChange = (e) => {
      const isMe = e.detail.index === slideIndex;
      if (isMe) {
        setActive(true);
        setTick(1);
      } else {
        setActive(false);
        setTick(0);
      }
    };
    stage.addEventListener('slidechange', onChange);
    const cur = stage.index ?? 0;
    if (cur === slideIndex) {
      setActive(true);
      setTick(1);
    }
    return () => stage.removeEventListener('slidechange', onChange);
  }, [slideIndex]);
  return { active, tick };
}

function entry(kind, { delay = 0, duration = 800, tick = 0 } = {}) {
  if (tick === 0) return { opacity: 0 };
  return {
    animationName: `pp-${kind}`,
    animationDuration: `${duration}ms`,
    animationDelay: `${delay}ms`,
    animationTimingFunction: 'cubic-bezier(.22,.61,.36,1)',
    animationFillMode: 'both',
    animationIterationCount: 1,
  };
}

function CountUp({ value, tick, duration = 1100, delay = 0 }) {
  const [out, setOut] = React.useState(value);
  React.useEffect(() => {
    if (!tick) { setOut(value); return; }
    const m = value.match(/(-|−|\+)?(\d+(?:\.\d+)?)/);
    if (!m) { setOut(value); return; }
    const target = parseFloat(m[2]);
    const sign = m[1] || '';
    const before = value.slice(0, m.index);
    const after = value.slice(m.index + m[0].length);
    let raf;
    const t0 = performance.now() + delay;
    const tick$ = (now) => {
      const t = Math.max(0, Math.min(1, (now - t0) / duration));
      const eased = 1 - Math.pow(1 - t, 3);
      const v = target * eased;
      const decimals = m[2].includes('.') ? 1 : 0;
      setOut(`${before}${sign}${v.toFixed(decimals)}${after}`);
      if (t < 1) raf = requestAnimationFrame(tick$);
    };
    raf = requestAnimationFrame(tick$);
    return () => raf && cancelAnimationFrame(raf);
  }, [tick, value, duration, delay]);
  return <>{out}</>;
}

// ── Shared chrome ──────────────────────────────────────────────────────────

function SlideFrame({ children, c, bg, style = {}, deckBg = false }) {
  return (
    <div style={{
      width: 1920, height: 1080,
      background: bg || c.bg,
      ...(deckBg ? darkDeckStyle() : null),
      color: c.fg,
      fontFamily: FONT_SANS,
      position: 'relative',
      overflow: 'hidden',
      boxSizing: 'border-box',
      ...style,
    }}>
      {children}
    </div>
  );
}

function CornerNum({ c, index, total, dark }) {
  const fg = dark ? c.ink : c.fg;
  const muted = dark ? 'rgba(14,16,32,0.45)' : c.fgDim;
  return (
    <div style={{
      position: 'absolute', top: 56, right: 96,
      fontFamily: FONT_MONO, fontSize: TYPE_SCALE.micro,
      color: muted, letterSpacing: '0.12em',
      display: 'flex', gap: 6,
    }}>
      <span style={{ color: fg, fontVariantNumeric: 'tabular-nums' }}>
        {String(index).padStart(2, '0')}
      </span>
      <span>/ {String(total).padStart(2, '0')}</span>
    </div>
  );
}

function CornerLabel({ c, label, dark }) {
  const muted = dark ? 'rgba(14,16,32,0.45)' : c.fgDim;
  return (
    <div style={{
      position: 'absolute', top: 56, left: 96,
      fontFamily: FONT_MONO, fontSize: TYPE_SCALE.micro,
      color: muted, letterSpacing: '0.18em', textTransform: 'uppercase',
      display: 'flex', alignItems: 'center', gap: 14,
    }}>
      <span>{label.replace(/^\d+\s*/, '')}</span>
    </div>
  );
}

function DeckTitle({ c, tick, eyebrow, line1, line2, accent, top = 188, maxWidth = 1540, dark = false }) {
  const muted = dark ? 'rgba(14,16,32,0.52)' : c.fgMuted;
  const fg = dark ? c.ink : c.fg;
  const primary = dark ? '#008F73' : c.primary;
  return (
    <div style={{ position: 'absolute', left: 96, top, maxWidth }}>
      {eyebrow && (
        <div style={{
          fontFamily: FONT_MONO,
          fontSize: 13,
          fontWeight: 700,
          letterSpacing: '0.20em',
          textTransform: 'uppercase',
          color: primary,
          marginBottom: 22,
          display: 'flex',
          alignItems: 'center',
          gap: 16,
          ...entry('fade', { tick, duration: 520 }),
        }}>
          <span style={{ width: 42, height: 1, background: 'currentColor', opacity: 0.62 }} />
          <span>{eyebrow}</span>
        </div>
      )}
      <h2 style={{
        margin: 0,
        fontSize: TYPE_SCALE.title,
        fontWeight: 560,
        letterSpacing: '-0.035em',
        lineHeight: 0.96,
        color: fg,
        textWrap: 'balance',
        ...entry('rise', { tick, delay: eyebrow ? 120 : 0, duration: 820 }),
      }}>
        {line1}
        {line2 && (
          <>
            <br />
            <span style={{
              color: accent ? primary : muted,
              fontStyle: accent ? 'italic' : 'normal',
              fontWeight: accent ? 420 : 360,
            }}>
              {line2}
            </span>
          </>
        )}
      </h2>
    </div>
  );
}

function Sig({ c, dark }) {
  const cfg = window.DECK_CONFIG || {};
  const left = cfg.sigLeft || 'Case Study';
  const right = cfg.sigRight || '';
  const muted = dark ? 'rgba(14,16,32,0.45)' : c.fgDim;
  return (
    <div style={{
      position: 'absolute', bottom: 36, left: 96, right: 96,
      display: 'flex', justifyContent: 'space-between',
      fontFamily: FONT_MONO, fontSize: 14,
      color: muted, letterSpacing: '0.16em', textTransform: 'uppercase',
    }}>
      <span>{left}</span>
      <span>{right}</span>
    </div>
  );
}

// ── VideoSlide — full-bleed video with title overlay ──────────────────────

function VideoSlide({ c, total, index, activeIndex, src, eyebrow, line1, line2, label, rightAlign = false }) {
  const { tick } = useSlideActive(activeIndex);
  const videoRef = React.useRef(null);

  React.useEffect(() => {
    const v = videoRef.current;
    if (!v) return;
    if (tick) {
      v.currentTime = 0;
      v.play().catch(() => {});
    } else {
      v.pause();
      v.currentTime = 0;
    }
  }, [tick]);

  const ct = React.useMemo(() => ({
    ...c,
    fg: '#0E1020',
    fgMuted: 'rgba(14,16,32,0.62)',
    fgDim: 'rgba(14,16,32,0.38)',
    rule: 'rgba(14,16,32,0.18)',
  }), [c]);

  return (
    <SlideFrame c={ct} bg="#000">
      <video
        ref={videoRef}
        src={src}
        loop
        muted
        playsInline
        style={{
          position: 'absolute', inset: 0,
          width: '100%', height: '100%',
          objectFit: 'cover',
        }}
      />
      <CornerLabel c={ct} label={label} dark />
      <CornerNum c={ct} index={index} total={total} dark />

      {rightAlign ? (
        <div style={{
          position: 'absolute', right: 96, top: 200, maxWidth: 900,
          textAlign: 'right',
          ...entry('rise', { tick, delay: 120, duration: 820 }),
        }}>
          <div style={{
            fontFamily: FONT_MONO, fontSize: 13, fontWeight: 700,
            letterSpacing: '0.20em', textTransform: 'uppercase',
            color: ct.primary, marginBottom: 22,
            display: 'flex', alignItems: 'center', justifyContent: 'flex-end', gap: 16,
            ...entry('fade', { tick, duration: 520 }),
          }}>
            <span>{eyebrow}</span>
            <span style={{ width: 42, height: 1, background: 'currentColor', opacity: 0.62 }} />
          </div>
          <h2 style={{
            margin: 0, fontSize: TYPE_SCALE.title, fontWeight: 560,
            letterSpacing: '-0.035em', lineHeight: 0.96, color: ct.fg,
          }}>
            {line1}<br />
            <span style={{ color: ct.primary, fontStyle: 'italic', fontWeight: 420 }}>
              {line2}
            </span>
          </h2>
        </div>
      ) : (
        <DeckTitle
          c={ct}
          tick={tick}
          eyebrow={eyebrow}
          line1={line1}
          line2={line2}
          accent
          dark
          top={200}
          maxWidth={900}
        />
      )}

      <Sig c={ct} dark />
    </SlideFrame>
  );
}

function BackToHub({ dark = false }) {
  const [hovered, setHovered] = React.useState(false);
  const fg = dark ? 'rgba(14,16,32,0.55)' : 'rgba(244,246,250,0.55)';
  const fgHover = dark ? 'rgba(14,16,32,0.90)' : 'rgba(244,246,250,0.90)';
  return (
    <a
      href="/"
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
      style={{
        position: 'absolute', top: 48, left: 80,
        display: 'inline-flex', alignItems: 'center', gap: 10,
        fontFamily: FONT_MONO, fontSize: 11,
        letterSpacing: '0.18em', textTransform: 'uppercase',
        color: hovered ? fgHover : fg,
        textDecoration: 'none',
        transition: 'color 180ms ease, transform 180ms ease',
        transform: hovered ? 'translateX(-4px)' : 'translateX(0)',
        zIndex: 10,
      }}
    >
      <span style={{ fontSize: 13, lineHeight: 1 }}>←</span>
      <span>Hub</span>
    </a>
  );
}

Object.assign(window, {
  TYPE_SCALE, SPACING, FONT_SANS, FONT_MONO,
  darkDeckStyle, useSlideActive, entry, CountUp,
  SlideFrame, CornerNum, CornerLabel, DeckTitle, Sig, VideoSlide, BackToHub,
});
