/* The Orb — visibility instrument.
   6 concentric arcs, each = one AI model. Arc length = mention rate.
   States: dormant | scanning | revealed
*/

// ids MUST match real-models.jsx PROVIDERS / api/health (anthropic/google/perplexity/xai),
// otherwise the orb arcs, per-model rail, and time-series ridges silently drop those models
// because the scan data is keyed by provider id.
const MODELS = [
  { id: 'anthropic',  name: 'Claude',     hue: 28,  short: 'CL' },
  { id: 'openai',     name: 'OpenAI',     hue: 158, short: 'GPT' },
  { id: 'google',     name: 'Gemini',     hue: 278, short: 'GM' },
  { id: 'perplexity', name: 'Perplexity', hue: 218, short: 'PX' },
  { id: 'xai',        name: 'Grok',       hue: 358, short: 'GK' },
  { id: 'deepseek',   name: 'DeepSeek',   hue: 318, short: 'DS' },
];

function modelColor(hue, l = 78, c = 0.17) {
  return `oklch(${l}% ${c} ${hue})`;
}

function Orb({ state = 'dormant', score = 0, models = MODELS, values = {}, scanProgress = {}, size = 480, label, suffix = '', viewTransitionName }) {
  const cx = size / 2;
  const cy = size / 2;
  const startR = size * 0.16;
  const ringGap = size * 0.042;
  const strokeW = Math.max(3.5, size * 0.012);

  // arc length per model based on state
  const arcs = models.map((m, i) => {
    const r = startR + i * ringGap;
    const c = 2 * Math.PI * r;
    let portion = 0;
    if (state === 'dormant') {
      portion = 0.06 + (i % 3) * 0.03; // tiny breath marks
    } else if (state === 'scanning') {
      portion = (scanProgress[m.id] || 0); // 0..(values/100)
    } else {
      portion = (values[m.id] || 0) / 100;
    }
    return { ...m, r, c, drawn: c * portion };
  });

  return (
    <div
      className="orb-wrap"
      style={{
        width: size,
        height: size,
        ...(viewTransitionName ? { viewTransitionName } : {}),
      }}
    >
      <svg
        width={size}
        height={size}
        viewBox={`0 0 ${size} ${size}`}
        className={`orb-svg orb-breathe`}
        style={{ overflow: 'visible' }}
      >
        <defs>
          {models.map((m, i) => (
            <linearGradient key={i} id={`og-${m.id}`} x1="0" y1="0" x2="1" y2="1">
              <stop offset="0%" stopColor={modelColor(m.hue, 82, 0.18)} stopOpacity="1" />
              <stop offset="100%" stopColor={modelColor(m.hue + 30, 70, 0.14)} stopOpacity="0.7" />
            </linearGradient>
          ))}
          <radialGradient id="orb-core-glow" cx="50%" cy="50%" r="50%">
            <stop offset="0%" stopColor="oklch(82% 0.16 var(--accent-h))" stopOpacity="0.5" />
            <stop offset="55%" stopColor="oklch(82% 0.16 var(--accent-h))" stopOpacity="0.06" />
            <stop offset="100%" stopColor="oklch(82% 0.16 var(--accent-h))" stopOpacity="0" />
          </radialGradient>
          <filter id="orb-soft-glow">
            <feGaussianBlur stdDeviation={size * 0.005} />
          </filter>
        </defs>

        {/* central soft glow */}
        <circle cx={cx} cy={cy} r={size * 0.45} fill="url(#orb-core-glow)" />

        {/* tick marks at compass points (every 15deg) */}
        <g opacity={state === 'dormant' ? 0.18 : 0.28}>
          {Array.from({ length: 36 }).map((_, i) => {
            const a = (i * 10 * Math.PI) / 180 - Math.PI / 2;
            const r1 = startR - size * 0.02;
            const r2 = startR - size * (i % 9 === 0 ? 0.04 : 0.028);
            return (
              <line
                key={i}
                x1={cx + r1 * Math.cos(a)}
                y1={cy + r1 * Math.sin(a)}
                x2={cx + r2 * Math.cos(a)}
                y2={cy + r2 * Math.sin(a)}
                stroke={`oklch(60% 0.02 80 / ${i % 9 === 0 ? 0.55 : 0.3})`}
                strokeWidth="1"
                strokeLinecap="round"
              />
            );
          })}
        </g>

        {/* faint outer ring — instrument bezel */}
        <circle
          cx={cx}
          cy={cy}
          r={startR + (models.length - 1) * ringGap + ringGap * 0.6}
          fill="none"
          stroke="oklch(60% 0.02 80 / 0.12)"
          strokeWidth="1"
          strokeDasharray="2 6"
        />

        {/* arcs */}
        {arcs.map((a, i) => (
          <g key={a.id}>
            {/* track */}
            <circle
              cx={cx}
              cy={cy}
              r={a.r}
              fill="none"
              stroke="oklch(35% 0.02 80 / 0.4)"
              strokeWidth={strokeW * 0.45}
              strokeLinecap="round"
            />
            {/* drawn arc */}
            <circle
              cx={cx}
              cy={cy}
              r={a.r}
              fill="none"
              stroke={`url(#og-${a.id})`}
              strokeWidth={strokeW}
              strokeLinecap="round"
              strokeDasharray={`${Math.max(0.5, a.drawn)} ${a.c}`}
              transform={`rotate(-90 ${cx} ${cy})`}
              style={{
                transition: 'stroke-dasharray 900ms cubic-bezier(.55,.05,.2,1)',
                filter: state === 'dormant' ? 'opacity(0.55)' : 'opacity(1)',
              }}
            />
            {/* dot at arc end */}
            {state !== 'dormant' && a.drawn > a.c * 0.04 && (
              <circle
                cx={cx + a.r * Math.cos((a.drawn / a.r) - Math.PI / 2)}
                cy={cy + a.r * Math.sin((a.drawn / a.r) - Math.PI / 2)}
                r={strokeW * 0.85}
                fill={modelColor(a.hue, 88, 0.16)}
                style={{
                  filter: `drop-shadow(0 0 8px ${modelColor(a.hue, 78, 0.2)})`,
                  transition: 'cx 900ms cubic-bezier(.55,.05,.2,1), cy 900ms cubic-bezier(.55,.05,.2,1)',
                }}
              />
            )}
          </g>
        ))}

        {/* inner disc */}
        <circle
          cx={cx}
          cy={cy}
          r={startR - size * 0.03}
          fill="oklch(13% 0.012 80 / 0.85)"
          stroke="oklch(60% 0.02 80 / 0.15)"
          strokeWidth="1"
        />
      </svg>

      <div className="orb-center">
        {state === 'dormant' ? (
          <>
            <div style={{ fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: '0.18em', textTransform: 'uppercase', color: 'var(--fg-3)' }}>
              awaiting input
            </div>
            <div style={{ width: 22, height: 22, marginTop: 14, borderRadius: '50%', background: 'var(--accent-grad)', boxShadow: '0 0 28px oklch(78% 0.16 var(--accent-h) / 0.7)', animation: 'pulse 2.4s ease-in-out infinite' }} />
          </>
        ) : (
          <>
            <div className="orb-score">
              {score}
              {suffix && <span className="orb-suffix">{suffix}</span>}
            </div>
            {label && <div className="orb-label">{label}</div>}
          </>
        )}
      </div>
    </div>
  );
}

/* Per-model legend dots, used elsewhere */
function ModelDots({ models = MODELS, size = 12 }) {
  return (
    <div style={{ display: 'inline-flex', gap: 6, alignItems: 'center' }}>
      {models.map((m) => (
        <span
          key={m.id}
          title={m.name}
          style={{
            width: size,
            height: size,
            borderRadius: '50%',
            background: modelColor(m.hue),
            boxShadow: `0 0 8px ${modelColor(m.hue, 78, 0.18)}`,
            display: 'inline-block',
          }}
        />
      ))}
    </div>
  );
}

Object.assign(window, { Orb, ModelDots, MODELS, modelColor });
