// Shared atoms — chart/timeline primitives used across all 3 dashboard variants.
// Pure visuals only; each variant wraps them in its own chrome.

const { useMemo, useState, useEffect, useRef } = React;

// ─── Equity overlay (the comparison hero) ─────────────────────────
function EquityOverlay({ data, bots, height = 280, width = 920, selectedDate, onPickDate, showAxis = true, showLegend = true, showZero = true }) {
  // data: { [botId]: [{date, equity, pnlPct}] }
  // Normalize as % return from start so the 3 accounts can be compared on one axis.
  const series = bots.map((b) => {
    const pts = data[b.id];
    const start = pts[0].equity;
    return {
      bot: b,
      points: pts.map((p, i) => ({ ...p, retPct: (p.equity / start - 1) * 100, idx: i })),
    };
  });
  const allRet = series.flatMap((s) => s.points.map((p) => p.retPct));
  const minR = Math.min(...allRet, -1);
  const maxR = Math.max(...allRet, 1);
  const padR = (maxR - minR) * 0.12;
  const yMin = minR - padR, yMax = maxR + padR;

  const padL = showAxis ? 44 : 8;
  const padR_ = 16, padT = 14, padB = showAxis ? 28 : 10;
  const W = width, H = height;
  const innerW = W - padL - padR_;
  const innerH = H - padT - padB;
  const N = series[0].points.length;

  const xFor = (i) => padL + (i / (N - 1)) * innerW;
  const yFor = (v) => padT + (1 - (v - yMin) / (yMax - yMin)) * innerH;

  const pathFor = (pts) => pts.map((p, i) => `${i === 0 ? 'M' : 'L'}${xFor(i).toFixed(2)},${yFor(p.retPct).toFixed(2)}`).join(' ');

  const yTicks = [];
  const step = niceStep((yMax - yMin) / 4);
  let t = Math.ceil(yMin / step) * step;
  while (t <= yMax) { yTicks.push(t); t += step; }

  // x-axis labels: ~6 evenly spaced
  const xTickIdx = [];
  for (let i = 0; i < 6; i++) xTickIdx.push(Math.round((i / 5) * (N - 1)));

  const selIdx = selectedDate ? series[0].points.findIndex((p) => p.date === selectedDate) : -1;

  return (
    <svg viewBox={`0 0 ${W} ${H}`} width="100%" height={H} style={{ display: 'block', overflow: 'visible' }}>
      {/* grid */}
      {yTicks.map((v) => (
        <g key={v}>
          <line x1={padL} x2={W - padR_} y1={yFor(v)} y2={yFor(v)} stroke="#1a1f29" strokeWidth="1" />
          {showAxis && (
            <text x={padL - 8} y={yFor(v) + 4} fill="#5b6473" fontSize="20" fontFamily="ui-monospace, 'JetBrains Mono', monospace" textAnchor="end">
              {v >= 0 ? '+' : ''}{v.toFixed(1)}%
            </text>
          )}
        </g>
      ))}
      {showZero && yMin < 0 && yMax > 0 && (
        <line x1={padL} x2={W - padR_} y1={yFor(0)} y2={yFor(0)} stroke="#2b323d" strokeDasharray="3 3" />
      )}

      {/* x-axis labels */}
      {showAxis && xTickIdx.map((i) => (
        <text key={i} x={xFor(i)} y={H - 10} fill="#5b6473" fontSize="18" fontFamily="ui-monospace, 'JetBrains Mono', monospace" textAnchor="middle">
          {fmtDateShort(series[0].points[i].date)}
        </text>
      ))}

      {/* selected date guide */}
      {selIdx >= 0 && (
        <line x1={xFor(selIdx)} x2={xFor(selIdx)} y1={padT} y2={H - padB} stroke="#22c55e" strokeOpacity="0.45" strokeWidth="1" strokeDasharray="2 3" />
      )}

      {/* series — soft glow under top line */}
      {series.map((s) => (
        <path key={s.bot.id} d={pathFor(s.points)} fill="none" stroke={s.bot.color} strokeWidth="1.6" strokeLinejoin="round" strokeLinecap="round" />
      ))}

      {/* selected dot per series */}
      {selIdx >= 0 && series.map((s) => (
        <circle key={s.bot.id + '-d'} cx={xFor(selIdx)} cy={yFor(s.points[selIdx].retPct)} r="3.5" fill={s.bot.color} stroke="#0a0d12" strokeWidth="1.5" />
      ))}

      {/* clickable verticals */}
      {onPickDate && series[0].points.map((p, i) => (
        <rect key={p.date} x={xFor(i) - innerW / N / 2} y={padT} width={innerW / N} height={innerH} fill="transparent" style={{ cursor: 'pointer' }} onClick={() => onPickDate(p.date)} />
      ))}

      {/* legend */}
      {showLegend && (
        <g transform={`translate(${padL}, ${padT - 2})`}>
          {bots.map((b, i) => (
            <g key={b.id} transform={`translate(${i * 130}, 0)`}>
              <rect x="0" y="-9" width="10" height="2" fill={b.color} />
              <text x="14" y="-5" fill="#9aa3b2" fontSize="20" fontFamily="ui-monospace, 'JetBrains Mono', monospace">
                {b.name.toUpperCase()} {(() => {
                  const last = series[i].points[series[i].points.length - 1].retPct;
                  return `${last >= 0 ? '+' : ''}${last.toFixed(2)}%`;
                })()}
              </text>
            </g>
          ))}
        </g>
      )}
    </svg>
  );
}

function niceStep(raw) {
  const exp = Math.floor(Math.log10(raw));
  const base = Math.pow(10, exp);
  const m = raw / base;
  let nice = 1;
  if (m < 1.5) nice = 1;
  else if (m < 3) nice = 2;
  else if (m < 7) nice = 5;
  else nice = 10;
  return nice * base;
}

function fmtDateShort(s) {
  const d = new Date(s + 'T00:00:00Z');
  return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', timeZone: 'UTC' });
}

function fmtDateLong(s) {
  const d = new Date(s + 'T00:00:00Z');
  return d.toLocaleDateString('en-US', { weekday: 'short', month: 'long', day: 'numeric', year: 'numeric', timeZone: 'UTC' });
}

// ─── Sparkline ────────────────────────────────────────────────────
function Sparkline({ values, color, width = 120, height = 32, fill = false }) {
  if (!values.length) return null;
  const min = Math.min(...values, 0);
  const max = Math.max(...values, 0);
  const range = max - min || 1;
  const x = (i) => (i / (values.length - 1)) * width;
  const y = (v) => height - ((v - min) / range) * (height - 4) - 2;
  const d = values.map((v, i) => `${i === 0 ? 'M' : 'L'}${x(i).toFixed(2)},${y(v).toFixed(2)}`).join(' ');
  const area = fill ? `${d} L${x(values.length - 1).toFixed(2)},${height} L0,${height} Z` : null;
  return (
    <svg viewBox={`0 0 ${width} ${height}`} width={width} height={height} style={{ display: 'block' }}>
      {fill && <path d={area} fill={color} fillOpacity="0.12" />}
      <path d={d} fill="none" stroke={color} strokeWidth="1.4" strokeLinejoin="round" strokeLinecap="round" />
      {/* zero line */}
      {min < 0 && max > 0 && (
        <line x1="0" x2={width} y1={y(0)} y2={y(0)} stroke="#2b323d" strokeDasharray="2 2" />
      )}
    </svg>
  );
}

// ─── Date ribbon ─────────────────────────────────────────────────
function DateRibbon({ days, dailyPnLByBot, selected, onSelect, bots }) {
  // Each cell shows date; combined avg-pnl across bots colors a tiny bar.
  const ribbonRef = useRef(null);

  useEffect(() => {
    // Auto-scroll selected into view
    if (!ribbonRef.current) return;
    const el = ribbonRef.current.querySelector(`[data-day="${selected}"]`);
    if (el) el.scrollIntoView({ behavior: 'auto', inline: 'center', block: 'nearest' });
  }, [selected]);

  return (
    <div ref={ribbonRef} style={{
      display: 'flex', gap: 4, overflowX: 'auto', overflowY: 'hidden', paddingBottom: 4,
      scrollbarWidth: 'thin', scrollSnapType: 'x mandatory',
    }}>
      {days.map((d) => {
        const isSel = d === selected;
        const heliosPnl = (dailyPnLByBot.helios.find((x) => x.date === d) || {}).pnlPct ?? 0;
        const atlasPnl = (dailyPnLByBot.atlas.find((x) => x.date === d) || {}).pnlPct ?? 0;
        const orionPnl = (dailyPnLByBot.orion.find((x) => x.date === d) || {}).pnlPct ?? 0;
        const avg = (heliosPnl + atlasPnl + orionPnl) / 3;
        const dt = new Date(d + 'T00:00:00Z');
        const wd = dt.toLocaleDateString('en-US', { weekday: 'short', timeZone: 'UTC' }).slice(0, 1);
        const dn = dt.getUTCDate();
        const month = dt.toLocaleDateString('en-US', { month: 'short', timeZone: 'UTC' });
        return (
          <button
            key={d}
            data-day={d}
            onClick={() => onSelect(d)}
            style={{
              flex: '0 0 auto',
              background: isSel ? 'rgba(34,197,94,0.10)' : 'transparent',
              border: isSel ? '1px solid rgba(34,197,94,0.55)' : '1px solid #1a1f29',
              borderRadius: 6,
              padding: '7px 10px',
              cursor: 'pointer',
              color: isSel ? '#22c55e' : '#9aa3b2',
              display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4,
              minWidth: 56, scrollSnapAlign: 'center',
              fontFamily: 'ui-monospace, "JetBrains Mono", monospace',
              transition: 'background .12s, border-color .12s, color .12s',
            }}
            onMouseEnter={(e) => { if (!isSel) { e.currentTarget.style.borderColor = '#2b323d'; e.currentTarget.style.color = '#d4d8df'; } }}
            onMouseLeave={(e) => { if (!isSel) { e.currentTarget.style.borderColor = '#1a1f29'; e.currentTarget.style.color = '#9aa3b2'; } }}
          >
            <div style={{ fontSize: 17, opacity: 0.7, letterSpacing: '0.08em' }}>{month.toUpperCase()}</div>
            <div style={{ fontSize: 27, fontWeight: 600 }}>{String(dn).padStart(2, '0')}</div>
            <div style={{ fontSize: 17, opacity: 0.55 }}>{wd}</div>
            <div style={{
              width: 28, height: 3, borderRadius: 2,
              background: avg >= 0 ? `rgba(34,197,94,${Math.min(0.85, 0.25 + Math.abs(avg) * 0.5)})` : `rgba(239,68,68,${Math.min(0.85, 0.25 + Math.abs(avg) * 0.5)})`,
            }} />
          </button>
        );
      })}
    </div>
  );
}

// ─── Status dot ───────────────────────────────────────────────────
function StatusDot({ status }) {
  const c = status === 'live' ? '#22c55e' : status === 'degraded' ? '#f59e0b' : '#ef4444';
  return (
    <span style={{ position: 'relative', display: 'inline-flex', width: 8, height: 8 }}>
      <span style={{
        position: 'absolute', inset: 0, borderRadius: '50%', background: c,
        boxShadow: `0 0 0 2px ${c}33`,
        animation: status === 'live' ? 'bot-pulse 2.2s ease-in-out infinite' : 'none',
      }} />
    </span>
  );
}

// ─── Decision pill (BUY/SELL/SKIP/etc.) ──────────────────────────
function ActionPill({ action }) {
  const isBuy = /BUY|CALL|SCALE/.test(action);
  const isSell = /SELL|PUT|CLOSE/.test(action);
  const isSkip = action === 'SKIP';
  const c = isSkip ? '#6b7280' : isBuy ? '#22c55e' : isSell ? '#ef4444' : '#9aa3b2';
  return (
    <span style={{
      fontFamily: 'ui-monospace, "JetBrains Mono", monospace',
      fontSize: 18, letterSpacing: '0.06em', fontWeight: 600,
      color: c, background: `${c}1f`, border: `1px solid ${c}55`,
      padding: '2px 6px', borderRadius: 3, whiteSpace: 'nowrap',
    }}>{action}</span>
  );
}

// ─── Vertical decision timeline ───────────────────────────────────
function DecisionTimeline({ decisions, bots, dense = false, showBot = true, height = null }) {
  const byId = Object.fromEntries(bots.map((b) => [b.id, b]));
  return (
    <div style={{
      position: 'relative',
      maxHeight: height || 'unset',
      overflowY: height ? 'auto' : 'visible',
      paddingLeft: 2,
    }}>
      {/* center rail */}
      <div style={{ position: 'absolute', left: 13, top: 4, bottom: 4, width: 1, background: '#1a1f29' }} />
      {decisions.map((d, idx) => {
        const bot = byId[d.bot];
        const pnlColor = d.pnl > 0 ? '#22c55e' : d.pnl < 0 ? '#ef4444' : '#6b7280';
        return (
          <div key={d.id} style={{
            position: 'relative', paddingLeft: 36, paddingRight: 4,
            paddingTop: dense ? 6 : 10, paddingBottom: dense ? 6 : 10,
            borderBottom: idx === decisions.length - 1 ? 'none' : '1px solid #11151c',
          }}>
            <div style={{
              position: 'absolute', left: 8, top: dense ? 11 : 16,
              width: 12, height: 12, borderRadius: '50%',
              background: bot.color, boxShadow: `0 0 0 3px #0a0d12, 0 0 0 4px ${bot.color}33`,
            }} />
            <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, alignItems: 'baseline' }}>
              <div style={{ display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }}>
                <span style={{ fontFamily: 'ui-monospace, "JetBrains Mono", monospace', fontSize: 20, color: '#6b7280' }}>{d.time}</span>
                {showBot && (
                  <span style={{ fontFamily: 'ui-monospace, "JetBrains Mono", monospace', fontSize: 18, color: bot.color, letterSpacing: '0.08em' }}>
                    {bot.name.toUpperCase()}
                  </span>
                )}
                <ActionPill action={d.action} />
                <span style={{ fontFamily: 'ui-monospace, "JetBrains Mono", monospace', fontSize: 21, color: '#d4d8df', fontWeight: 600 }}>{d.symbol}</span>
                <span style={{ fontFamily: 'ui-monospace, "JetBrains Mono", monospace', fontSize: 20, color: '#6b7280' }}>{d.qty} @ ${d.price}</span>
              </div>
              {d.action !== 'SKIP' && (
                <span style={{ fontFamily: 'ui-monospace, "JetBrains Mono", monospace', fontSize: 20, color: pnlColor, fontWeight: 600 }}>
                  {d.pnl >= 0 ? '+' : ''}{d.pnl.toFixed(2)}
                </span>
              )}
            </div>
            <div style={{ fontFamily: 'Inter, system-ui, sans-serif', fontSize: 20, color: '#9aa3b2', marginTop: 4, lineHeight: 1.5 }}>
              {d.reason}
            </div>
          </div>
        );
      })}
      {decisions.length === 0 && (
        <div style={{ padding: 24, color: '#5b6473', fontSize: 21, fontFamily: 'ui-monospace, monospace' }}>
          — no decisions logged for this day —
        </div>
      )}
    </div>
  );
}

// expose
Object.assign(window, {
  EquityOverlay, Sparkline, DateRibbon, StatusDot, ActionPill, DecisionTimeline,
  fmtDateShort, fmtDateLong,
});
