// va-common.jsx — Vizalyze demo: brand tokens + reusable motion components.
// Loaded as a Babel script after animations.jsx. Exports to window at the bottom.

const VZ = {
  bg:      '#0a0b10',
  bg2:     '#0d0f16',
  panel:   '#12141d',
  border:  'rgba(255,255,255,0.10)',
  white:   '#f4f5f8',
  gray:    '#9aa3b2',
  grayDim: '#6b7280',
  blue:    '#0B6DFF',
  purple:  '#6A42E8',
  pink:    '#F24FA0',
  grad:    'linear-gradient(100deg, #0B6DFF 0%, #6A42E8 52%, #F24FA0 100%)',
  gradSoft:'linear-gradient(100deg, #2f7dff 0%, #8a6bf0 52%, #f56fb6 100%)',
  font:    "'Inter', system-ui, -apple-system, sans-serif",
  mono:    "'JetBrains Mono', ui-monospace, SFMono-Regular, monospace",
};

const W = 1920, H = 1080;

// ── easing reveal helper ─────────────────────────────────────────────────────
// Reads the enclosing Sprite's localTime. Fades/slides in at `start`, and
// auto-fades out `fadeOut` seconds before the sprite ends.
function Reveal({ start = 0, dur = 0.6, y = 22, x = 0, fadeOut = 0.45, blur = 0, children, style = {} }) {
  const { localTime, duration } = useSprite();
  const inT  = clamp((localTime - start) / dur, 0, 1);
  const ein  = Easing.easeOutCubic(inT);
  const exitStart = Math.max(0, duration - fadeOut);
  const outT = fadeOut > 0 ? clamp((localTime - exitStart) / fadeOut, 0, 1) : 0;
  const eout = Easing.easeInCubic(outT);

  const opacity = ein * (1 - eout);
  const ty = (1 - ein) * y - eout * 10;
  const tx = (1 - ein) * x;
  return (
    <div style={{
      opacity,
      transform: `translate(${tx}px, ${ty}px)`,
      filter: blur ? `blur(${(1 - ein) * blur}px)` : undefined,
      willChange: 'transform, opacity',
      ...style,
    }}>
      {children}
    </div>
  );
}

// ── gradient text ────────────────────────────────────────────────────────────
function GradientText({ children, style = {} }) {
  return (
    <span style={{
      background: VZ.gradSoft,
      WebkitBackgroundClip: 'text',
      backgroundClip: 'text',
      WebkitTextFillColor: 'transparent',
      ...style,
    }}>{children}</span>
  );
}

// ── animated background: dot grid + slow drifting brand glow ──────────────────
function BrandBackground({ glow = 1 }) {
  const t = useTime();
  const gx = 50 + Math.sin(t * 0.12) * 18;
  const gy = 42 + Math.cos(t * 0.09) * 14;
  return (
    <div style={{ position: 'absolute', inset: 0, background: VZ.bg, overflow: 'hidden' }}>
      <div style={{
        position: 'absolute', inset: '-10%',
        background: `radial-gradient(closest-side at ${gx}% ${gy}%, rgba(106,66,232,${0.18*glow}), transparent 70%),
                     radial-gradient(closest-side at ${100-gx}% ${gy+18}%, rgba(11,109,255,${0.12*glow}), transparent 70%),
                     radial-gradient(closest-side at ${gx+12}% ${100-gy}%, rgba(242,79,160,${0.08*glow}), transparent 70%)`,
        filter: 'blur(8px)',
      }} />
      <div style={{
        position: 'absolute', inset: 0,
        backgroundImage: 'radial-gradient(circle, rgba(255,255,255,0.05) 1.2px, transparent 1.2px)',
        backgroundSize: '40px 40px',
        maskImage: 'radial-gradient(ellipse 75% 70% at 50% 45%, black 35%, transparent 100%)',
        WebkitMaskImage: 'radial-gradient(ellipse 75% 70% at 50% 45%, black 35%, transparent 100%)',
      }} />
    </div>
  );
}

// ── Vizalyze VA mark — draws itself by `draw` prop (0..1) ─────────────────────
const VA_MAIN = "M230 395 C270 458 305 535 350 615 C382 672 421 706 466 644 C514 579 548 458 611 361 C658 289 721 299 758 373 C798 453 819 524 858 611";
const VA_INNER = "M438 654 C487 628 524 571 577 531 C622 497 668 508 710 484";

function AnimatedLogo({ size = 120, draw = 1, showDot = true, idSuffix = 'a' }) {
  const mainRef = React.useRef(null);
  const [dot, setDot] = React.useState({ x: 230, y: 395 });
  React.useEffect(() => {
    const el = mainRef.current;
    if (!el) return;
    const len = el.getTotalLength();
    const p = clamp(draw, 0, 1);
    try {
      const pt = el.getPointAtLength(len * p);
      setDot({ x: pt.x, y: pt.y });
    } catch (e) {}
  }, [draw]);

  const gid = `vg-${idSuffix}`, iid = `vi-${idSuffix}`;
  const dp = clamp(draw, 0, 1);
  const innerP = clamp((draw - 0.12) / 0.88, 0, 1);
  return (
    <svg viewBox="0 0 1024 1024" width={size} height={size} style={{ display: 'block', overflow: 'visible' }}>
      <defs>
        <linearGradient id={gid} x1="210" y1="475" x2="825" y2="560" gradientUnits="userSpaceOnUse">
          <stop offset="0%" stopColor="#0B6DFF" /><stop offset="52%" stopColor="#6A42E8" /><stop offset="100%" stopColor="#F24FA0" />
        </linearGradient>
        <linearGradient id={iid} x1="405" y1="675" x2="705" y2="515" gradientUnits="userSpaceOnUse">
          <stop offset="0%" stopColor="#1858F5" /><stop offset="60%" stopColor="#7044E6" /><stop offset="100%" stopColor="#D84DBA" />
        </linearGradient>
      </defs>
      <path d={VA_MAIN} fill="none" stroke="rgba(255,255,255,0.08)" strokeWidth="62" strokeLinecap="round" strokeLinejoin="round" />
      <path ref={mainRef} d={VA_MAIN} fill="none" stroke={`url(#${gid})`} strokeWidth="62"
        strokeLinecap="round" strokeLinejoin="round" pathLength="1"
        style={{ strokeDasharray: 1, strokeDashoffset: 1 - dp }} />
      <path d={VA_INNER} fill="none" stroke={`url(#${iid})`} strokeWidth="26"
        strokeLinecap="round" strokeLinejoin="round" pathLength="1"
        style={{ strokeDasharray: 1, strokeDashoffset: 1 - innerP }} />
      {showDot && dp > 0.02 && dp < 0.999 && (
        <circle cx={dot.x} cy={dot.y} r="34" fill="#fff" style={{ filter: 'drop-shadow(0 0 12px rgba(242,79,160,0.9))' }} />
      )}
    </svg>
  );
}

// ── wordmark lockup ───────────────────────────────────────────────────────────
function Wordmark({ size = 44, draw = 1, logoSize, gap = 18, color = VZ.white }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap }}>
      <AnimatedLogo size={logoSize || size * 1.5} draw={draw} idSuffix={'wm' + Math.round(size)} />
      <span style={{ fontFamily: VZ.font, fontWeight: 700, fontSize: size, letterSpacing: '-0.02em', color }}>
        Vizalyze
      </span>
    </div>
  );
}

// ── screenshot card with directed pan-zoom camera ─────────────────────────────
// cam: array of {p, scale, fx, fy}  (p = local progress 0..1, fx/fy normalized focus)
function Shot({ src, x, y, w, h, cam, radius = 16, entry = 0.6, exit = 0.45, frame = true }) {
  const { localTime, duration, progress } = useSprite();
  const inT = Easing.easeOutCubic(clamp(localTime / entry, 0, 1));
  const exitStart = Math.max(0, duration - exit);
  const outT = Easing.easeInCubic(clamp((localTime - exitStart) / exit, 0, 1));
  const opacity = inT * (1 - outT);
  const cardScale = (0.965 + 0.035 * inT) * (1 - 0.02 * outT);

  // camera keyframes over progress
  const ps  = cam.map(c => c.p);
  const sc  = interpolate(ps, cam.map(c => c.scale), Easing.easeInOutCubic)(progress);
  const fx  = interpolate(ps, cam.map(c => c.fx), Easing.easeInOutCubic)(progress);
  const fy  = interpolate(ps, cam.map(c => c.fy), Easing.easeInOutCubic)(progress);

  return (
    <div style={{
      position: 'absolute', left: x, top: y, width: w, height: h,
      opacity, transform: `scale(${cardScale})`, transformOrigin: 'center',
      borderRadius: radius, overflow: 'hidden',
      border: frame ? `1px solid ${VZ.border}` : 'none',
      boxShadow: frame ? '0 40px 90px -20px rgba(0,0,0,0.75), 0 0 0 1px rgba(255,255,255,0.04)' : 'none',
      background: VZ.panel,
      willChange: 'transform, opacity',
    }}>
      <img src={src} alt="" style={{
        width: '100%', height: '100%', objectFit: 'cover', display: 'block',
        transform: `scale(${sc})`,
        transformOrigin: `${fx * 100}% ${fy * 100}%`,
        willChange: 'transform',
      }} />
      {frame && (
        <div style={{
          position: 'absolute', inset: 0, borderRadius: radius, pointerEvents: 'none',
          background: 'linear-gradient(160deg, rgba(255,255,255,0.10), transparent 30%)',
        }} />
      )}
    </div>
  );
}

// ── kicker (mono section label with index) ────────────────────────────────────
function Kicker({ index, label }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 26 }}>
      <span style={{
        fontFamily: VZ.mono, fontSize: 19, fontWeight: 600, letterSpacing: '0.04em',
        background: VZ.grad, WebkitBackgroundClip: 'text', backgroundClip: 'text',
        WebkitTextFillColor: 'transparent',
      }}>{index}</span>
      <span style={{ width: 46, height: 1.5, background: VZ.grad, display: 'inline-block' }} />
      <span style={{
        fontFamily: VZ.mono, fontSize: 16, fontWeight: 500, letterSpacing: '0.22em',
        color: VZ.gray, textTransform: 'uppercase',
      }}>{label}</span>
    </div>
  );
}

// ── format / feature chip ─────────────────────────────────────────────────────
function Chip({ children, mono = true, accent = false }) {
  return (
    <span style={{
      fontFamily: mono ? VZ.mono : VZ.font,
      fontSize: 24, fontWeight: 500,
      padding: '12px 22px', borderRadius: 999,
      color: accent ? VZ.white : VZ.gray,
      background: accent ? 'rgba(106,66,232,0.18)' : 'rgba(255,255,255,0.04)',
      border: `1px solid ${accent ? 'rgba(138,107,240,0.5)' : VZ.border}`,
      whiteSpace: 'nowrap',
    }}>{children}</span>
  );
}

// ── animated cursor ────────────────────────────────────────────────────────────
// path: [{p, x, y}] keyframes over local progress; clickAt: progress to pop a click ring
function Cursor({ path, clickAt = [] }) {
  const { progress } = useSprite();
  const ps = path.map(p => p.p);
  const x = interpolate(ps, path.map(p => p.x), Easing.easeInOutCubic)(progress);
  const y = interpolate(ps, path.map(p => p.y), Easing.easeInOutCubic)(progress);

  // click ring
  let ring = null;
  for (const c of clickAt) {
    const dt = progress - c;
    if (dt >= 0 && dt < 0.06) {
      const k = dt / 0.06;
      ring = { r: 8 + k * 34, o: 1 - k };
      break;
    }
  }
  const press = clickAt.some(c => Math.abs(progress - c) < 0.025) ? 0.85 : 1;
  return (
    <div style={{ position: 'absolute', left: 0, top: 0, transform: `translate(${x}px, ${y}px)`, willChange: 'transform', zIndex: 50 }}>
      {ring && (
        <div style={{
          position: 'absolute', left: 2, top: 2, width: ring.r * 2, height: ring.r * 2,
          marginLeft: -ring.r, marginTop: -ring.r, borderRadius: '50%',
          border: '3px solid rgba(138,107,240,0.9)', opacity: ring.o,
        }} />
      )}
      <svg width="40" height="46" viewBox="0 0 24 28" style={{ transform: `scale(${press})`, transformOrigin: '2px 2px', filter: 'drop-shadow(0 3px 6px rgba(0,0,0,0.5))' }}>
        <path d="M2 2 L2 22 L7.5 17 L11 25 L14 23.5 L10.5 16 L18 16 Z" fill="#fff" stroke="#111" strokeWidth="1.4" strokeLinejoin="round" />
      </svg>
    </div>
  );
}

// ── persistent minimal frame (logo lockup + beat counter) ─────────────────────
function FrameChrome({ index, total, label }) {
  return (
    <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none', fontFamily: VZ.font }}>
      <div style={{ position: 'absolute', left: 60, bottom: 50, display: 'flex', alignItems: 'center', gap: 11, opacity: 0.92 }}>
        <AnimatedLogo size={34} draw={1} showDot={false} idSuffix="chrome" />
        <span style={{ fontWeight: 700, fontSize: 21, letterSpacing: '-0.02em', color: VZ.white }}>Vizalyze</span>
      </div>
      <div style={{ position: 'absolute', right: 60, bottom: 52, fontFamily: VZ.mono, fontSize: 16, letterSpacing: '0.18em', color: VZ.grayDim }}>
        {String(index).padStart(2, '0')} <span style={{ opacity: 0.5 }}>/ {String(total).padStart(2, '0')}</span>
        {label && <span style={{ color: VZ.gray, marginLeft: 14, letterSpacing: '0.2em' }}>{label}</span>}
      </div>
    </div>
  );
}

// ── global progress line along bottom edge ────────────────────────────────────
function ProgressLine() {
  const { time, duration } = useTimeline();
  return (
    <div style={{ position: 'absolute', left: 0, right: 0, bottom: 0, height: 3, background: 'rgba(255,255,255,0.06)' }}>
      <div style={{ height: '100%', width: `${(time / duration) * 100}%`, background: VZ.grad }} />
    </div>
  );
}

Object.assign(window, {
  VZ, W, H, Reveal, GradientText, BrandBackground, AnimatedLogo, Wordmark,
  Shot, Kicker, Chip, Cursor, FrameChrome, ProgressLine,
});
