// ui.jsx — shared UI primitives, exported to window
const { useState, useRef, useEffect } = React;

/* ---------- Icons (lucide-style set, synced with the Reclova dashboard) ---------- */
function Icon({ name, size = 20, stroke = 1.8, style, fill }) {
  const p = { width: size, height: size, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: stroke, strokeLinecap: 'round', strokeLinejoin: 'round', style };
  switch (name) {
    case 'arrowRight':return <svg {...p}><path d="M5 12h14M13 6l6 6-6 6" /></svg>;
    case 'arrowLeft':return <svg {...p}><path d="M19 12H5M11 6l-6 6 6 6" /></svg>;
    case 'check':return <svg {...p}><path d="M20 6 9 17l-5-5" /></svg>;
    case 'x':return <svg {...p}><path d="M18 6 6 18M6 6l12 12" /></svg>;
    case 'chevronDown':return <svg {...p}><path d="m6 9 6 6 6-6" /></svg>;
    case 'chevronRight':return <svg {...p}><path d="m9 18 6-6-6-6" /></svg>;
    case 'chevronLeft':return <svg {...p}><path d="m15 18-6-6 6-6" /></svg>;
    case 'mic':return <svg {...p}><rect x="9" y="2" width="6" height="12" rx="3" /><path d="M19 11a7 7 0 0 1-14 0M12 18v3" /></svg>;
    case 'micOff':return <svg {...p}><path d="M9 9v3a3 3 0 0 0 4.5 2.6M15 11.5V6a3 3 0 0 0-5.9-.7M5 11a7 7 0 0 0 10.7 6M12 18v3M4 4l16 16" /></svg>;
    case 'camera':return <svg {...p}><rect x="2" y="6" width="14" height="12" rx="2" /><path d="m16 10 6-3v10l-6-3z" /></svg>;
    case 'cameraOff':return <svg {...p}><path d="M16 16H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h1M7 6h9l2 2h2a2 2 0 0 1 2 2v6M4 4l16 16" /></svg>;
    case 'speaker':return <svg {...p}><path d="M11 5L6 9H3v6h3l5 4z" /><path d="M15.5 8.5a5 5 0 0 1 0 7" /><path d="M19 5a10 10 0 0 1 0 14" /></svg>;
    case 'wifi':return <svg {...p}><path d="M5 12.5a10 10 0 0 1 14 0M8.5 16a5.5 5.5 0 0 1 7 0" /><circle cx="12" cy="20" r="1" fill="currentColor" stroke="none" /></svg>;
    case 'calendar':return <svg {...p}><rect x="3" y="5" width="18" height="16" rx="2" /><path d="M16 3v4M8 3v4M3 11h18" /></svg>;
    case 'clock':return <svg {...p}><circle cx="12" cy="12" r="10" /><path d="M12 6v6l4 2" /></svg>;
    case 'phone':return <svg {...p}><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z" /></svg>;
    case 'phoneOff':return <svg {...p}><path d="M3 3l18 18M8.5 8.5l-1 1a11 11 0 0 0 4.5 4.5l1.5-2 4 1.5V17M21 12.5l-1.5-4-2.5 1" /></svg>;
    case 'copy':return <svg {...p}><rect x="9" y="9" width="11" height="11" rx="2" /><path d="M5 15H4a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v1" /></svg>;
    case 'mail':return <svg {...p}><rect x="3" y="5" width="18" height="14" rx="2" /><path d="m3 7 9 6 9-6" /></svg>;
    case 'alert':return <svg {...p}><path d="M10.3 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" /><path d="M12 9v4M12 17h.01" /></svg>;
    case 'shield':return <svg {...p}><path d="M12 2 4 5v6c0 5 3.5 9 8 11 4.5-2 8-6 8-11V5z" /></svg>;
    case 'shieldCheck':return <svg {...p}><path d="M12 2 4 5v6c0 5 3.5 9 8 11 4.5-2 8-6 8-11V5z" /><path d="M9 12l2 2 4-4" /></svg>;
    case 'sparkle':return <svg {...p}><path d="M12 2 14.2 9.8 22 12l-7.8 2.2L12 22l-2.2-7.8L2 12l7.8-2.2z" /></svg>;
    case 'play':return <svg width={size} height={size} viewBox="0 0 24 24" style={style}><polygon points="7 4 20 12 7 20" fill={fill || 'currentColor'} stroke={fill || 'currentColor'} strokeWidth="1.5" strokeLinejoin="round" /></svg>;
    case 'user':return <svg {...p}><circle cx="12" cy="8" r="4" /><path d="M4 21c0-4 4-7 8-7s8 3 8 7" /></svg>;
    case 'briefcase':return <svg {...p}><rect x="3" y="7" width="18" height="13" rx="2" /><path d="M9 7V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2M3 13h18" /></svg>;
    case 'zap':return <svg {...p}><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" fill={fill} /></svg>;
    case 'signal':return <svg {...p}><path d="M4 20h.01M8 20v-4M12 20v-8M16 20v-12M20 20V6" /></svg>;
    case 'refresh':return <svg {...p}><path d="M4 12a8 8 0 0 1 14-5.3L20 8M20 4v4h-4M20 12a8 8 0 0 1-14 5.3L4 16M4 20v-4h4" /></svg>;
    case 'eye':return <svg {...p}><path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7S2 12 2 12z" /><circle cx="12" cy="12" r="3" /></svg>;
    case 'lock':return <svg {...p}><rect x="4" y="11" width="16" height="10" rx="2" /><path d="M8 11V8a4 4 0 0 1 8 0v3" /></svg>;
    case 'globe':return <svg {...p}><circle cx="12" cy="12" r="10" /><path d="M2 12h20M12 2a15 15 0 0 1 0 20M12 2a15 15 0 0 0 0 20" /></svg>;
    case 'download':return <svg {...p}><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /><polyline points="7 10 12 15 17 10" /><line x1="12" y1="15" x2="12" y2="3" /></svg>;
    case 'send':return <svg {...p}><path d="m22 2-7 20-4-9-9-4z" /><path d="M22 2 11 13" /></svg>;
    case 'dot':return <svg {...p}><circle cx="12" cy="12" r="1.5" fill="currentColor" stroke="none" /></svg>;
    case 'record':return <svg width={size} height={size} viewBox="0 0 24 24" style={style}><circle cx="12" cy="12" r="6" fill={fill || 'currentColor'} /></svg>;
    default:return <svg {...p}><circle cx="12" cy="12" r="9" /></svg>;
  }
}

/* ---------- Logo (Reclova) — ink mark with bars glyph + coral accent dot, matching the dashboard top bar ---------- */
function Logo({ size = 22, mono = false }) {
  const mark = size + 8;
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
      <div style={{
        width: mark, height: mark, borderRadius: Math.round(mark * 0.27),
        display: 'grid', placeItems: 'center', flexShrink: 0, overflow: 'hidden',
        boxShadow: mono ? 'none' : 'var(--shadow-sm)', border: mono ? '1px solid var(--border)' : 'none'
      }}>
        <img src="/favicon.png" alt="Reclova" width={mark} height={mark} style={{ display: 'block', width: '100%', height: '100%', objectFit: 'cover' }} />
      </div>
      <span style={{ display: 'inline-flex', alignItems: 'baseline', fontFamily: 'var(--font)', fontWeight: 700, fontSize: size * 0.82, letterSpacing: '-0.015em', color: 'var(--text)' }}>
        Reclova<span style={{ color: 'var(--accent)', marginLeft: 1 }}></span>
      </span>
    </div>);
}

/* ---------- Button ---------- */
function Button({ children, onClick, variant = 'primary', size = 'md', icon, iconRight, full, disabled, style, type }) {
  const [hover, setHover] = useState(false);
  const sizes = {
    sm: { padding: '8px 14px', fontSize: 13.5, gap: 7, radius: 8 },
    md: { padding: '12px 20px', fontSize: 15, gap: 9, radius: 10 },
    lg: { padding: '16px 28px', fontSize: 16.5, gap: 10, radius: 10 }
  };
  const s = sizes[size];
  const variants = {
    primary: { background: hover ? 'var(--ink-hover)' : 'var(--ink)', color: 'var(--ink-fg)', border: '1px solid transparent', boxShadow: hover ? 'var(--shadow-md)' : 'var(--shadow-sm)' },
    accent: { background: hover ? 'var(--accent-hover)' : 'var(--accent)', color: 'var(--accent-fg)', border: '1px solid transparent', boxShadow: hover ? 'var(--shadow-md)' : 'var(--shadow-sm)' },
    secondary: { background: hover ? 'var(--surface-2)' : 'var(--surface)', color: 'var(--text)', border: '1px solid var(--border-strong)', boxShadow: 'var(--shadow-sm)' },
    ghost: { background: hover ? 'var(--surface-2)' : 'transparent', color: 'var(--text-dim)', border: '1px solid transparent' },
    danger: { background: hover ? 'var(--danger)' : 'var(--danger-soft)', color: hover ? 'var(--accent-fg)' : 'var(--danger)', border: '1px solid var(--danger)' },
    dangerSolid: { background: 'var(--danger)', color: '#fff', border: '1px solid transparent', boxShadow: hover ? 'var(--shadow-md)' : 'var(--shadow-sm)', filter: hover ? 'brightness(1.05)' : 'none' }
  };
  return (
    <button type={type || 'button'} onClick={disabled ? undefined : onClick}
    onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
    style={{
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: s.gap,
      padding: s.padding, fontSize: s.fontSize, fontWeight: 600, fontFamily: 'var(--font)',
      borderRadius: s.radius, cursor: disabled ? 'not-allowed' : 'pointer',
      width: full ? '100%' : 'auto', opacity: disabled ? 0.45 : 1,
      transition: 'background .15s, box-shadow .15s, transform .1s, filter .15s',
      letterSpacing: '-0.005em', lineHeight: 1.1, whiteSpace: 'nowrap', ...variants[variant], ...style
    }}>
      {icon && <Icon name={icon} size={s.fontSize + 2} stroke={2.2} />}
      {children}
      {iconRight && <Icon name={iconRight} size={s.fontSize + 2} stroke={2.2} />}
    </button>);
}

/* ---------- Card ---------- */
function Card({ children, style, pad = 30, interactive, selected, onClick }) {
  const [hover, setHover] = useState(false);
  return (
    <div onClick={onClick}
    onMouseEnter={() => interactive && setHover(true)} onMouseLeave={() => interactive && setHover(false)}
    style={{
      background: 'var(--surface)', border: `1px solid ${selected ? 'var(--accent)' : hover ? 'var(--border-strong)' : 'var(--border)'}`,
      borderRadius: 14, padding: pad,
      boxShadow: selected ? '0 0 0 3px var(--accent-ring), var(--shadow-md)' : hover ? 'var(--shadow-md)' : 'var(--shadow-sm)',
      cursor: interactive ? 'pointer' : 'default',
      transition: 'border-color .15s, box-shadow .18s, transform .15s',
      transform: hover && interactive ? 'translateY(-2px)' : 'none',
      ...style
    }}>
      {children}
    </div>);
}

/* ---------- StatusPill (with border, matching dashboard chip style) ---------- */
function StatusPill({ status, children, icon }) {
  const map = {
    good: { bg: 'var(--success-soft)', fg: 'var(--success)', bc: 'rgba(14,138,79,.18)' },
    warn: { bg: 'var(--warn-soft)', fg: 'var(--warn)', bc: 'rgba(182,121,10,.18)' },
    bad: { bg: 'var(--danger-soft)', fg: 'var(--danger)', bc: 'rgba(200,54,43,.18)' },
    neutral: { bg: 'var(--surface-2)', fg: 'var(--text-dim)', bc: 'var(--border)' },
    accent: { bg: 'var(--accent-soft)', fg: 'var(--accent)', bc: 'rgba(255,90,31,.18)' }
  };
  const c = map[status] || map.neutral;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 6, padding: '4px 11px 4px 9px',
      borderRadius: 999, fontSize: 11.5, fontWeight: 600, letterSpacing: '.01em',
      background: c.bg, color: c.fg, border: `1px solid ${c.bc}`, lineHeight: 1.2, whiteSpace: 'nowrap'
    }}>
      {icon && <Icon name={icon} size={12} stroke={2.4} />}
      {children}
    </span>);
}

/* ---------- Checkbox ---------- */
function Checkbox({ checked, onChange, children }) {
  return (
    <label style={{ display: 'flex', gap: 12, alignItems: 'flex-start', cursor: 'pointer', userSelect: 'none' }}
    onClick={(e) => {e.preventDefault();onChange(!checked);}}>
      <span style={{
        width: 22, height: 22, borderRadius: 6, flexShrink: 0, marginTop: 1,
        border: `1.5px solid ${checked ? 'var(--accent)' : 'var(--border-strong)'}`,
        background: checked ? 'var(--accent)' : 'var(--surface)', color: 'var(--accent-fg)',
        display: 'grid', placeItems: 'center', transition: 'all .15s'
      }}>
        {checked && <Icon name="check" size={15} stroke={3} />}
      </span>
      <span style={{ fontSize: 14.5, color: 'var(--text-dim)', lineHeight: 1.5 }}>{children}</span>
    </label>);
}

/* ---------- Modal ---------- */
function Modal({ children, onClose, tone, width = 460 }) {
  useEffect(() => {
    const h = (e) => {if (e.key === 'Escape' && onClose) onClose();};
    window.addEventListener('keydown', h);
    return () => window.removeEventListener('keydown', h);
  }, [onClose]);
  return (
    <div style={{
      position: 'fixed', inset: 0, zIndex: 1000, display: 'grid', placeItems: 'center', padding: 24,
      background: 'rgba(15,17,22,.45)', backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)',
      animation: 'fadeIn .18s ease'
    }} onClick={onClose}>
      <div onClick={(e) => e.stopPropagation()} style={{
        width: '100%', maxWidth: width, background: 'var(--surface)',
        border: `1px solid ${tone === 'danger' ? 'var(--danger)' : 'var(--border)'}`,
        borderRadius: 20, padding: 30,
        boxShadow: '0 32px 80px -20px rgba(15,17,22,.28), 0 12px 24px -8px rgba(15,17,22,.1)',
        animation: 'modalSlideUp .25s cubic-bezier(.2,.7,.3,1)'
      }}>
        {children}
      </div>
    </div>);
}

/* ---------- VoiceOrb (reacts to real audio amplitude, not a canned loop) ----------
   `level` is 0..1 real-time amplitude (from an AnalyserNode on the actual audio — see
   useAudioLevel below). Bar heights and glow track it directly so the motion matches
   actual speech energy: it visibly settles during pauses and swells on louder words,
   instead of pulsing at a fixed cadence regardless of what's actually being said. */
function VoiceOrb({ speaking, level = 0, size = 140 }) {
  const barWeights = [0.55, 0.85, 1, 0.85, 0.55]; // relative per-bar weighting for a natural equalizer look
  const l = speaking ? Math.max(0, Math.min(1, level)) : 0;
  return (
    <div style={{ position: 'relative', width: size, height: size, display: 'grid', placeItems: 'center' }}>
      {[0, 1, 2].map((i) =>
      <div key={i} style={{
        position: 'absolute', inset: 0, borderRadius: '50%', border: '1.5px solid var(--accent)',
        opacity: speaking ? Math.max(0, l * 0.5 - i * 0.12) : 0,
        transform: `scale(${1 + l * 0.1 + i * 0.06})`,
        transition: 'opacity 0.12s ease-out, transform 0.12s ease-out',
      }} />
      )}
      <div style={{
        width: size * 0.62, height: size * 0.62, borderRadius: '50%',
        background: 'radial-gradient(circle at 35% 30%, var(--accent), var(--accent-hover))',
        boxShadow: speaking ? `0 0 ${6 + l * 22}px ${l * 3}px var(--accent-ring), var(--shadow-lg)` : 'var(--shadow-md)',
        transform: `scale(${1 + l * 0.05})`,
        display: 'grid', placeItems: 'center', color: 'var(--accent-fg)',
        transition: 'box-shadow 0.1s ease-out, transform 0.1s ease-out'
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 3, height: size * 0.22 }}>
          {barWeights.map((w, i) =>
          <span key={i} style={{
            width: 3.5, borderRadius: 2, background: 'var(--accent-fg)',
            height: `${speaking ? Math.max(18, l * 100 * w) : 24}%`,
            transition: 'height 0.1s ease-out', opacity: 0.92
          }} />
          )}
        </div>
      </div>
    </div>);
}

/* ---------- Screen shell with intro animation ---------- */
function Screen({ children, max = 560, center = true, style }) {
  return (
    <div style={{
      width: '100%', maxWidth: max, margin: '0 auto',
      display: 'flex', flexDirection: 'column', alignItems: center ? 'center' : 'stretch',
      animation: 'screenIn .35s cubic-bezier(.2,.7,.3,1)', ...style
    }}>
      {children}
    </div>);
}

/* ---------- Spinner ---------- */
function Spinner({ size = 14 }) {
  return (
    <span style={{ width: size, height: size, borderRadius: '50%', border: '2px solid var(--border)', borderTopColor: 'var(--accent)', display: 'inline-block', animation: 'spin 0.8s linear infinite', flexShrink: 0 }} />
  );
}

Object.assign(window, { Icon, Logo, Button, Card, StatusPill, Checkbox, Modal, VoiceOrb, Screen, Spinner });
