// primitives.jsx — shared visual atoms

// ──────────────────────────────────────────────────────────────────────────
// Obsidian Ridge — Design System tokens
// Source: DESIGN.md (reverse-engineered from brand PNGs).
//   --obsidian-black #000   --ridge-gold #D6A45F   --cream #FDFBF7
// Strictly two colors on dark. No blue/green/red accents — except chromatic
// aberration in the deepfake-glitch moment, which is an *intentional* break
// (the brand is being attacked in that scene).
// ──────────────────────────────────────────────────────────────────────────
const OR = {
  bg:        '#000000',
  bgSlate:   '#0F0F0F',
  ink:       '#FDFBF7',
  inkDim:    'rgba(253,251,247,0.58)',
  inkFaint:  'rgba(253,251,247,0.22)',
  line:      'rgba(214,164,95,0.18)',
  // Ridge gold — the only brand accent
  gold:      '#D6A45F',
  goldDim:   '#D1A55A',
  goldDeep:  '#A87842',
  cream:     '#FDFBF7',
  inkDark:   '#292929',

  // Legacy aliases (so existing scene code still resolves).
  alert:     '#D6A45F',
  alertSoft: '#D1A55A',
  amber:     '#D6A45F',
  signal:    '#FDFBF7',         // "remedy" = cream — high contrast on gold
  steel:     'rgba(253,251,247,0.4)',
};

// ── Type stacks ────────────────────────────────────────────────────────────
const FF = {
  display: "'Cinzel', 'Trajan Pro', 'Times New Roman', serif",
  sans:    "'Space Grotesk', system-ui, sans-serif",
  mono:    "'JetBrains Mono', ui-monospace, monospace",
  italic:  "'Cormorant Garamond', 'Cinzel', serif",
};

// ──────────────────────────────────────────────────────────────────────────
// Film grain + vignette over everything
// ──────────────────────────────────────────────────────────────────────────
function FilmTexture() {
  return (
    <React.Fragment>
      <div style={{
        position: 'absolute', inset: 0, pointerEvents: 'none',
        background: 'radial-gradient(ellipse at 50% 50%, transparent 40%, rgba(0,0,0,0.55) 100%)',
        mixBlendMode: 'multiply', zIndex: 80,
      }} />
      <div style={{
        position: 'absolute', inset: 0, pointerEvents: 'none', zIndex: 81,
        opacity: 0.12,
        backgroundImage: "url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.55 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>\")",
        mixBlendMode: 'overlay',
      }} />
    </React.Fragment>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Brand mark — hexagonal gateway with faceted mountain peaks inside.
// Per DESIGN.md: hexagonal silhouette in gold linework; mountain peaks
// rising from baseline; gold-on-black only.
// ──────────────────────────────────────────────────────────────────────────
function HexMark({ size = 80, color = OR.gold, fillPeaks = true }) {
  const s = size;
  // hex points (normalized 0-80 viewBox)
  const hex = "40,4 72,22 72,58 40,76 8,58 8,22";
  return (
    <svg width={s} height={s} viewBox="0 0 80 80" style={{ display: 'block' }}>
      {/* outer hexagonal gateway */}
      <polygon points={hex} fill="none" stroke={color} strokeWidth="2" strokeLinejoin="miter" />
      {/* PCB trace decorations inside hex (top arc) */}
      <path d="M 20 22 L 24 22 L 24 18 M 56 22 L 60 22 L 60 18"
        stroke={color} strokeWidth="1" fill="none" opacity="0.7" />
      <circle cx="24" cy="18" r="1.2" fill={color} opacity="0.7" />
      <circle cx="60" cy="18" r="1.2" fill={color} opacity="0.7" />
      {/* faceted mountain peaks at bottom — three peaks, low-poly */}
      <polygon
        points="14,60 26,44 34,52 42,36 50,48 56,42 66,60"
        fill={fillPeaks ? color : 'none'}
        stroke={color}
        strokeWidth={fillPeaks ? 0 : 1.6}
        strokeLinejoin="miter"
      />
      {/* secondary back ridge */}
      <polygon
        points="10,60 20,52 28,58 36,46 44,54 52,44 60,52 70,60"
        fill="none" stroke={color} strokeWidth="1" opacity="0.45"
      />
    </svg>
  );
}

// Small PCB-style trace ornament — for corners / edges of scenes.
// kind: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
function PCBTrace({ kind = 'top-left', size = 200, color = OR.gold, opacity = 0.5 }) {
  const flip = (kind === 'top-right' || kind === 'bottom-right');
  const flipY = (kind === 'bottom-left' || kind === 'bottom-right');
  const tx = flip ? `scale(-1, ${flipY ? -1 : 1}) translate(${-size}, 0)` : (flipY ? `scale(1, -1) translate(0, ${-size})` : '');
  return (
    <svg width={size} height={size} viewBox="0 0 200 200" style={{ display: 'block', overflow: 'visible' }}>
      <g transform={tx} stroke={color} fill={color} strokeWidth="1.4" opacity={opacity}>
        {/* main L trace */}
        <path d="M 0 16 L 60 16 L 60 60 L 110 60 L 110 110" fill="none" />
        <circle cx="60" cy="16" r="2" />
        <circle cx="110" cy="60" r="2" />
        <circle cx="110" cy="110" r="2" />
        {/* secondary branch */}
        <path d="M 60 16 L 60 36 L 80 36" fill="none" />
        <circle cx="80" cy="36" r="1.5" />
        {/* terminal pad */}
        <rect x="-1" y="14" width="6" height="4" fill={color} stroke="none" />
      </g>
    </svg>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Source citation — small mono line, bottom-left.
// ──────────────────────────────────────────────────────────────────────────
function SourceChip({ text, x = 60, y = 1000 }) {
  return (
    <div style={{
      position: 'absolute', left: x, top: y,
      fontFamily: FF.mono,
      fontSize: 14, letterSpacing: '0.18em',
      color: OR.inkFaint, textTransform: 'uppercase',
    }}>
      <span style={{ color: OR.gold, marginRight: 10 }}>—</span>{text}
    </div>
  );
}

// Eyebrow — small uppercase mono with leading gold dot.
function Eyebrow({ children, x, y, color = OR.gold }) {
  return (
    <div style={{
      position: 'absolute', left: x, top: y,
      display: 'flex', alignItems: 'center', gap: 14,
      fontFamily: FF.mono,
      fontSize: 16, letterSpacing: '0.28em',
      color: color, textTransform: 'uppercase',
    }}>
      <span style={{
        width: 7, height: 7, borderRadius: 0,
        background: color,
        boxShadow: `0 0 12px ${color}`,
        transform: 'rotate(45deg)',
      }} />
      {children}
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Counter — ticks a number up using a custom curve.
// fromVal/toVal and t∈[0,1]. format is a fn.
// ──────────────────────────────────────────────────────────────────────────
function useCountUp({ from, to, start, end, ease = Easing.easeOutExpo }) {
  const t = useTime();
  if (t <= start) return from;
  if (t >= end) return to;
  const p = ease((t - start) / (end - start));
  return from + (to - from) * p;
}

// Format a big number with commas, optional currency prefix.
function fmtMoney(n, opts = {}) {
  const v = Math.floor(n);
  const s = v.toLocaleString('en-US');
  return (opts.prefix || '$') + s;
}

// Format a percent (0-100 scale)
function fmtPct(n, digits = 1) {
  return n.toFixed(digits) + '%';
}

// ──────────────────────────────────────────────────────────────────────────
// VideoCallTile — Zoom/Teams-style call cell.
// Soft gradient background, circular initials avatar, name strap, REC dot.
// Glitch prop (0..1) progressively distorts the tile for the deepfake reveal.
// ──────────────────────────────────────────────────────────────────────────
function PortraitTile({ x, y, w, h, label, role, initials, hue = 220, talking = true, glitch = 0 }) {
  const t = useTime();

  // subtle breathing on the avatar so it doesn't feel dead
  const breathe = 1 + Math.sin(t * 1.6 + hue * 0.01) * 0.012;
  // talking pulse — outer ring of the avatar
  const talk = talking ? Math.max(0, Math.sin(t * 6.0 + hue * 0.03)) : 0;

  // glitch effects
  const gShiftX = glitch > 0 ? Math.sin(t * 50 + hue) * 6 * glitch : 0;
  const tearY   = glitch > 0 ? (((t * 0.7 + hue * 0.01) % 1) * h) : -100;
  const split   = glitch * 6;

  const avSize = Math.min(w, h) * 0.42;
  const gradTop  = `oklch(${28 + (hue % 30) * 0.4}% 0.05 ${hue})`;
  const gradBot  = `oklch(${14 + (hue % 30) * 0.2}% 0.04 ${hue})`;
  const avTop    = `oklch(${64}% 0.07 ${hue})`;
  const avBot    = `oklch(${52}% 0.09 ${hue})`;

  return (
    <div style={{
      position: 'absolute', left: x, top: y, width: w, height: h,
      overflow: 'hidden', borderRadius: 10,
      background: `linear-gradient(165deg, ${gradTop} 0%, ${gradBot} 100%)`,
      border: `1px solid ${OR.line}`,
      transform: `translate(${gShiftX}px, 0)`,
      filter: glitch > 0.4 ? `hue-rotate(${(glitch - 0.4) * 60}deg)` : 'none',
    }}>
      {/* RGB color-split halos behind avatar when glitching */}
      {glitch > 0 && (
        <React.Fragment>
          <div style={{
            position: 'absolute', left: '50%', top: '50%',
            transform: `translate(calc(-50% - ${split}px), -50%) scale(${breathe})`,
            width: avSize, height: avSize, borderRadius: '50%',
            background: `oklch(60% 0.18 25 / ${glitch * 0.6})`,
            mixBlendMode: 'screen',
            filter: `blur(${glitch * 2}px)`,
          }} />
          <div style={{
            position: 'absolute', left: '50%', top: '50%',
            transform: `translate(calc(-50% + ${split}px), -50%) scale(${breathe})`,
            width: avSize, height: avSize, borderRadius: '50%',
            background: `oklch(60% 0.18 250 / ${glitch * 0.6})`,
            mixBlendMode: 'screen',
            filter: `blur(${glitch * 2}px)`,
          }} />
        </React.Fragment>
      )}

      {/* talking-ring */}
      <div style={{
        position: 'absolute', left: '50%', top: '50%',
        transform: `translate(-50%, -50%) scale(${1 + talk * 0.08})`,
        width: avSize + 18, height: avSize + 18, borderRadius: '50%',
        border: `2px solid oklch(80% 0.08 ${hue} / ${0.55 + talk * 0.4})`,
        opacity: glitch < 0.4 ? 1 : 0,
      }} />

      {/* avatar circle with initials */}
      <div style={{
        position: 'absolute', left: '50%', top: '50%',
        transform: `translate(-50%, -50%) scale(${breathe})`,
        width: avSize, height: avSize, borderRadius: '50%',
        background: `linear-gradient(160deg, ${avTop} 0%, ${avBot} 100%)`,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        fontFamily: 'Space Grotesk, sans-serif',
        fontWeight: 600,
        fontSize: avSize * 0.42, color: '#0a080c',
        letterSpacing: '-0.02em',
        boxShadow: `inset 0 ${avSize * 0.06}px ${avSize * 0.12}px rgba(255,255,255,0.18), 0 ${avSize * 0.04}px ${avSize * 0.08}px rgba(0,0,0,0.45)`,
        filter: glitch > 0.7 ? `blur(${(glitch - 0.7) * 16}px)` : 'none',
      }}>
        {initials}
      </div>

      {/* glitch overlays */}
      {glitch > 0 && (
        <React.Fragment>
          {/* scanlines */}
          <div style={{
            position: 'absolute', inset: 0, pointerEvents: 'none',
            backgroundImage: 'repeating-linear-gradient(0deg, rgba(0,0,0,0.45) 0 1px, transparent 1px 3px)',
            opacity: glitch,
          }} />
          {/* horizontal tear */}
          <div style={{
            position: 'absolute', left: 0, right: 0,
            top: tearY, height: 10 * glitch,
            background: 'oklch(60% 0.2 25)', opacity: 0.7 * glitch,
            mixBlendMode: 'screen',
          }} />
          {/* color-split edge */}
          <div style={{
            position: 'absolute', inset: 0, pointerEvents: 'none',
            boxShadow: `inset ${-4 * glitch}px 0 0 oklch(70% 0.2 25 / ${glitch * 0.6}), inset ${4 * glitch}px 0 0 oklch(70% 0.2 250 / ${glitch * 0.6})`,
          }} />
        </React.Fragment>
      )}

      {/* REC indicator top-left */}
      <div style={{
        position: 'absolute', top: 14, left: 14,
        display: 'flex', alignItems: 'center', gap: 6,
        fontFamily: 'JetBrains Mono, monospace',
        fontSize: 11, color: OR.inkDim, letterSpacing: '0.16em',
      }}>
        <span style={{
          width: 7, height: 7, borderRadius: 7, background: OR.alert,
          opacity: 0.55 + Math.sin(t * 3 + hue) * 0.45,
          boxShadow: `0 0 8px ${OR.alert}`,
        }} />
        REC
      </div>

      {/* mute mic icon top-right (mock UI chrome) */}
      <div style={{
        position: 'absolute', top: 14, right: 14,
        width: 22, height: 22, borderRadius: 6,
        background: 'rgba(0,0,0,0.35)',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
      }}>
        <svg width="11" height="14" viewBox="0 0 11 14" fill="none">
          <rect x="3" y="1" width="5" height="8" rx="2.5" stroke={OR.inkDim} strokeWidth="1.3" />
          <path d="M1 7 a4.5 4.5 0 0 0 9 0" stroke={OR.inkDim} strokeWidth="1.3" fill="none" />
          <path d="M5.5 12 v1.5" stroke={OR.inkDim} strokeWidth="1.3" />
        </svg>
      </div>

      {/* name strap */}
      <div style={{
        position: 'absolute', left: 14, bottom: 12, right: 14,
        display: 'flex', alignItems: 'baseline', justifyContent: 'space-between',
        gap: 12, whiteSpace: 'nowrap',
        fontFamily: 'Space Grotesk, sans-serif',
      }}>
        <div style={{ fontSize: 18, fontWeight: 600, color: OR.ink, letterSpacing: '-0.01em', whiteSpace: 'nowrap' }}>{label}</div>
        <div style={{
          fontFamily: 'JetBrains Mono, monospace',
          fontSize: 11, color: OR.inkFaint, letterSpacing: '0.14em', textTransform: 'uppercase',
          whiteSpace: 'nowrap',
        }}>{role}</div>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// CursorTip — animated cursor pointer
// ──────────────────────────────────────────────────────────────────────────
function CursorTip({ x, y, size = 28 }) {
  return (
    <div style={{
      position: 'absolute', left: x, top: y, width: size, height: size,
      transform: 'translate(-2px, -2px)',
      filter: 'drop-shadow(0 4px 10px rgba(0,0,0,0.6))',
      zIndex: 50,
    }}>
      <svg width={size} height={size} viewBox="0 0 28 28">
        <path d="M3 2 L3 22 L9 16 L13 24 L17 22 L13 14 L21 14 Z"
          fill="#fff" stroke="#000" strokeWidth="1.5" strokeLinejoin="round" />
      </svg>
    </div>
  );
}

Object.assign(window, {
  OR, FF, FilmTexture, SourceChip, Eyebrow,
  HexMark, PCBTrace,
  useCountUp, fmtMoney, fmtPct,
  PortraitTile, CursorTip,
});
