// Shared viz helpers — iridescent palette
function Sparkline({ data, w = 80, h = 24, color = "var(--cyan)", fill = true, gradient = false }) {
  const max = Math.max(...data, 1);
  const min = Math.min(...data, 0);
  const range = max - min || 1;
  const step = w / (data.length - 1 || 1);
  const pts = data.map((v, i) => [i * step, h - ((v - min) / range) * h]);
  const d = pts.map((p, i) => (i === 0 ? `M${p[0]},${p[1]}` : `L${p[0]},${p[1]}`)).join(' ');
  const area = d + ` L${w},${h} L0,${h} Z`;
  const gid = `g-${Math.random().toString(36).slice(2, 8)}`;
  return (
    <svg className="spark" width={w} height={h} viewBox={`0 0 ${w} ${h}`}>
      {gradient && (
        <defs>
          <linearGradient id={gid} x1="0" x2="1" y1="0" y2="0">
            <stop offset="0%" stopColor="#4be8ff"/>
            <stop offset="50%" stopColor="#8b6bff"/>
            <stop offset="100%" stopColor="#ff7ad9"/>
          </linearGradient>
          <linearGradient id={gid + '-f'} x1="0" x2="0" y1="0" y2="1">
            <stop offset="0%" stopColor="#8b6bff" stopOpacity="0.4"/>
            <stop offset="100%" stopColor="#8b6bff" stopOpacity="0"/>
          </linearGradient>
        </defs>
      )}
      {fill && <path d={area} fill={gradient ? `url(#${gid}-f)` : color} opacity={gradient ? 1 : 0.14}/>}
      <path d={d} fill="none" stroke={gradient ? `url(#${gid})` : color} strokeWidth="1.4" strokeLinejoin="round" strokeLinecap="round"/>
    </svg>
  );
}

function BarSeries({ data, w = 120, h = 32, color = "var(--cyan)" }) {
  const max = Math.max(...data, 1);
  const bw = w / data.length - 1;
  return (
    <svg className="spark" width={w} height={h} viewBox={`0 0 ${w} ${h}`}>
      {data.map((v, i) => {
        const bh = (v / max) * h;
        return <rect key={i} x={i * (bw + 1)} y={h - bh} width={bw} height={bh} fill={color} opacity={0.4 + (v / max) * 0.6} rx="1"/>;
      })}
    </svg>
  );
}

function Ring({ pct, size = 44, stroke = 3.5, color = "var(--cyan)" }) {
  const r = (size - stroke) / 2;
  const c = 2 * Math.PI * r;
  const off = c - (pct / 100) * c;
  const gid = `r-${Math.random().toString(36).slice(2, 8)}`;
  return (
    <div className="ring-wrap" style={{ width: size, height: size }}>
      <svg width={size} height={size}>
        <defs>
          <linearGradient id={gid} x1="0" x2="1" y1="0" y2="1">
            <stop offset="0%" stopColor="#4be8ff"/>
            <stop offset="100%" stopColor="#8b6bff"/>
          </linearGradient>
        </defs>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="rgba(255,255,255,0.06)" strokeWidth={stroke}/>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke={`url(#${gid})`} strokeWidth={stroke}
          strokeDasharray={c} strokeDashoffset={off} strokeLinecap="round"
          transform={`rotate(-90 ${size/2} ${size/2})`}/>
      </svg>
      <span className="ring-label">{pct}</span>
    </div>
  );
}

function Heatmap({ rows = 7, cols = 24 }) {
  const cells = [];
  for (let r = 0; r < rows; r++) {
    for (let c = 0; c < cols; c++) {
      const seed = (r * 31 + c * 7) % 100;
      const v = (Math.sin(seed) + 1) / 2;
      const peak = c > 7 && c < 18 ? 0.5 : 0;
      const intensity = Math.min(1, v * 0.6 + peak);
      const hue = 240 + intensity * 60;
      cells.push(
        <div key={`${r}-${c}`} style={{
          width: 11, height: 11,
          background: `hsla(${hue}, 80%, ${50 + intensity * 20}%, ${intensity * 0.85})`,
          borderRadius: 2,
          boxShadow: intensity > 0.7 ? `0 0 4px hsla(${hue}, 80%, 60%, 0.6)` : 'none',
        }}/>
      );
    }
  }
  return (
    <div style={{
      display: 'grid',
      gridTemplateColumns: `repeat(${cols}, 11px)`,
      gridAutoRows: '11px',
      gap: 3,
    }}>{cells}</div>
  );
}

function Tag({ status, children }) {
  const cls = status === 'live' ? 'tag live'
    : status === 'paused' ? 'tag paused'
    : status === 'error' ? 'tag error'
    : status === 'scheduled' ? 'tag scheduled' : 'tag';
  return <span className={cls}>{children || status}</span>;
}

function StatusTag({ status }) {
  const label = { live: 'LIVE', paused: 'PAUSED', error: 'ERROR', scheduled: 'SCHEDULED', draft: 'DRAFT', connected: 'CONNECTED', disconnected: 'DISCONNECTED', degraded: 'DEGRADED' }[status] || status?.toUpperCase();
  const map = { connected: 'live', disconnected: 'paused', degraded: 'error' };
  return <Tag status={map[status] || status}>{label}</Tag>;
}

function fakeStream(seed, n = 24, base = 50, amp = 30) {
  return Array.from({ length: n }, (_, i) => {
    return base + Math.round(Math.sin((i + seed) * 0.4) * amp * 0.6 + Math.cos((i * 0.7 + seed) * 0.3) * amp * 0.4 + amp * 0.5);
  });
}

function linePath(data, w, h, padFraction = 0.1) {
  const max = Math.max(...data, 1);
  const step = w / (data.length - 1);
  const pad = h * padFraction;
  const avail = h - pad * 2;
  return data.map((v, i) => `${i === 0 ? 'M' : 'L'}${i * step},${h - pad - (v / max) * avail}`).join(' ');
}
function areaPath(data, w, h, padFraction = 0.1) {
  return linePath(data, w, h, padFraction) + ` L${w},${h} L0,${h} Z`;
}

// Cosmos dial — circular real-time gauge (signature visual)
function CosmosDial({ size = 280, agents = AGENTS }) {
  const cx = size / 2, cy = size / 2;
  const liveAgents = agents.filter(a => a.status === 'live');
  return (
    <div className="cosmos" style={{ height: size }}>
      <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
        <defs>
          <radialGradient id="cosmos-bg" cx="50%" cy="50%">
            <stop offset="0%" stopColor="#1a1f4d" stopOpacity="0.5"/>
            <stop offset="60%" stopColor="#07091a" stopOpacity="0"/>
          </radialGradient>
          <linearGradient id="cosmos-ring" x1="0" x2="1" y1="0" y2="1">
            <stop offset="0%" stopColor="#4be8ff"/>
            <stop offset="50%" stopColor="#8b6bff"/>
            <stop offset="100%" stopColor="#ff7ad9"/>
          </linearGradient>
        </defs>
        <circle cx={cx} cy={cy} r={size/2 - 4} fill="url(#cosmos-bg)"/>
        {/* outer ring */}
        <circle cx={cx} cy={cy} r={size/2 - 14} fill="none" stroke="rgba(255,255,255,0.05)" strokeWidth="1"/>
        <circle cx={cx} cy={cy} r={size/2 - 14} fill="none" stroke="url(#cosmos-ring)" strokeWidth="1.5" strokeDasharray="180 600" transform={`rotate(-90 ${cx} ${cy})`}/>
        {/* tick marks */}
        {Array.from({ length: 60 }).map((_, i) => {
          const a = (i / 60) * Math.PI * 2 - Math.PI / 2;
          const r1 = size/2 - 22, r2 = i % 5 === 0 ? size/2 - 30 : size/2 - 26;
          return <line key={i} x1={cx + Math.cos(a) * r1} y1={cy + Math.sin(a) * r1}
            x2={cx + Math.cos(a) * r2} y2={cy + Math.sin(a) * r2}
            stroke="rgba(255,255,255,0.18)" strokeWidth={i % 5 === 0 ? 1 : 0.5}/>;
        })}
        {/* inner ring */}
        <circle cx={cx} cy={cy} r={size/2 - 64} fill="none" stroke="rgba(255,255,255,0.08)" strokeWidth="1" strokeDasharray="4 6"/>
        {/* agent dots on orbit */}
        {liveAgents.map((a, i) => {
          const angle = (i / liveAgents.length) * Math.PI * 2 - Math.PI / 2;
          const r = size/2 - 48;
          const x = cx + Math.cos(angle) * r;
          const y = cy + Math.sin(angle) * r;
          return (
            <g key={a.id}>
              <circle cx={x} cy={y} r="4" fill="#4be8ff" opacity="0.3"/>
              <circle cx={x} cy={y} r="2.5" fill="#4be8ff"/>
            </g>
          );
        })}
        {/* center text */}
        <text x={cx} y={cy - 4} textAnchor="middle" fontSize="36" fill="#eaecf5"
          fontFamily="Instrument Serif" fontStyle="italic">{liveAgents.length}</text>
        <text x={cx} y={cy + 18} textAnchor="middle" fontSize="9" fill="#8388a8"
          fontFamily="Geist Mono" letterSpacing="2">LIVE AGENTS</text>
        <text x={cx} y={cy + 36} textAnchor="middle" fontSize="9" fill="#4be8ff"
          fontFamily="Geist Mono" letterSpacing="1">{liveAgents.reduce((s, a) => s + a.sent24, 0).toLocaleString()} actions today</text>
      </svg>
    </div>
  );
}

Object.assign(window, { Sparkline, BarSeries, Ring, Heatmap, Tag, StatusTag, fakeStream, linePath, areaPath, CosmosDial });
