// Novox animations — radiating "speaking" loader + nova-star video intro.

const { useState: useS, useEffect: useE, useRef: useR } = React;

// True when the visitor asked their OS to reduce motion. JS-driven loops
// (requestAnimationFrame) aren't stopped by the CSS reduced-motion reset,
// so each animation checks this and renders a calm, static frame instead.
function nvxReducedMotion() {
  return typeof window !== 'undefined' && window.matchMedia
    && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
}

// The three sound-arc paths for one side, outer → inner radius order.
const NVX_ARCS = [
  { key: 'inner', d: 'M64.6 37.8 A 19 19 0 0 1 64.6 62.2', accent: true,  dim: 1.0 },
  { key: 'mid',   d: 'M70.7 32.6 A 27 27 0 0 1 70.7 67.4', accent: false, dim: 0.55 },
  { key: 'outer', d: 'M76.8 27.5 A 35 35 0 0 1 76.8 72.5', accent: false, dim: 1.0 },
];

const NVX_STAR = 'M50 35 Q52.1 47.9 65 50 Q52.1 52.1 50 65 Q47.9 52.1 35 50 Q47.9 47.9 50 35 Z';

// ─────────────────────────────────────────────────────────────
// Live "signal" loader — the sound-arcs pulse outward from the star in a
// travelling wave. Used for: loading indicators, "agent is speaking" status.
// ─────────────────────────────────────────────────────────────
function NovoxLoader({ size = 160, color = '#131726', accent = '#F5A623', showAccent = false, speed = 1 }) {
  const [t, setT] = useS(0);
  useE(() => {
    if (nvxReducedMotion()) return; // hold a static frame, no RAF loop
    let raf, start;
    const loop = (ts) => {
      if (!start) start = ts;
      setT(((ts - start) / 1000) * speed);
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, [speed]);

  // Each arc lags the one inside it → energy radiates from the star outward.
  const opacityFor = (i, dim) => {
    const wave = (Math.sin(t * 4.2 - i * 1.15) + 1) / 2; // 0..1
    return dim * (0.18 + 0.82 * wave);
  };

  const sideArcs = (mirror) => NVX_ARCS.map((a, i) => (
    <path key={(mirror ? 'l' : 'r') + a.key} d={a.d} fill="none" strokeLinecap="round"
      stroke={a.accent && showAccent ? accent : color} strokeWidth={4.4}
      opacity={opacityFor(i, a.dim)} />
  ));

  return (
    <svg width={size} height={size} viewBox="0 0 100 100" style={{ display: 'block' }}>
      <path d={NVX_STAR} fill={color} />
      <g>{sideArcs(false)}</g>
      <g transform="scale(-1,1) translate(-100,0)">{sideArcs(true)}</g>
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────
// Video intro — star ignites, the sound-arcs draw outward (inner → outer)
// on both sides, then the "Novox" wordmark reveals. 2.4s total, loops on click.
// ─────────────────────────────────────────────────────────────
function NovoxIntro({
  width = 560, height = 240,
  bg = '#F8F6F1', fg = '#131726', accent = '#F5A623',
  onDone,
  showCaption = true, showProgress = true, clickToReplay = true,
  playId: controlledPlayId,
}) {
  const [internalPlayId, setInternalPlayId] = useS(0);
  const playId = controlledPlayId !== undefined ? controlledPlayId : internalPlayId;
  const [t, setT] = useS(0); // 0..1 normalized
  const DURATION = 2400;

  useE(() => {
    if (nvxReducedMotion()) { setT(1); if (onDone) onDone(); return; } // show fully-drawn mark, no animation
    let raf, start;
    const loop = (ts) => {
      if (!start) start = ts;
      const k = Math.min(1, (ts - start) / DURATION);
      setT(k);
      if (k < 1) raf = requestAnimationFrame(loop);
      else if (onDone) onDone();
    };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, [playId]);

  const easeOut = (x) => 1 - Math.pow(1 - x, 3);
  const easeInOut = (x) => x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2;
  const clamp01 = (x) => Math.max(0, Math.min(1, x));

  // Star: ignites 0.02..0.26 with a soft overshoot, then holds.
  const starP = t <= 0.02 ? 0 : easeOut(clamp01((t - 0.02) / 0.24));
  const starScale = 0.55 + 0.45 * starP + Math.sin(starP * Math.PI) * 0.08;

  // Arcs draw inner → mid → outer, each over its own window. Both sides together.
  const arcWindows = [[0.16, 0.44], [0.28, 0.58], [0.40, 0.72]];
  const arcProg = (i) => {
    const [s, e] = arcWindows[i];
    if (t <= s) return 0;
    if (t >= e) return 1;
    return easeOut((t - s) / (e - s));
  };

  // Wordmark reveal: 0.58..0.98, slides in from the left.
  const wmProg = t < 0.58 ? 0 : t > 0.98 ? 1 : easeInOut((t - 0.58) / 0.4);

  const markSize = height * 0.62;

  const sideArcs = (mirror) => NVX_ARCS.map((a, i) => (
    <path key={(mirror ? 'l' : 'r') + a.key} d={a.d} fill="none" strokeLinecap="round"
      stroke={a.accent ? accent : fg} strokeWidth={4.4}
      opacity={a.dim < 1 ? a.dim * (arcProg(i) > 0 ? 1 : 0) : 1}
      pathLength={1} strokeDasharray={1} strokeDashoffset={1 - arcProg(i)} />
  ));

  return (
    <div style={{ position: 'relative', width, height, background: bg, overflow: 'hidden',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      cursor: clickToReplay ? 'pointer' : 'default', userSelect: 'none' }}
      onClick={clickToReplay ? () => setInternalPlayId((x) => x + 1) : undefined}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 28 }}>
        <svg width={markSize} height={markSize} viewBox="0 0 100 100" style={{ display: 'block' }}>
          <g transform={`translate(50 50) scale(${starScale}) translate(-50 -50)`} opacity={starP}>
            <path d={NVX_STAR} fill={fg} />
          </g>
          <g>{sideArcs(false)}</g>
          <g transform="scale(-1,1) translate(-100,0)">{sideArcs(true)}</g>
        </svg>
        <div style={{
          fontFamily: '"Space Grotesk", ui-sans-serif', fontWeight: 600,
          fontSize: height * 0.38, color: fg, letterSpacing: '-0.02em', lineHeight: 1,
          opacity: wmProg,
          transform: `translateX(${(1 - wmProg) * -16}px)`,
          transition: 'none',
        }}>Novox</div>
      </div>
      {showCaption && (
        <div style={{ position: 'absolute', bottom: 10, right: 14,
          fontFamily: '"JetBrains Mono", monospace', fontSize: 10,
          letterSpacing: '0.12em', textTransform: 'uppercase',
          color: fg, opacity: 0.35 }}>
          click to replay · {Math.round(t * DURATION)}ms
        </div>
      )}
      {showProgress && (
        <div style={{ position: 'absolute', bottom: 0, left: 0, height: 2,
          width: `${t * 100}%`, background: accent, opacity: 0.6 }} />
      )}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Ambient nova field — the brand signature as an environment.
// A breathing core glow + concentric sonar rings expanding outward
// (the "signal heard in every direction") + two slow orbital arcs
// echoing the mark's concentric sound-arcs. Pure CSS animation, so
// it composites on the GPU and never re-renders React. Sits behind
// hero / section content as a living backdrop.
// ─────────────────────────────────────────────────────────────
function NovoxField({ accent = '#F5A623', rings = 4, base = 300, glow = 0.5,
  orbit = true, style = {} }) {
  const ringEls = Array.from({ length: rings }, (_, i) => (
    <span key={i} className="nvx-ring-el" style={{
      position: 'absolute', left: '50%', top: '50%', width: base, height: base,
      marginLeft: -base / 2, marginTop: -base / 2, borderRadius: '50%',
      border: `1px solid ${accent}`,
      animationDelay: `${(i * 4.6) / rings}s`,
      '--nvx-ring-peak': 0.5 - i * 0.06,
    }} />
  ));
  return (
    <div aria-hidden style={{ position: 'absolute', inset: 0, overflow: 'hidden',
      pointerEvents: 'none', ...style }}>
      {/* breathing core glow */}
      <div className="nvx-breathe" style={{ position: 'absolute', left: '50%', top: '50%',
        width: base * 1.7, height: base * 1.7, marginLeft: -base * 0.85, marginTop: -base * 0.85,
        borderRadius: '50%',
        background: `radial-gradient(circle, ${accent}${Math.round(glow * 38).toString(16).padStart(2, '0')} 0%, transparent 62%)` }} />
      {ringEls}
      {orbit && (
        // One calm guide ring with a single "signal" node travelling around it —
        // a clean orbit rather than busy dashed circles. The ring is symmetric so
        // it reads as still; only the node moves. 1px stroke at any size.
        <svg className="nvx-orbit" viewBox="0 0 100 100" style={{ position: 'absolute',
          left: '50%', top: '50%', width: base * 1.7, height: base * 1.7,
          marginLeft: -base * 0.85, marginTop: -base * 0.85,
          animationDuration: '80s' }}>
          <circle cx="50" cy="50" r="48" fill="none" stroke={accent} strokeWidth="1"
            vectorEffect="non-scaling-stroke" opacity="0.16" />
          <circle cx="50" cy="2" r="1" fill={accent} opacity="0.85" />
        </svg>
      )}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Live waveform — the voice persona, made visible. A row of bars
// that rise and fall like an agent mid-sentence. CSS-driven; each
// bar carries its own delay + duration so the motion reads organic.
// ─────────────────────────────────────────────────────────────
const NVX_WAVE_PATTERN = [0.4, 0.7, 1.0, 0.55, 0.85, 0.35, 0.95, 0.6, 0.45, 0.8, 0.5, 0.7];
function NovoxWaveform({ bars = 12, color = '#131726', accent = '#F5A623',
  height = 32, width = 3, gap = 4, accentEvery = 4, style = {} }) {
  return (
    <div aria-hidden style={{ display: 'flex', alignItems: 'center', gap,
      height, ...style }}>
      {Array.from({ length: bars }, (_, i) => {
        const peak = NVX_WAVE_PATTERN[i % NVX_WAVE_PATTERN.length];
        const isAccent = i % accentEvery === accentEvery - 1;
        return (
          <span key={i} className="nvx-wave-bar" style={{ display: 'block',
            width, height: '100%', borderRadius: width,
            background: isAccent ? accent : color,
            transform: `scaleY(${peak})`,
            animationDelay: `${(i * 0.09).toFixed(2)}s`,
            animationDuration: `${(0.9 + (i % 5) * 0.14).toFixed(2)}s`,
            opacity: isAccent ? 1 : 0.55 }} />
        );
      })}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Compact loader pill — for buttons / inline "agent thinking"
// ─────────────────────────────────────────────────────────────
function NovoxPill({ label = 'Agent speaking', color = '#131726', bg = 'transparent' }) {
  return (
    <div style={{ display: 'inline-flex', alignItems: 'center', gap: 10,
      padding: '8px 14px', background: bg, borderRadius: 999,
      border: `1px solid ${color}22`, fontFamily: '"Inter", ui-sans-serif',
      fontSize: 12, color, letterSpacing: '-0.005em' }}>
      <NovoxLoader size={20} color={color} speed={1.4} />
      {label}
    </div>
  );
}

Object.assign(window, { NovoxLoader, NovoxIntro, NovoxPill, NovoxField, NovoxWaveform });
