import { useState, useEffect, useRef } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import {
  LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, ReferenceLine,
} from 'recharts';
import {
  LineChart as LineChartIcon, Play, Pause, RotateCcw, Plus, Trash2, X, CheckCircle,
  XCircle, Clock, Loader, AlertTriangle, Activity,
  ChevronDown, RefreshCw, ScrollText, Shield, Cpu, Square,
} from 'lucide-react';
import {
  paperApi,
  type PaperSession,
  type PaperTask,
  type PaperTrade,
} from '../api/client';
import { Loading, ErrorState } from '../components/common/Loading';
import { classifyTradeSleeve, tradeSleeveLabel, type TradeSleeve } from '../lib/tradeSleeves';
import { ansiToHtml } from '../lib/utils';

// ── Shared styles ────────────────────────────────────────────────────────────

const card: React.CSSProperties = {
  background: 'var(--bg1)',
  border: '1px solid var(--border)',
  borderRadius: 12,
  overflow: 'hidden',
};

const inputStyle: React.CSSProperties = {
  width: '100%',
  padding: '8px 11px',
  fontSize: 14,
  fontFamily: 'var(--font-mono)',
  background: 'var(--bg2)',
  border: '1px solid var(--border-md)',
  borderRadius: 7,
  color: 'var(--text1)',
  outline: 'none',
};

const btn = (variant: 'primary' | 'danger' | 'ghost' | 'outline' = 'outline'): React.CSSProperties => ({
  display: 'inline-flex',
  alignItems: 'center',
  gap: 6,
  padding: '7px 14px',
  fontSize: 13,
  fontWeight: 500,
  borderRadius: 7,
  border: '1px solid',
  cursor: 'pointer',
  transition: 'all 0.12s',
  whiteSpace: 'nowrap' as const,
  background: variant === 'primary' ? 'var(--cyan)' : variant === 'danger' ? 'var(--red)' : 'transparent',
  color: variant === 'primary' ? '#fff' : variant === 'danger' ? '#fff' : variant === 'ghost' ? 'var(--text3)' : 'var(--text2)',
  borderColor: variant === 'primary' ? 'var(--cyan)' : variant === 'danger' ? 'var(--red)' : 'var(--border-md)',
});

// ── Helpers ──────────────────────────────────────────────────────────────────

function fmtMoney(v: number | null | undefined, decimals = 2): string {
  if (v == null) return '—';
  const sign = v >= 0 ? '+' : '';
  return `${sign}$${Math.abs(v).toLocaleString('en-US', { minimumFractionDigits: decimals, maximumFractionDigits: decimals })}`;
}

function fmtPct(v: number | null | undefined, decimals = 2): string {
  if (v == null) return '—';
  const sign = v >= 0 ? '+' : '';
  return `${sign}${v.toFixed(decimals)}%`;
}

function fmtPrice(v: number | null | undefined): string {
  if (v == null) return '—';
  return `$${v.toFixed(2)}`;
}

function pnlColor(v: number | null | undefined): string {
  if (v == null) return 'var(--text3)';
  return v >= 0 ? 'var(--green)' : 'var(--red)';
}

function StatusBadge({ status }: { status: string }) {
  const map: Record<string, { color: string; bg: string }> = {
    active: { color: 'var(--green)', bg: 'var(--green-dim)' },
    paused: { color: 'var(--gold)', bg: 'var(--gold-dim)' },
    closed: { color: 'var(--text3)', bg: 'var(--bg2)' },
  };
  const { color, bg } = map[status] ?? map.closed;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 5,
      padding: '2px 9px', borderRadius: 20,
      fontSize: 11, fontFamily: 'var(--font-mono)', fontWeight: 600, letterSpacing: '0.06em',
      background: bg, color,
    }}>
      <span style={{ width: 5, height: 5, borderRadius: '50%', background: color, display: 'inline-block' }} />
      {status.toUpperCase()}
    </span>
  );
}

function TaskStatusIcon({ status }: { status: PaperTask['status'] }) {
  if (status === 'running') return <Loader size={13} style={{ color: 'var(--cyan)', animation: 'spin 1s linear infinite' }} />;
  if (status === 'completed') return <CheckCircle size={13} style={{ color: 'var(--green)' }} />;
  if (status === 'failed') return <XCircle size={13} style={{ color: 'var(--red)' }} />;
  return <Clock size={13} style={{ color: 'var(--text3)' }} />;
}

function KillSwitchBadge({ on }: { on: boolean }) {
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 5,
      padding: '2px 9px', borderRadius: 20,
      fontSize: 11, fontFamily: 'var(--font-mono)', fontWeight: 600,
      background: on ? 'var(--red-dim)' : 'var(--green-dim)',
      color: on ? 'var(--red)' : 'var(--green)',
    }}>
      <Shield size={10} /> {on ? 'KILL SW ON' : 'OK'}
    </span>
  );
}

function SleeveBadge({ sleeve }: { sleeve: TradeSleeve }) {
  const tone = sleeve === 'parking'
    ? { color: 'var(--gold)', bg: 'var(--gold-dim)' }
    : sleeve === 'ownership'
      ? { color: 'var(--violet, var(--cyan))', bg: 'color-mix(in srgb, var(--violet, var(--cyan)) 12%, transparent)' }
    : sleeve === 'risk_off_alpha'
      ? { color: 'var(--orange)', bg: 'color-mix(in srgb, var(--orange) 12%, transparent)' }
    : sleeve === 'idle_alpha'
      ? { color: 'var(--cyan)', bg: 'var(--cyan-dim)' }
      : { color: 'var(--text2)', bg: 'var(--bg2)' };
  return (
    <span style={{
      display: 'inline-flex',
      alignItems: 'center',
      padding: '2px 8px',
      borderRadius: 999,
      fontFamily: 'var(--font-mono)',
      fontSize: 11,
      fontWeight: 600,
      letterSpacing: '0.04em',
      color: tone.color,
      background: tone.bg,
      whiteSpace: 'nowrap',
    }}>
      {tradeSleeveLabel(sleeve)}
    </span>
  );
}

// ── Stat Card ────────────────────────────────────────────────────────────────

function StatCard({ label, value, sub, valueColor }: {
  label: string; value: string; sub?: string; valueColor?: string
}) {
  return (
    <div style={{
      background: 'var(--bg2)', borderRadius: 10, padding: '14px 18px',
      display: 'flex', flexDirection: 'column', gap: 4,
    }}>
      <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text3)', letterSpacing: '0.08em', textTransform: 'uppercase' }}>
        {label}
      </div>
      <div style={{ fontSize: 20, fontWeight: 700, fontFamily: 'var(--font-mono)', color: valueColor ?? 'var(--text1)' }}>
        {value}
      </div>
      {sub && <div style={{ fontSize: 12, color: 'var(--text3)', fontFamily: 'var(--font-mono)' }}>{sub}</div>}
    </div>
  );
}

// ── Create Session Modal ──────────────────────────────────────────────────────

function CreateSessionModal({ onClose, onCreated }: {
  onClose: () => void;
  onCreated: (session: { session_id: string; name: string }) => void;
}) {
  const [name, setName] = useState('');
  const [configSearch, setConfigSearch] = useState('');
  const [selectedConfig, setSelectedConfig] = useState('');
  const [capital, setCapital] = useState('10000');
  const [parking, setParking] = useState('');
  const [idleAlpha, setIdleAlpha] = useState('');
  const [form4Sleeve, setForm4Sleeve] = useState('');
  const [ownershipSleeve, setOwnershipSleeve] = useState('');
  const [riskOffSleeve, setRiskOffSleeve] = useState('');
  const [configOpen, setConfigOpen] = useState(false);
  const dropRef = useRef<HTMLDivElement>(null);

  const { data: cfgData, isLoading: cfgLoading } = useQuery({
    queryKey: ['paper-configs', configSearch],
    queryFn: () => paperApi.configs({ pattern: configSearch || undefined, limit: 100 }),
    staleTime: 60_000,
  });

  const { data: parkingPresetsData } = useQuery({
    queryKey: ['parking-presets'],
    queryFn: () => paperApi.parkingPresets(),
    staleTime: 300_000,
  });
  const { data: idleAlphaPresetsData } = useQuery({
    queryKey: ['idle-alpha-presets'],
    queryFn: () => paperApi.idleAlphaPresets(),
    staleTime: 300_000,
  });
  const { data: form4PresetsData } = useQuery({
    queryKey: ['form4-capture-presets'],
    queryFn: () => paperApi.form4CapturePresets(),
    staleTime: 300_000,
  });
  const { data: ownershipPresetsData } = useQuery({
    queryKey: ['ownership-capture-presets'],
    queryFn: () => paperApi.ownershipCapturePresets(),
    staleTime: 300_000,
  });
  const { data: riskOffPresetsData } = useQuery({
    queryKey: ['risk-off-alpha-presets'],
    queryFn: () => paperApi.riskOffAlphaPresets(),
    staleTime: 300_000,
  });

  const qc = useQueryClient();
  const { mutate, isPending, error } = useMutation({
    mutationFn: () =>
      paperApi.createSession(
        name.trim(),
        selectedConfig,
        parseFloat(capital) || 10000,
        parking || null,
        idleAlpha || null,
        form4Sleeve || null,
        ownershipSleeve || null,
        riskOffSleeve || null,
      ),
    onSuccess: (data) => {
      qc.invalidateQueries({ queryKey: ['paper-sessions'] });
      onCreated({ session_id: data.session_id, name: data.name });
    },
  });

  // Close dropdown on outside click
  useEffect(() => {
    function handle(e: MouseEvent) {
      if (dropRef.current && !dropRef.current.contains(e.target as Node)) {
        setConfigOpen(false);
      }
    }
    document.addEventListener('mousedown', handle);
    return () => document.removeEventListener('mousedown', handle);
  }, []);

  const filtered = cfgData?.configs ?? [];
  const canSubmit = name.trim() && selectedConfig && parseFloat(capital) > 0;

  return (
    <div style={{
      position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.35)', zIndex: 100,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
    }} onClick={onClose}>
      <div style={{
        background: 'var(--bg1)', borderRadius: 14, padding: 28, width: 480,
        border: '1px solid var(--border-md)', boxShadow: '0 8px 40px rgba(0,0,0,0.15)',
      }} onClick={e => e.stopPropagation()}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 22 }}>
          <h2 style={{ fontSize: 18, fontWeight: 700, color: 'var(--text1)' }}>New Paper Trading Session</h2>
          <button onClick={onClose} style={{ ...btn('ghost'), padding: '4px 8px', border: 'none' }}>
            <X size={16} />
          </button>
        </div>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          {/* Session name */}
          <div>
            <label style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text3)', display: 'block', marginBottom: 6, letterSpacing: '0.06em' }}>
              SESSION NAME *
            </label>
            <input
              style={inputStyle}
              placeholder="my_session_v1"
              value={name}
              onChange={e => setName(e.target.value)}
            />
          </div>

          {/* Strategy config */}
          <div>
            <label style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text3)', display: 'block', marginBottom: 6, letterSpacing: '0.06em' }}>
              STRATEGY CONFIG *
            </label>
            <div ref={dropRef} style={{ position: 'relative' }}>
              <div
                onClick={() => setConfigOpen(!configOpen)}
                style={{
                  ...inputStyle,
                  cursor: 'pointer',
                  display: 'flex',
                  justifyContent: 'space-between',
                  alignItems: 'center',
                  userSelect: 'none',
                }}
              >
                <span style={{ color: selectedConfig ? 'var(--text1)' : 'var(--text3)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                  {selectedConfig || 'Select or type config name…'}
                </span>
                <ChevronDown size={14} style={{ flexShrink: 0, color: 'var(--text3)' }} />
              </div>
              {configOpen && (
                <div style={{
                  position: 'absolute', top: '100%', left: 0, right: 0, zIndex: 10,
                  background: 'var(--bg1)', border: '1px solid var(--border-md)',
                  borderRadius: 8, boxShadow: '0 4px 20px rgba(0,0,0,0.12)',
                  maxHeight: 280, overflow: 'hidden', display: 'flex', flexDirection: 'column',
                }}>
                  <div style={{ padding: '8px 10px', borderBottom: '1px solid var(--border)' }}>
                    <input
                      style={{ ...inputStyle, padding: '5px 9px', fontSize: 13 }}
                      placeholder="Search configs…"
                      value={configSearch}
                      onChange={e => setConfigSearch(e.target.value)}
                      autoFocus
                      onClick={e => e.stopPropagation()}
                    />
                  </div>
                  <div style={{ overflowY: 'auto', flex: 1 }}>
                    {cfgLoading && <div style={{ padding: '12px 14px', color: 'var(--text3)', fontSize: 13 }}>Loading…</div>}
                    {/* Also allow manual entry */}
                    {configSearch && !filtered.find(c => c.name === configSearch) && (
                      <div
                        onClick={() => { setSelectedConfig(configSearch); setConfigOpen(false); }}
                        style={{
                          padding: '9px 14px', cursor: 'pointer', fontSize: 13,
                          fontFamily: 'var(--font-mono)', color: 'var(--cyan)',
                          borderBottom: '1px solid var(--border)',
                        }}
                      >
                        Use "{configSearch}" directly
                      </div>
                    )}
                    {filtered.map(c => (
                      <div
                        key={c.name}
                        onClick={() => { setSelectedConfig(c.name); setConfigOpen(false); }}
                        style={{
                          padding: '8px 14px', cursor: 'pointer',
                          fontSize: 13, fontFamily: 'var(--font-mono)',
                          color: c.name === selectedConfig ? 'var(--cyan)' : 'var(--text1)',
                          background: c.name === selectedConfig ? 'var(--cyan-dim)' : 'transparent',
                          display: 'flex', justifyContent: 'space-between', alignItems: 'center',
                        }}
                        onMouseEnter={e => (e.currentTarget.style.background = 'var(--bg2)')}
                        onMouseLeave={e => (e.currentTarget.style.background = c.name === selectedConfig ? 'var(--cyan-dim)' : 'transparent')}
                      >
                        <span style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>{c.name}</span>
                        {c.id != null && <span style={{ color: 'var(--text3)', fontSize: 11, flexShrink: 0, marginLeft: 8 }}>#{c.id}</span>}
                      </div>
                    ))}
                  </div>
                </div>
              )}
            </div>
          </div>

          {/* Capital */}
          <div>
            <label style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text3)', display: 'block', marginBottom: 6, letterSpacing: '0.06em' }}>
              INITIAL CAPITAL ($)
            </label>
            <input
              style={inputStyle}
              type="number"
              min="100"
              step="1000"
              value={capital}
              onChange={e => setCapital(e.target.value)}
            />
          </div>

          {/* Cash Parking */}
          <div>
            <label style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text3)', display: 'block', marginBottom: 6, letterSpacing: '0.06em' }}>
              CASH PARKING <span style={{ opacity: 0.5 }}>(optional)</span>
            </label>
            <select
              value={parking}
              onChange={e => setParking(e.target.value)}
              style={{
                ...inputStyle,
                fontSize: 13,
                color: parking ? 'var(--orange)' : 'var(--text3)',
                cursor: 'pointer',
              }}
            >
              <option value="">— none —</option>
              {parkingPresetsData
                ? Object.entries(parkingPresetsData.groups).map(([group, names]) => (
                    <optgroup key={group} label={group}>
                      {(names as string[]).map(preset => (
                        <option key={preset} value={preset}>{preset}</option>
                      ))}
                    </optgroup>
                  ))
                : null}
            </select>
            {parking && (
              <div style={{ marginTop: 5, fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>
                Idle cash will be parked per <span style={{ color: 'var(--orange)' }}>{parking}</span> preset rules
              </div>
            )}
          </div>

          {/* Idle Alpha */}
          <div>
            <label style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text3)', display: 'block', marginBottom: 6, letterSpacing: '0.06em' }}>
              IDLE ALPHA <span style={{ opacity: 0.5 }}>(optional)</span>
            </label>
            <select
              value={idleAlpha}
              onChange={e => setIdleAlpha(e.target.value)}
              style={{
                ...inputStyle,
                fontSize: 13,
                color: idleAlpha ? 'var(--green)' : 'var(--text3)',
                cursor: 'pointer',
              }}
            >
              <option value="">— none —</option>
              {idleAlphaPresetsData
                ? Object.entries(idleAlphaPresetsData.groups).map(([group, names]) => (
                    <optgroup key={group} label={group}>
                      {(names as string[]).map(preset => (
                        <option key={preset} value={preset}>{preset}</option>
                      ))}
                    </optgroup>
                  ))
                : null}
            </select>
            {idleAlpha && (
              <div style={{ marginTop: 5, fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>
                Residual cash can also flow into <span style={{ color: 'var(--green)' }}>{idleAlpha}</span> post-core event engines
              </div>
            )}
          </div>

          {/* Form 4 Sleeve */}
          <div>
            <label style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text3)', display: 'block', marginBottom: 6, letterSpacing: '0.06em' }}>
              FORM 4 SLEEVE <span style={{ opacity: 0.5 }}>(optional)</span>
            </label>
            <select
              value={form4Sleeve}
              onChange={e => setForm4Sleeve(e.target.value)}
              style={{
                ...inputStyle,
                fontSize: 13,
                color: form4Sleeve ? 'var(--cyan)' : 'var(--text3)',
                cursor: 'pointer',
              }}
            >
              <option value="">— none —</option>
              {form4PresetsData
                ? Object.entries(form4PresetsData.groups).map(([group, names]) => (
                    <optgroup key={group} label={group}>
                      {(names as string[]).map(preset => (
                        <option key={preset} value={preset}>{preset}</option>
                      ))}
                    </optgroup>
                  ))
                : null}
            </select>
            {form4Sleeve && (
              <div style={{ marginTop: 5, fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>
                Residual cash can also flow into <span style={{ color: 'var(--cyan)' }}>{form4Sleeve}</span> insider cluster entries
              </div>
            )}
          </div>

          {/* Ownership Sleeve */}
          <div>
            <label style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text3)', display: 'block', marginBottom: 6, letterSpacing: '0.06em' }}>
              OWNERSHIP SLEEVE <span style={{ opacity: 0.5 }}>(optional)</span>
            </label>
            <select
              value={ownershipSleeve}
              onChange={e => setOwnershipSleeve(e.target.value)}
              style={{
                ...inputStyle,
                fontSize: 13,
                color: ownershipSleeve ? 'var(--violet, var(--cyan))' : 'var(--text3)',
                cursor: 'pointer',
              }}
            >
              <option value="">— none —</option>
              {ownershipPresetsData
                ? Object.entries(ownershipPresetsData.groups).map(([group, names]) => (
                    <optgroup key={group} label={group}>
                      {(names as string[]).map(preset => (
                        <option key={preset} value={preset}>{preset}</option>
                      ))}
                    </optgroup>
                  ))
                : null}
            </select>
            {ownershipSleeve && (
              <div style={{ marginTop: 5, fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>
                Reserve cash can also flow into <span style={{ color: 'var(--violet, var(--cyan))' }}>{ownershipSleeve}</span> 13D/13G ownership entries
              </div>
            )}
          </div>

          {/* Risk-Off Alpha Sleeve */}
          <div>
            <label style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text3)', display: 'block', marginBottom: 6, letterSpacing: '0.06em' }}>
              RISK-OFF ALPHA <span style={{ opacity: 0.5 }}>(optional)</span>
            </label>
            <select
              value={riskOffSleeve}
              onChange={e => setRiskOffSleeve(e.target.value)}
              style={{
                ...inputStyle,
                fontSize: 13,
                color: riskOffSleeve ? 'var(--orange)' : 'var(--text3)',
                cursor: 'pointer',
              }}
            >
              <option value="">— none —</option>
              {riskOffPresetsData
                ? Object.entries(riskOffPresetsData.groups).map(([group, names]) => (
                    <optgroup key={group} label={group}>
                      {(names as string[]).map(preset => (
                        <option key={preset} value={preset}>{preset}</option>
                      ))}
                    </optgroup>
                  ))
                : null}
            </select>
            {riskOffSleeve && (
              <div style={{ marginTop: 5, fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>
                Risk-off parking can also deploy into <span style={{ color: 'var(--orange)' }}>{riskOffSleeve}</span> crisis assets
              </div>
            )}
          </div>

          {error && (
            <div style={{ padding: '10px 12px', background: 'var(--red-dim)', borderRadius: 7, fontSize: 13, color: 'var(--red)' }}>
              {(error as Error).message}
            </div>
          )}

          <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end', marginTop: 4 }}>
            <button style={btn('outline')} onClick={onClose}>Cancel</button>
            <button
              style={{ ...btn('primary'), opacity: (!canSubmit || isPending) ? 0.5 : 1 }}
              onClick={() => canSubmit && mutate()}
              disabled={!canSubmit || isPending}
            >
              {isPending ? <><Loader size={13} /> Creating…</> : <><Plus size={13} /> Create Session</>}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ── Close Confirm Modal ───────────────────────────────────────────────────────

function CloseConfirmModal({ session, onClose, onConfirm }: {
  session: PaperSession;
  onClose: () => void;
  onConfirm: () => void;
}) {
  return (
    <div style={{
      position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.35)', zIndex: 100,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
    }} onClick={onClose}>
      <div style={{
        background: 'var(--bg1)', borderRadius: 14, padding: 28, width: 420,
        border: '1px solid var(--border-md)', boxShadow: '0 8px 40px rgba(0,0,0,0.15)',
      }} onClick={e => e.stopPropagation()}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 14 }}>
          <AlertTriangle size={18} style={{ color: 'var(--red)' }} />
          <h2 style={{ fontSize: 16, fontWeight: 700, color: 'var(--text1)' }}>Close Session?</h2>
        </div>
        <p style={{ fontSize: 14, color: 'var(--text2)', lineHeight: 1.6, marginBottom: 20 }}>
          This will <strong>liquidate all Alpaca positions</strong> and permanently delete session
          <strong> "{session.session_name}"</strong> and all its trade history.
          This cannot be undone.
        </p>
        <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end' }}>
          <button style={btn('outline')} onClick={onClose}>Cancel</button>
          <button style={btn('danger')} onClick={onConfirm}>
            <Trash2 size={13} /> Close & Delete
          </button>
        </div>
      </div>
    </div>
  );
}

// ── Session List Item ─────────────────────────────────────────────────────────

function SessionItem({ session, selected, onClick }: {
  session: PaperSession;
  selected: boolean;
  onClick: () => void;
}) {
  const pnlPct = session.total_pnl_pct;
  return (
    <div
      onClick={onClick}
      style={{
        padding: '13px 16px',
        cursor: 'pointer',
        borderBottom: '1px solid var(--border)',
        background: selected ? 'var(--cyan-dim)' : 'transparent',
        borderLeft: `3px solid ${selected ? 'var(--cyan)' : 'transparent'}`,
        transition: 'all 0.1s',
      }}
      onMouseEnter={e => { if (!selected) e.currentTarget.style.background = 'var(--bg2)'; }}
      onMouseLeave={e => { if (!selected) e.currentTarget.style.background = 'transparent'; }}
    >
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 6 }}>
        <span style={{ fontWeight: 600, fontSize: 14, color: 'var(--text1)' }}>{session.session_name}</span>
        <StatusBadge status={session.status} />
      </div>
      <div style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text3)', marginBottom: 6, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
        {session.config_path.replace('configs/experiments/', '')}
      </div>
      <div style={{ display: 'flex', gap: 12, alignItems: 'center' }}>
        <span style={{ fontSize: 13, fontFamily: 'var(--font-mono)', fontWeight: 600, color: 'var(--text1)' }}>
          ${session.current_equity.toLocaleString('en-US', { maximumFractionDigits: 0 })}
        </span>
        <span style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: pnlColor(pnlPct) }}>
          {fmtPct(pnlPct)}
        </span>
        {session.parking_preset && (
          <span style={{
            fontFamily: 'var(--font-mono)', fontSize: 10,
            background: 'color-mix(in srgb, var(--orange) 12%, transparent)',
            border: '1px solid color-mix(in srgb, var(--orange) 25%, transparent)',
            color: 'var(--orange)', borderRadius: 3, padding: '1px 5px',
          }}>
            🅿 {session.parking_preset}
          </span>
        )}
        {session.idle_alpha_preset && (
          <span style={{
            fontFamily: 'var(--font-mono)', fontSize: 10,
            background: 'color-mix(in srgb, var(--green) 12%, transparent)',
            border: '1px solid color-mix(in srgb, var(--green) 25%, transparent)',
            color: 'var(--green)', borderRadius: 3, padding: '1px 5px',
          }}>
            IA {session.idle_alpha_preset}
          </span>
        )}
        {session.form4_sleeve_preset && (
          <span style={{
            fontFamily: 'var(--font-mono)', fontSize: 10,
            background: 'color-mix(in srgb, var(--cyan) 12%, transparent)',
            border: '1px solid color-mix(in srgb, var(--cyan) 25%, transparent)',
            color: 'var(--cyan)', borderRadius: 3, padding: '1px 5px',
          }}>
            F4 {session.form4_sleeve_preset}
          </span>
        )}
        {session.ownership_sleeve_preset && (
          <span style={{
            fontFamily: 'var(--font-mono)', fontSize: 10,
            background: 'color-mix(in srgb, var(--violet, var(--cyan)) 12%, transparent)',
            border: '1px solid color-mix(in srgb, var(--violet, var(--cyan)) 25%, transparent)',
            color: 'var(--violet, var(--cyan))', borderRadius: 3, padding: '1px 5px',
          }}>
            13D {session.ownership_sleeve_preset}
          </span>
        )}
        {session.kill_switch && <Shield size={11} style={{ color: 'var(--red)' }} />}
        {session.latest_date && (
          <span style={{ fontSize: 11, color: 'var(--text3)', marginLeft: 'auto' }}>{session.latest_date}</span>
        )}
      </div>
    </div>
  );
}

// ── Overview Tab ─────────────────────────────────────────────────────────────

function OverviewTab({ session }: { session: PaperSession }) {
  const { data, isLoading } = useQuery({
    queryKey: ['paper-equity', session.session_id],
    queryFn: () => paperApi.equity(session.session_id),
    refetchInterval: 60_000,
  });

  const snapshots = data?.snapshots ?? [];
  const chartData = snapshots.map(s => ({
    date: s.date,
    equity: s.equity,
    pnl: s.total_pnl ?? 0,
    drawdown: s.drawdown_pct ?? 0,
  }));

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
      {/* Stats grid */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 12 }}>
        <StatCard
          label="Equity"
          value={`$${session.current_equity.toLocaleString('en-US', { maximumFractionDigits: 0 })}`}
          sub={`Initial: $${session.initial_equity.toLocaleString('en-US', { maximumFractionDigits: 0 })}`}
        />
        <StatCard
          label="Total P&L"
          value={fmtMoney(session.total_pnl, 0)}
          sub={fmtPct(session.total_pnl_pct)}
          valueColor={pnlColor(session.total_pnl)}
        />
        <StatCard
          label="Max Drawdown"
          value={`${session.drawdown_pct.toFixed(2)}%`}
          sub={`Peak: $${session.peak_equity.toLocaleString('en-US', { maximumFractionDigits: 0 })}`}
          valueColor={session.drawdown_pct > 10 ? 'var(--red)' : session.drawdown_pct > 5 ? 'var(--gold)' : 'var(--green)'}
        />
        <StatCard
          label="Trades"
          value={String(session.trade_count)}
          sub={session.latest_date ? `Last: ${session.latest_date}` : 'No trades yet'}
        />
      </div>

      {/* Risk state */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 12 }}>
        <StatCard
          label="Kill Switch"
          value={session.kill_switch ? 'ON' : 'OFF'}
          valueColor={session.kill_switch ? 'var(--red)' : 'var(--green)'}
        />
        <StatCard
          label="Consec. Losses"
          value={String(session.consecutive_losses)}
          valueColor={session.consecutive_losses >= 3 ? 'var(--red)' : 'var(--text1)'}
        />
        <StatCard
          label="Cooldown"
          value={session.cooldown_remaining > 0 ? `${session.cooldown_remaining}d` : 'None'}
          valueColor={session.cooldown_remaining > 0 ? 'var(--gold)' : 'var(--text1)'}
        />
        <StatCard
          label="Daily Risk Used"
          value={`${(session.daily_new_risk_used * 100).toFixed(1)}%`}
        />
      </div>

      {/* Equity chart */}
      <div style={{ ...card, padding: 20 }}>
        <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text2)', marginBottom: 16, display: 'flex', alignItems: 'center', gap: 7 }}>
          <Activity size={14} /> Equity Curve
          <span style={{ fontSize: 12, color: 'var(--text3)', fontFamily: 'var(--font-mono)', marginLeft: 'auto' }}>
            {snapshots.length} days
          </span>
        </div>
        {isLoading && <Loading />}
        {!isLoading && chartData.length === 0 && (
          <div style={{ padding: '40px 0', textAlign: 'center', color: 'var(--text3)', fontSize: 14 }}>
            No equity history yet. Run the session to start tracking.
          </div>
        )}
        {chartData.length > 0 && (
          <ResponsiveContainer width="100%" height={240}>
            <LineChart data={chartData} margin={{ top: 4, right: 16, bottom: 0, left: 0 }}>
              <CartesianGrid strokeDasharray="3 3" stroke="var(--border)" />
              <XAxis
                dataKey="date"
                tick={{ fontSize: 11, fontFamily: 'var(--font-mono)', fill: 'var(--text3)' }}
                tickFormatter={v => v.slice(5)}
                interval="preserveStartEnd"
              />
              <YAxis
                tick={{ fontSize: 11, fontFamily: 'var(--font-mono)', fill: 'var(--text3)' }}
                tickFormatter={v => `$${(v / 1000).toFixed(1)}k`}
                width={58}
              />
              <Tooltip
                contentStyle={{
                  background: 'var(--bg1)', border: '1px solid var(--border-md)',
                  borderRadius: 8, fontSize: 12, fontFamily: 'var(--font-mono)',
                }}
                formatter={(v) => [`$${Number(v).toLocaleString('en-US', { maximumFractionDigits: 2 })}`, 'Equity']}
                labelStyle={{ color: 'var(--text2)' }}
              />
              <ReferenceLine y={data?.initial_equity} stroke="var(--text3)" strokeDasharray="4 4" />
              <Line
                type="monotone"
                dataKey="equity"
                stroke="var(--cyan)"
                strokeWidth={2}
                dot={false}
                activeDot={{ r: 4, fill: 'var(--cyan)' }}
              />
            </LineChart>
          </ResponsiveContainer>
        )}
      </div>

      {/* Daily snapshots table */}
      {snapshots.length > 0 && (
        <div style={card}>
          <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', fontSize: 13, fontWeight: 600, color: 'var(--text2)' }}>
            Daily Snapshots (last 20)
          </div>
          <div style={{ overflowX: 'auto' }}>
            <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
              <thead>
                <tr style={{ background: 'var(--bg2)' }}>
                  {['Date', 'Equity', 'Cash', 'Mkt Val', 'Daily P&L', 'Total P&L', 'Drawdown', 'Positions'].map((h, hi) => (
                    <th key={h} style={{ padding: '10px 14px', textAlign: hi === 0 ? 'left' : 'right', fontFamily: 'var(--font-mono)', fontSize: 11, fontWeight: 500, letterSpacing: '0.07em', color: 'var(--text3)', textTransform: 'uppercase', whiteSpace: 'nowrap' }}>
                      {h}
                    </th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {[...snapshots].reverse().slice(0, 20).map((s, i) => (
                  <tr key={s.date} style={{ borderTop: '1px solid var(--border)', background: i % 2 === 1 ? 'rgba(0,0,0,0.015)' : 'transparent' }}>
                    <td style={{ padding: '8px 14px', fontFamily: 'var(--font-mono)', fontSize: 13, color: 'var(--text2)' }}>{s.date}</td>
                    <td style={{ padding: '8px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', fontWeight: 600, color: 'var(--text1)' }}>${s.equity.toLocaleString('en-US', { maximumFractionDigits: 0 })}</td>
                    <td style={{ padding: '8px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>${s.cash.toLocaleString('en-US', { maximumFractionDigits: 0 })}</td>
                    <td style={{ padding: '8px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>${s.market_value.toLocaleString('en-US', { maximumFractionDigits: 0 })}</td>
                    <td style={{ padding: '8px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: pnlColor(s.daily_pnl) }}>{fmtMoney(s.daily_pnl)}</td>
                    <td style={{ padding: '8px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: pnlColor(s.total_pnl) }}>{fmtMoney(s.total_pnl)}</td>
                    <td style={{ padding: '8px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: (s.drawdown_pct ?? 0) > 5 ? 'var(--red)' : 'var(--text2)' }}>{s.drawdown_pct?.toFixed(2) ?? '—'}%</td>
                    <td style={{ padding: '8px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>{s.open_position_count ?? '—'}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      )}
    </div>
  );
}

// ── Positions Tab ─────────────────────────────────────────────────────────────

function PositionsTab({ session }: { session: PaperSession }) {
  const { data, isLoading, error, refetch, isFetching } = useQuery({
    queryKey: ['paper-positions', session.session_id],
    queryFn: () => paperApi.positions(session.session_id),
    staleTime: 30_000,
  });

  const positions = data?.positions ?? [];
  const brokerAvailable = data?.broker_available;

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <span style={{ fontSize: 13, color: 'var(--text2)' }}>
          {positions.length} open position{positions.length !== 1 ? 's' : ''}
        </span>
        {brokerAvailable === false && (
          <span style={{ fontSize: 12, color: 'var(--gold)', display: 'flex', alignItems: 'center', gap: 5 }}>
            <AlertTriangle size={12} /> Alpaca unavailable — showing local state only
          </span>
        )}
        <button
          style={{ ...btn('outline'), marginLeft: 'auto', padding: '5px 10px' }}
          onClick={() => refetch()}
        >
          <RefreshCw size={13} style={{ animation: isFetching ? 'spin 1s linear infinite' : 'none' }} />
          Refresh
        </button>
      </div>

      {isLoading && <Loading />}
      {error && <ErrorState error={error as Error} />}

      {!isLoading && positions.length === 0 && (
        <div style={{ ...card, padding: '40px 24px', textAlign: 'center', color: 'var(--text3)', fontSize: 14 }}>
          No open positions
        </div>
      )}

      {positions.length > 0 && (
        <div style={card}>
          <div style={{ overflowX: 'auto' }}>
            <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
              <thead>
                <tr style={{ background: 'var(--bg2)', borderBottom: '1px solid var(--border-md)' }}>
                  {['Symbol', 'Qty', 'Entry', 'Current', 'P&L $', 'P&L %', 'Days', 'Stop', 'Target', 'Direction'].map(h => (
                    <th key={h} style={{ padding: '11px 14px', textAlign: h === 'Symbol' ? 'left' : 'right', fontFamily: 'var(--font-mono)', fontSize: 11, fontWeight: 500, letterSpacing: '0.07em', color: 'var(--text3)', textTransform: 'uppercase', whiteSpace: 'nowrap' }}>
                      {h}
                    </th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {positions.map((p, i) => (
                  <tr key={p.symbol} style={{ borderBottom: '1px solid var(--border)', background: i % 2 === 1 ? 'rgba(0,0,0,0.015)' : 'transparent' }}>
                    <td style={{ padding: '10px 14px', fontFamily: 'var(--font-mono)', fontWeight: 700, color: p._ghost ? 'var(--gold)' : 'var(--text1)', display: 'flex', alignItems: 'center', gap: 6 }}>
                      {p.symbol}
                      {p._ghost && <span style={{ fontSize: 10, color: 'var(--gold)' }}>GHOST</span>}
                    </td>
                    <td style={{ padding: '10px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>{p.qty ?? '—'}</td>
                    <td style={{ padding: '10px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>{fmtPrice(p.avg_entry_price)}</td>
                    <td style={{ padding: '10px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>{fmtPrice(p.current_price)}</td>
                    <td style={{ padding: '10px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', fontWeight: 600, color: pnlColor(p.unrealized_pl) }}>{fmtMoney(p.unrealized_pl)}</td>
                    <td style={{ padding: '10px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: pnlColor(p.unrealized_pl_pct) }}>{fmtPct(p.unrealized_pl_pct)}</td>
                    <td style={{ padding: '10px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>{p.days_held ?? '—'}</td>
                    <td style={{ padding: '10px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: 'var(--red)' }}>{fmtPrice(p.stop_price)}</td>
                    <td style={{ padding: '10px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: 'var(--green)' }}>{fmtPrice(p.target_price)}</td>
                    <td style={{ padding: '10px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--text3)' }}>{p.trade_direction ?? '—'}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      )}
    </div>
  );
}

// ── Trades Tab ────────────────────────────────────────────────────────────────

function TradesTab({ session }: { session: PaperSession }) {
  const [lastN, setLastN] = useState<string>('');
  const [sleeveFilter, setSleeveFilter] = useState<'' | TradeSleeve>('');

  const { data, isLoading, error } = useQuery({
    queryKey: ['paper-trades', session.session_id, lastN],
    queryFn: () => paperApi.trades(session.session_id, lastN ? parseInt(lastN) : undefined),
  });

  const trades = (data?.trades ?? []) as PaperTrade[];
  const sleevedTrades = trades.map(t => ({
    ...t,
    _sleeve: classifyTradeSleeve(t),
  })) as (PaperTrade & { _sleeve: TradeSleeve })[];
  const filteredTrades = sleeveFilter ? sleevedTrades.filter(t => t._sleeve === sleeveFilter) : sleevedTrades;
  const wins = filteredTrades.filter(t => t.net_pnl > 0).length;
  const totalPnl = filteredTrades.reduce((s, t) => s + (t.net_pnl ?? 0), 0);
  const sleeveOptions: TradeSleeve[] = ['core', 'idle_alpha', 'risk_off_alpha', 'ownership', 'parking'];

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <span style={{ fontSize: 13, color: 'var(--text2)' }}>
          {filteredTrades.length}{filteredTrades.length !== (data?.total ?? 0) ? ` / ${data?.total ?? 0}` : ''} trades
          {filteredTrades.length > 0 && ` · Win Rate: ${((wins / filteredTrades.length) * 100).toFixed(0)}%`}
          {filteredTrades.length > 0 && ` · P&L: `}
          {filteredTrades.length > 0 && <span style={{ color: pnlColor(totalPnl), fontFamily: 'var(--font-mono)' }}>{fmtMoney(totalPnl, 0)}</span>}
        </span>
        <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 8 }}>
          <select
            value={sleeveFilter}
            onChange={e => setSleeveFilter(e.target.value as '' | TradeSleeve)}
            style={{
              ...inputStyle,
              width: 130,
              padding: '4px 10px',
              fontSize: 12,
              cursor: 'pointer',
            }}
          >
            <option value="">All Sleeves</option>
            {sleeveOptions.map(s => <option key={s} value={s}>{tradeSleeveLabel(s)}</option>)}
          </select>
          <span style={{ fontSize: 12, color: 'var(--text3)', fontFamily: 'var(--font-mono)' }}>Show last:</span>
          {[10, 20, 50, 100].map(n => (
            <button
              key={n}
              onClick={() => setLastN(String(n))}
              style={{
                ...btn('outline'),
                padding: '4px 10px',
                fontSize: 12,
                background: lastN === String(n) ? 'var(--cyan-dim)' : 'transparent',
                color: lastN === String(n) ? 'var(--cyan)' : 'var(--text3)',
                borderColor: lastN === String(n) ? 'var(--cyan)' : 'var(--border-md)',
              }}
            >
              {n}
            </button>
          ))}
          <button
            onClick={() => setLastN('')}
            style={{
              ...btn('outline'),
              padding: '4px 10px',
              fontSize: 12,
              background: !lastN ? 'var(--cyan-dim)' : 'transparent',
              color: !lastN ? 'var(--cyan)' : 'var(--text3)',
              borderColor: !lastN ? 'var(--cyan)' : 'var(--border-md)',
            }}
          >
            All
          </button>
        </div>
      </div>

      {isLoading && <Loading />}
      {error && <ErrorState error={error as Error} />}

      {!isLoading && filteredTrades.length === 0 && (
        <div style={{ ...card, padding: '40px 24px', textAlign: 'center', color: 'var(--text3)', fontSize: 14 }}>
          {trades.length === 0 ? 'No trades recorded yet' : 'No trades match the sleeve filter'}
        </div>
      )}

      {filteredTrades.length > 0 && (
        <div style={card}>
          <div style={{ overflowX: 'auto' }}>
            <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
              <thead>
                <tr style={{ background: 'var(--bg2)', borderBottom: '1px solid var(--border-md)' }}>
                  {['Symbol', 'Sleeve', 'Engine', 'Entry Date', 'Exit Date', 'Entry $', 'Exit $', 'Shares', 'Net P&L', 'R', 'Days', 'Reason'].map(h => (
                    <th key={h} style={{ padding: '11px 14px', textAlign: h === 'Symbol' || h === 'Sleeve' || h === 'Engine' || h === 'Reason' ? 'left' : 'right', fontFamily: 'var(--font-mono)', fontSize: 11, fontWeight: 500, letterSpacing: '0.07em', color: 'var(--text3)', textTransform: 'uppercase', whiteSpace: 'nowrap' }}>
                      {h}
                    </th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {filteredTrades.map((t, i) => (
                  <tr key={t.trade_id} style={{ borderBottom: '1px solid var(--border)', background: i % 2 === 1 ? 'rgba(0,0,0,0.015)' : 'transparent' }}>
                    <td style={{ padding: '9px 14px', fontFamily: 'var(--font-mono)', fontWeight: 700, color: 'var(--text1)' }}>{t.symbol}</td>
                    <td style={{ padding: '9px 14px', textAlign: 'left' }}><SleeveBadge sleeve={t._sleeve} /></td>
                    <td style={{ padding: '9px 14px', textAlign: 'left', fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text3)' }}>{t.engine_id ?? '—'}</td>
                    <td style={{ padding: '9px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>{t.entry_date ?? '—'}</td>
                    <td style={{ padding: '9px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>{t.exit_date}</td>
                    <td style={{ padding: '9px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>{fmtPrice(t.entry_price)}</td>
                    <td style={{ padding: '9px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>{fmtPrice(t.exit_price)}</td>
                    <td style={{ padding: '9px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>{t.shares}</td>
                    <td style={{ padding: '9px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', fontWeight: 600, color: pnlColor(t.net_pnl) }}>{fmtMoney(t.net_pnl)}</td>
                    <td style={{ padding: '9px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: pnlColor(t.r_multiple) }}>
                      {t.r_multiple != null ? `${t.r_multiple >= 0 ? '+' : ''}${t.r_multiple.toFixed(2)}R` : '—'}
                    </td>
                    <td style={{ padding: '9px 14px', textAlign: 'right', fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>{t.holding_days != null ? `${t.holding_days}d` : '—'}</td>
                    <td style={{ padding: '9px 14px', fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--text3)' }}>{t.exit_reason}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      )}
    </div>
  );
}

// ── Run Tab ───────────────────────────────────────────────────────────────────

function RunTab({ session, onTaskLaunched }: {
  session: PaperSession;
  onTaskLaunched: (task: PaperTask) => void;
}) {
  const [date, setDate] = useState('');
  const [force, setForce] = useState(false);
  const [runningOp, setRunningOp] = useState<string | null>(null);

  const qc = useQueryClient();

  const execOp = async (op: 'run' | 'run-close' | 'run-open' | 'run-all') => {
    setRunningOp(op);
    try {
      let task: PaperTask;
      const d = date || null;
      if (op === 'run') task = await paperApi.run(session.session_id, d, force);
      else if (op === 'run-close') task = await paperApi.runClose(session.session_id, d, force);
      else if (op === 'run-open') task = await paperApi.runOpen(session.session_id, d, force);
      else {
        const result = await paperApi.runAll();
        task = result.tasks[0];
      }
      onTaskLaunched(task);
      qc.invalidateQueries({ queryKey: ['paper-tasks'] });
    } catch (err) {
      alert((err as Error).message);
    } finally {
      setRunningOp(null);
    }
  };

  const isActive = session.status === 'active';

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
      {!isActive && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '12px 16px', background: 'var(--gold-dim)', borderRadius: 9, color: 'var(--gold)', fontSize: 13 }}>
          <AlertTriangle size={14} />
          Session is {session.status}. Resume to run operations.
        </div>
      )}
      {session.kill_switch && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '12px 16px', background: 'var(--red-dim)', borderRadius: 9, color: 'var(--red)', fontSize: 13 }}>
          <Shield size={14} />
          Kill switch is active — all trading halted.
        </div>
      )}

      {/* Options */}
      <div style={{ ...card, padding: 20 }}>
        <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text2)', marginBottom: 16 }}>Options</div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr auto', gap: 12, alignItems: 'end' }}>
          <div>
            <label style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text3)', display: 'block', marginBottom: 5, letterSpacing: '0.07em', textTransform: 'uppercase' }}>
              Target Date (YYYY-MM-DD)
            </label>
            <input
              style={inputStyle}
              type="date"
              value={date}
              onChange={e => setDate(e.target.value)}
              placeholder="Leave empty for today"
            />
          </div>
          <label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, color: 'var(--text2)', cursor: 'pointer', paddingBottom: 2, fontFamily: 'var(--font-mono)' }}>
            <input
              type="checkbox"
              checked={force}
              onChange={e => setForce(e.target.checked)}
              style={{ width: 15, height: 15 }}
            />
            --force (re-run even if already processed)
          </label>
        </div>
      </div>

      {/* Run operations */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
        {/* run */}
        <div style={{ ...card, padding: 20 }}>
          <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--text1)', marginBottom: 6 }}>run</div>
          <div style={{ fontSize: 12, color: 'var(--text3)', marginBottom: 14, lineHeight: 1.5 }}>
            전체 일일 처리: exit 판단 + 신규 이벤트 검색 + 진입
          </div>
          <button
            style={{ ...btn('primary'), width: '100%', justifyContent: 'center', opacity: (!isActive || !!runningOp) ? 0.5 : 1 }}
            onClick={() => execOp('run')}
            disabled={!isActive || !!runningOp}
          >
            {runningOp === 'run' ? <><Loader size={13} /> Running…</> : <><Play size={13} /> Run Daily</>}
          </button>
        </div>

        {/* run-close */}
        <div style={{ ...card, padding: 20 }}>
          <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--text1)', marginBottom: 6 }}>run-close</div>
          <div style={{ fontSize: 12, color: 'var(--text3)', marginBottom: 14, lineHeight: 1.5 }}>
            장 마감 직전: same-day 이벤트 → MOC 매수
          </div>
          <button
            style={{ ...btn('outline'), width: '100%', justifyContent: 'center', opacity: (!isActive || !!runningOp) ? 0.5 : 1 }}
            onClick={() => execOp('run-close')}
            disabled={!isActive || !!runningOp}
          >
            {runningOp === 'run-close' ? <><Loader size={13} /> Running…</> : <><Play size={13} /> Run Close</>}
          </button>
        </div>

        {/* run-open */}
        <div style={{ ...card, padding: 20 }}>
          <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--text1)', marginBottom: 6 }}>run-open</div>
          <div style={{ fontSize: 12, color: 'var(--text3)', marginBottom: 14, lineHeight: 1.5 }}>
            장 시작 직후: 전날 exit + after-close 이벤트 → 시장가 매수
          </div>
          <button
            style={{ ...btn('outline'), width: '100%', justifyContent: 'center', opacity: (!isActive || !!runningOp) ? 0.5 : 1 }}
            onClick={() => execOp('run-open')}
            disabled={!isActive || !!runningOp}
          >
            {runningOp === 'run-open' ? <><Loader size={13} /> Running…</> : <><Play size={13} /> Run Open</>}
          </button>
        </div>

        {/* run-all */}
        <div style={{ ...card, padding: 20 }}>
          <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--text1)', marginBottom: 6 }}>run-all</div>
          <div style={{ fontSize: 12, color: 'var(--text3)', marginBottom: 14, lineHeight: 1.5 }}>
            전체 활성 세션에 대해 일일 처리 실행
          </div>
          <button
            style={{ ...btn('outline'), width: '100%', justifyContent: 'center', opacity: !!runningOp ? 0.5 : 1 }}
            onClick={() => execOp('run-all')}
            disabled={!!runningOp}
          >
            {runningOp === 'run-all' ? <><Loader size={13} /> Running…</> : <><Play size={13} /> Run All Sessions</>}
          </button>
        </div>
      </div>
    </div>
  );
}

// ── Tasks Tab ─────────────────────────────────────────────────────────────────

function TasksTab({ session, highlightTaskId }: {
  session: PaperSession;
  highlightTaskId?: string | null;
}) {
  const [selectedTask, setSelectedTask] = useState<string | null>(highlightTaskId ?? null);

  const { data, isLoading } = useQuery({
    queryKey: ['paper-tasks', session.session_name],
    queryFn: () => paperApi.tasks(session.session_name),
    refetchInterval: 3000,
  });

  const { data: logData } = useQuery({
    queryKey: ['paper-task-log', selectedTask],
    queryFn: () => selectedTask ? paperApi.taskLog(selectedTask) : null,
    enabled: !!selectedTask,
    refetchInterval: (query) => {
      const status = query.state.data?.status;
      return status === 'running' ? 2000 : false;
    },
  });

  const tasks = data?.tasks ?? [];

  useEffect(() => {
    if (highlightTaskId) setSelectedTask(highlightTaskId);
  }, [highlightTaskId]);

  return (
    <div style={{ display: 'flex', gap: 16, minHeight: 400 }}>
      {/* Task list */}
      <div style={{ width: 280, flexShrink: 0, ...card, alignSelf: 'flex-start' }}>
        <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--border)', fontSize: 13, fontWeight: 600, color: 'var(--text2)' }}>
          Recent Tasks
        </div>
        {isLoading && <div style={{ padding: 16 }}><Loading /></div>}
        {tasks.length === 0 && !isLoading && (
          <div style={{ padding: '20px 16px', fontSize: 13, color: 'var(--text3)', textAlign: 'center' }}>
            No tasks yet
          </div>
        )}
        {tasks.map(t => (
          <div
            key={t.task_id}
            onClick={() => setSelectedTask(t.task_id)}
            style={{
              padding: '11px 16px',
              cursor: 'pointer',
              borderBottom: '1px solid var(--border)',
              background: selectedTask === t.task_id ? 'var(--cyan-dim)' : 'transparent',
              borderLeft: `3px solid ${selectedTask === t.task_id ? 'var(--cyan)' : 'transparent'}`,
            }}
            onMouseEnter={e => { if (selectedTask !== t.task_id) e.currentTarget.style.background = 'var(--bg2)'; }}
            onMouseLeave={e => { if (selectedTask !== t.task_id) e.currentTarget.style.background = 'transparent'; }}
          >
            <div style={{ display: 'flex', alignItems: 'center', gap: 7, marginBottom: 4 }}>
              <TaskStatusIcon status={t.status} />
              <span style={{ fontFamily: 'var(--font-mono)', fontSize: 12, fontWeight: 600, color: 'var(--text1)' }}>
                {t.operation}
              </span>
            </div>
            <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>
              {t.started_at ? new Date(t.started_at).toLocaleString() : t.created_at}
            </div>
            {t.error && (
              <div style={{ fontSize: 11, color: 'var(--red)', marginTop: 3, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                {t.error}
              </div>
            )}
          </div>
        ))}
      </div>

      {/* Log viewer */}
      <div style={{ flex: 1, background: '#0d1117', border: '1px solid rgba(255,255,255,0.08)', borderRadius: 12, overflow: 'hidden', boxShadow: '0 4px 20px rgba(0,0,0,0.3)', display: 'flex', flexDirection: 'column' }}>
        {!selectedTask && (
          <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'rgba(255,255,255,0.25)', fontSize: 14, gap: 8 }}>
            <ScrollText size={16} /> Select a task to view its log
          </div>
        )}
        {selectedTask && (
          <>
            {/* Terminal title bar */}
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '10px 16px', background: '#161b22', borderBottom: '1px solid rgba(255,255,255,0.06)' }}>
              <div style={{ display: 'flex', gap: 6 }}>
                <div style={{ width: 12, height: 12, borderRadius: '50%', background: '#ff5f57' }} />
                <div style={{ width: 12, height: 12, borderRadius: '50%', background: '#febc2e' }} />
                <div style={{ width: 12, height: 12, borderRadius: '50%', background: '#28c840' }} />
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginLeft: 8 }}>
                {logData && <TaskStatusIcon status={logData.status as PaperTask['status']} />}
                <span style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: 'rgba(255,255,255,0.4)' }}>
                  {tasks.find(t => t.task_id === selectedTask)?.operation ?? selectedTask}
                </span>
                {logData?.status === 'running' && (
                  <span style={{ fontSize: 11, color: 'var(--cyan)', fontFamily: 'var(--font-mono)' }}>(live)</span>
                )}
              </div>
            </div>
            <pre
              className="terminal-scroll"
              style={{
                flex: 1,
                padding: '16px 20px',
                fontSize: 12,
                fontFamily: 'var(--font-mono)',
                lineHeight: 1.7,
                color: 'rgba(230,237,243,0.85)',
                background: 'transparent',
                overflowY: 'auto',
                whiteSpace: 'pre-wrap',
                wordBreak: 'break-all',
                minHeight: 200,
                maxHeight: 500,
                margin: 0,
              }}
              dangerouslySetInnerHTML={{
                __html: logData?.log
                  ? ansiToHtml(logData.log)
                  : `<span style="color:rgba(255,255,255,0.25);font-style:italic">${logData?.status === 'running' ? '(waiting for output...)' : 'No output'}</span>`,
              }}
            />
          </>
        )}
      </div>
    </div>
  );
}

// ── Session Detail ────────────────────────────────────────────────────────────

type TabId = 'overview' | 'positions' | 'trades' | 'run' | 'tasks';

function SessionDetail({ session, onRefresh }: {
  session: PaperSession;
  onRefresh: () => void;
}) {
  const [tab, setTab] = useState<TabId>('overview');
  const [showClose, setShowClose] = useState(false);
  const [latestTask, setLatestTask] = useState<PaperTask | null>(null);
  const qc = useQueryClient();

  const pauseMut = useMutation({
    mutationFn: () => paperApi.pauseSession(session.session_id),
    onSuccess: () => { qc.invalidateQueries({ queryKey: ['paper-sessions'] }); onRefresh(); },
  });

  const resumeMut = useMutation({
    mutationFn: () => paperApi.resumeSession(session.session_id),
    onSuccess: () => { qc.invalidateQueries({ queryKey: ['paper-sessions'] }); onRefresh(); },
  });

  const closeMut = useMutation({
    mutationFn: () => paperApi.closeSession(session.session_id),
    onSuccess: () => { qc.invalidateQueries({ queryKey: ['paper-sessions'] }); setShowClose(false); },
  });

  const TABS: { id: TabId; label: string }[] = [
    { id: 'overview', label: 'Overview' },
    { id: 'positions', label: 'Positions' },
    { id: 'trades', label: 'Trades' },
    { id: 'run', label: 'Run' },
    { id: 'tasks', label: 'Tasks' },
  ];

  function handleTaskLaunched(task: PaperTask) {
    setLatestTask(task);
    setTab('tasks');
  }

  return (
    <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 0 }}>
      {/* Header */}
      <div style={{
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        padding: '16px 24px', borderBottom: '1px solid var(--border)',
        background: 'var(--bg1)', flexShrink: 0,
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              <h2 style={{ fontSize: 18, fontWeight: 700, color: 'var(--text1)' }}>{session.session_name}</h2>
              <StatusBadge status={session.status} />
              {session.kill_switch && <KillSwitchBadge on />}
              {session.parking_preset && (
                <span style={{
                  fontFamily: 'var(--font-mono)', fontSize: 11,
                  background: 'color-mix(in srgb, var(--orange) 12%, transparent)',
                  border: '1px solid color-mix(in srgb, var(--orange) 25%, transparent)',
                  color: 'var(--orange)', borderRadius: 4, padding: '2px 8px',
                }}>
                  🅿 {session.parking_preset}
                </span>
              )}
              {session.idle_alpha_preset && (
                <span style={{
                  fontFamily: 'var(--font-mono)', fontSize: 11,
                  background: 'color-mix(in srgb, var(--green) 12%, transparent)',
                  border: '1px solid color-mix(in srgb, var(--green) 25%, transparent)',
                  color: 'var(--green)', borderRadius: 4, padding: '2px 8px',
                }}>
                  IA {session.idle_alpha_preset}
                </span>
              )}
              {session.form4_sleeve_preset && (
                <span style={{
                  fontFamily: 'var(--font-mono)', fontSize: 11,
                  background: 'color-mix(in srgb, var(--cyan) 12%, transparent)',
                  border: '1px solid color-mix(in srgb, var(--cyan) 25%, transparent)',
                  color: 'var(--cyan)', borderRadius: 4, padding: '2px 8px',
                }}>
                  F4 {session.form4_sleeve_preset}
                </span>
              )}
              {session.ownership_sleeve_preset && (
                <span style={{
                  fontFamily: 'var(--font-mono)', fontSize: 11,
                  background: 'color-mix(in srgb, var(--violet, var(--cyan)) 12%, transparent)',
                  border: '1px solid color-mix(in srgb, var(--violet, var(--cyan)) 25%, transparent)',
                  color: 'var(--violet, var(--cyan))', borderRadius: 4, padding: '2px 8px',
                }}>
                  13D {session.ownership_sleeve_preset}
                </span>
              )}
            </div>
            <div style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text3)', marginTop: 3 }}>
              {session.config_path} · ID: {session.session_id} · Created {session.created_at.slice(0, 10)}
            </div>
          </div>
        </div>
        <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
          {session.status === 'active' && (
            <button
              style={btn('outline')}
              onClick={() => pauseMut.mutate()}
              disabled={pauseMut.isPending}
            >
              <Pause size={13} /> Pause
            </button>
          )}
          {session.status === 'paused' && (
            <button
              style={btn('primary')}
              onClick={() => resumeMut.mutate()}
              disabled={resumeMut.isPending}
            >
              <Play size={13} /> Resume
            </button>
          )}
          <button style={btn('danger')} onClick={() => setShowClose(true)}>
            <Trash2 size={13} /> Close
          </button>
        </div>
      </div>

      {/* Tabs */}
      <div style={{
        display: 'flex', gap: 0,
        borderBottom: '1px solid var(--border)',
        background: 'var(--bg1)', flexShrink: 0, paddingLeft: 24,
      }}>
        {TABS.map(t => (
          <button
            key={t.id}
            onClick={() => setTab(t.id)}
            style={{
              padding: '11px 18px',
              fontSize: 13, fontWeight: 500,
              border: 'none', borderBottom: `2px solid ${tab === t.id ? 'var(--cyan)' : 'transparent'}`,
              background: 'transparent',
              color: tab === t.id ? 'var(--cyan)' : 'var(--text3)',
              cursor: 'pointer',
              transition: 'all 0.1s',
              marginBottom: -1,
            }}
          >
            {t.label}
          </button>
        ))}
      </div>

      {/* Tab content */}
      <div style={{ flex: 1, padding: '22px 24px', overflowY: 'auto' }}>
        {tab === 'overview' && <OverviewTab session={session} />}
        {tab === 'positions' && <PositionsTab session={session} />}
        {tab === 'trades' && <TradesTab session={session} />}
        {tab === 'run' && <RunTab session={session} onTaskLaunched={handleTaskLaunched} />}
        {tab === 'tasks' && <TasksTab session={session} highlightTaskId={latestTask?.task_id} />}
      </div>

      {showClose && (
        <CloseConfirmModal
          session={session}
          onClose={() => setShowClose(false)}
          onConfirm={() => closeMut.mutate()}
        />
      )}
    </div>
  );
}

// ── Auto Daemon Badge (sidebar) ───────────────────────────────────────────────

function AutoDaemonBadge() {
  const { data } = useQuery({
    queryKey: ['paper-auto-status'],
    queryFn: () => paperApi.autoStatus(),
    refetchInterval: 5000,
    staleTime: 4000,
  });
  if (!data) return null;
  return (
    <span style={{
      marginLeft: 'auto',
      display: 'inline-flex', alignItems: 'center', gap: 4,
      padding: '2px 8px', borderRadius: 20,
      fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 600,
      background: data.running ? 'var(--green-dim)' : 'var(--bg2)',
      color: data.running ? 'var(--green)' : 'var(--text3)',
    }}>
      <span style={{
        width: 5, height: 5, borderRadius: '50%',
        background: data.running ? 'var(--green)' : 'var(--text3)',
        display: 'inline-block',
        animation: data.running ? 'pulse 1.5s ease-in-out infinite' : 'none',
      }} />
      {data.running ? 'ON' : 'OFF'}
    </span>
  );
}

// ── Auto Daemon Panel ────────────────────────────────────────────────────────

function fmtCountdown(secs: number): string {
  if (secs <= 0) return 'now';
  const h = Math.floor(secs / 3600);
  const m = Math.floor((secs % 3600) / 60);
  const s = Math.floor(secs % 60);
  if (h > 0) return `${h}h ${String(m).padStart(2, '0')}m`;
  if (m > 0) return `${m}m ${String(s).padStart(2, '0')}s`;
  return `${s}s`;
}

function AutoDaemonPanel({ sessions }: { sessions: string[] }) {
  const [showLog, setShowLog] = useState(true);
  const [sessionFilter, setSessionFilter] = useState<string[]>([]);
  const [dryRun, setDryRun] = useState(false);
  const [sessionDropOpen, setSessionDropOpen] = useState(false);
  const logRef = useRef<HTMLDivElement>(null);
  const qc = useQueryClient();

  const { data, isLoading, refetch, isFetching } = useQuery({
    queryKey: ['paper-auto-status'],
    queryFn: () => paperApi.autoStatus(),
    refetchInterval: 5000,
  });

  const { data: logData, refetch: refetchLog } = useQuery({
    queryKey: ['paper-auto-log'],
    queryFn: () => paperApi.autoLog(300),
    enabled: showLog,
    refetchInterval: showLog ? 3000 : false,
  });

  // Auto-scroll log to bottom
  useEffect(() => {
    if (logRef.current) logRef.current.scrollTop = logRef.current.scrollHeight;
  }, [logData?.log]);

  const startMut = useMutation({
    mutationFn: () => paperApi.autoStart(sessionFilter.length > 0 ? sessionFilter : [], dryRun),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['paper-auto-status'] }),
    onError: (e) => alert((e as Error).message),
  });

  const stopMut = useMutation({
    mutationFn: () => paperApi.autoStop(),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['paper-auto-status'] }),
    onError: (e) => alert((e as Error).message),
  });

  const running = data?.running ?? false;
  const pid = data?.pid;
  const schedule = data?.schedule ?? [];

  // Live countdown — re-render every second
  const [tick, setTick] = useState(0);
  useEffect(() => {
    const id = setInterval(() => setTick(t => t + 1), 1000);
    return () => clearInterval(id);
  }, []);

  const nextEvent = schedule.find(e => !e.past);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      {/* Status + controls */}
      <div style={{ display: 'flex', gap: 16, flexWrap: 'wrap', alignItems: 'flex-start' }}>
        {/* Status card */}
        <div style={{
          ...card, padding: '16px 20px', flex: '0 0 auto', minWidth: 220,
          borderLeft: `3px solid ${running ? 'var(--green)' : 'var(--border-md)'}`,
        }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
            <Cpu size={14} style={{ color: running ? 'var(--green)' : 'var(--text3)' }} />
            <span style={{ fontFamily: 'var(--font-mono)', fontSize: 13, fontWeight: 600, color: running ? 'var(--green)' : 'var(--text3)' }}>
              {running ? 'RUNNING' : 'STOPPED'}
            </span>
            {running && pid && (
              <span style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>PID {pid}</span>
            )}
            {running && !pid && (
              <span style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>Web Server</span>
            )}
            <button
              style={{ marginLeft: 'auto', ...btn('ghost'), padding: '2px 5px', border: 'none' }}
              onClick={() => { refetch(); if (showLog) refetchLog(); }}
            >
              <RotateCcw size={12} style={{ animation: isFetching ? 'spin 1s linear infinite' : 'none' }} />
            </button>
          </div>
          {running && nextEvent && (
            <div style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>
              Next: <span style={{ color: 'var(--cyan)' }}>{nextEvent.label}</span>
              <br />
              <span style={{ color: 'var(--text3)' }}>
                {nextEvent.et_time} · in{' '}
                <span style={{ color: 'var(--gold)', fontWeight: 600 }}>
                  {fmtCountdown(nextEvent.wait_secs - tick)}
                </span>
              </span>
            </div>
          )}
          {!running && (
            <div style={{ fontSize: 12, color: 'var(--text3)' }}>Scheduler not running</div>
          )}
        </div>

        {/* Controls */}
        <div style={{ ...card, padding: '16px 20px', flex: 1, minWidth: 280 }}>
          <div style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text3)', marginBottom: 12, letterSpacing: '0.07em', textTransform: 'uppercase' }}>
            Controls
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
            {/* Session filter */}
            {!running && (
              <>
                <div>
                  <div style={{ fontSize: 11, color: 'var(--text3)', marginBottom: 5, fontFamily: 'var(--font-mono)' }}>
                    Sessions (비워두면 모든 active 세션)
                  </div>
                  <div style={{ position: 'relative' }}>
                    <div
                      onClick={() => setSessionDropOpen(!sessionDropOpen)}
                      style={{ ...inputStyle, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'space-between', fontSize: 13 }}
                    >
                      <span style={{ color: sessionFilter.length ? 'var(--text1)' : 'var(--text3)' }}>
                        {sessionFilter.length ? sessionFilter.join(', ') : 'All active sessions'}
                      </span>
                      <ChevronDown size={13} style={{ color: 'var(--text3)', flexShrink: 0 }} />
                    </div>
                    {sessionDropOpen && (
                      <div style={{
                        position: 'absolute', top: '100%', left: 0, right: 0, zIndex: 20,
                        background: 'var(--bg1)', border: '1px solid var(--border-md)',
                        borderRadius: 7, boxShadow: '0 4px 16px rgba(0,0,0,0.1)',
                      }}>
                        <div
                          onClick={() => { setSessionFilter([]); setSessionDropOpen(false); }}
                          style={{ padding: '8px 12px', fontSize: 13, cursor: 'pointer', color: !sessionFilter.length ? 'var(--cyan)' : 'var(--text2)', fontFamily: 'var(--font-mono)', borderBottom: '1px solid var(--border)' }}
                        >
                          All active sessions
                        </div>
                        {sessions.map(s => (
                          <div
                            key={s}
                            onClick={() => {
                              setSessionFilter(prev =>
                                prev.includes(s) ? prev.filter(x => x !== s) : [...prev, s]
                              );
                            }}
                            style={{
                              padding: '8px 12px', fontSize: 13, cursor: 'pointer', fontFamily: 'var(--font-mono)',
                              display: 'flex', alignItems: 'center', gap: 8,
                              color: sessionFilter.includes(s) ? 'var(--cyan)' : 'var(--text1)',
                              background: sessionFilter.includes(s) ? 'var(--cyan-dim)' : 'transparent',
                            }}
                          >
                            <input type="checkbox" readOnly checked={sessionFilter.includes(s)} style={{ width: 13, height: 13 }} />
                            {s}
                          </div>
                        ))}
                      </div>
                    )}
                  </div>
                </div>
                <label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, cursor: 'pointer', fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>
                  <input type="checkbox" checked={dryRun} onChange={e => setDryRun(e.target.checked)} style={{ width: 14, height: 14 }} />
                  --dry-run (실행 없이 로그만)
                </label>
              </>
            )}
            <div style={{ display: 'flex', gap: 8 }}>
              {!running && (
                <button
                  style={{ ...btn('primary'), flex: 1, justifyContent: 'center', opacity: startMut.isPending ? 0.5 : 1 }}
                  onClick={() => startMut.mutate()}
                  disabled={startMut.isPending}
                >
                  {startMut.isPending
                    ? <><Loader size={13} /> Starting…</>
                    : <><Play size={13} /> Start Scheduler</>}
                </button>
              )}
              {running && (
                <button
                  style={{ ...btn('danger'), flex: 1, justifyContent: 'center', opacity: stopMut.isPending ? 0.5 : 1 }}
                  onClick={() => stopMut.mutate()}
                  disabled={stopMut.isPending}
                >
                  {stopMut.isPending
                    ? <><Loader size={13} /> Stopping…</>
                    : <><Square size={13} /> Stop Daemon</>}
                </button>
              )}
              <button
                style={{ ...btn('outline'), opacity: isLoading ? 0.5 : 1 }}
                onClick={() => setShowLog(!showLog)}
              >
                <ScrollText size={13} /> {showLog ? 'Hide Log' : 'View Log'}
              </button>
            </div>
          </div>
        </div>

        {/* Schedule */}
        <div style={{ ...card, flex: '0 0 auto', minWidth: 300 }}>
          <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--border)', fontSize: 12, fontFamily: 'var(--font-mono)', fontWeight: 600, color: 'var(--text2)', letterSpacing: '0.06em', textTransform: 'uppercase' }}>
            Today's Schedule (ET)
          </div>
          {schedule.map(ev => (
            <div key={ev.name} style={{
              padding: '10px 16px',
              borderBottom: '1px solid var(--border)',
              display: 'flex', alignItems: 'center', gap: 10,
              opacity: ev.past ? 0.45 : 1,
            }}>
              <div style={{
                width: 7, height: 7, borderRadius: '50%', flexShrink: 0,
                background: ev.past ? 'var(--text3)' : running ? 'var(--green)' : 'var(--border-md)',
              }} />
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 13, color: 'var(--text1)' }}>{ev.label}</div>
                <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>{ev.et_time}</div>
              </div>
              <div style={{ fontSize: 11, fontFamily: 'var(--font-mono)', color: ev.past ? 'var(--text3)' : 'var(--gold)' }}>
                {ev.past ? '✓' : fmtCountdown(ev.wait_secs - tick)}
              </div>
            </div>
          ))}
        </div>
      </div>

      {/* Log viewer */}
      {showLog && (
        <div style={{ ...card, overflow: 'hidden' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '10px 16px', borderBottom: '1px solid var(--border)', background: 'var(--bg1)' }}>
            <ScrollText size={13} style={{ color: 'var(--text3)' }} />
            <span style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text2)', fontWeight: 600 }}>Scheduler Log</span>
            {logData && (
              <span style={{ fontSize: 11, color: 'var(--text3)', fontFamily: 'var(--font-mono)' }}>{logData.lines} lines</span>
            )}
            {running && (
              <span style={{ fontSize: 11, color: 'var(--green)', fontFamily: 'var(--font-mono)', display: 'flex', alignItems: 'center', gap: 4 }}>
                <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--green)', display: 'inline-block', animation: 'pulse 1.5s ease-in-out infinite' }} />
                live
              </span>
            )}
          </div>
          <div
            ref={logRef}
            style={{ overflowY: 'auto', maxHeight: 420 }}
          >
            {logData?.log
              ? logData.log.split('\n').filter(Boolean).map((line, i) => {
                  const m = line.match(/^(\d{2}:\d{2} UTC)\s{2}(.*)$/);
                  const ts = m?.[1] ?? '';
                  const msg = m?.[2] ?? line;
                  const isError = msg.includes('ERROR');
                  const isDone = msg.startsWith('✓');
                  const isSection = msg.startsWith('━━━');
                  const isArrow = msg.trimStart().startsWith('▶');
                  const isDry = msg.includes('[DRY]') || msg.includes('DRY RUN');
                  const msgColor = isError ? 'var(--red)' : isDone ? 'var(--green)' : isSection ? 'var(--cyan)' : isArrow ? 'var(--text1)' : isDry ? 'var(--text3)' : 'var(--text2)';
                  if (isSection) {
                    return (
                      <div key={i} style={{ padding: '5px 16px', fontSize: 11, fontFamily: 'var(--font-mono)', color: msgColor, borderTop: '1px solid var(--border)', borderBottom: '1px solid var(--border)', background: 'var(--bg1)', fontWeight: 600, letterSpacing: '0.03em' }}>
                        {msg}
                      </div>
                    );
                  }
                  return (
                    <div key={i} style={{ display: 'flex', gap: 12, padding: '3px 16px', borderBottom: '1px solid var(--border)' }}>
                      <span style={{ flexShrink: 0, fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text3)', minWidth: 56, paddingTop: 1 }}>{ts}</span>
                      <span style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: msgColor, whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}>{msg}</span>
                    </div>
                  );
                })
              : (
                <div style={{ padding: '20px 16px', fontSize: 13, color: 'var(--text3)', textAlign: 'center', fontStyle: 'italic' }}>
                  No log output yet.
                </div>
              )
            }
          </div>
        </div>
      )}
    </div>
  );
}

// ── Main Page ────────────────────────────────────────────────────────────────

export function PaperTradingPage() {
  const [selectedId, setSelectedId] = useState<string | null>(null);
  const [view, setView] = useState<'session' | 'auto'>('session');
  const [showCreate, setShowCreate] = useState(false);
  const qc = useQueryClient();

  const { data, isLoading, error, refetch, isFetching } = useQuery({
    queryKey: ['paper-sessions'],
    queryFn: () => paperApi.sessions(),
    refetchInterval: 30_000,
  });

  const sessions = data?.sessions ?? [];
  const selected = sessions.find(s => s.session_id === selectedId || s.session_name === selectedId) ?? null;

  // Auto-select first session
  useEffect(() => {
    if (!selectedId && sessions.length > 0) {
      setSelectedId(sessions[0].session_id);
    }
  }, [sessions]);

  function handleCreated(s: { session_id: string; name: string }) {
    setShowCreate(false);
    qc.invalidateQueries({ queryKey: ['paper-sessions'] });
    setSelectedId(s.session_id);
  }

  const activeCount = sessions.filter(s => s.status === 'active').length;

  return (
    <div style={{ display: 'flex', height: '100vh', overflow: 'hidden' }} className="fade-up">
      <style>{`
        @keyframes spin { to { transform: rotate(360deg); } }
        @keyframes pulse { 0%,100% { opacity:1 } 50% { opacity:0.4 } }
        .terminal-scroll { scrollbar-width: thin; scrollbar-color: rgba(255,255,255,0.2) transparent; }
        .terminal-scroll::-webkit-scrollbar { width: 7px; }
        .terminal-scroll::-webkit-scrollbar-track { background: transparent; }
        .terminal-scroll::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.18); border-radius: 4px; }
        .terminal-scroll::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.32); }
      `}</style>

      {/* Session sidebar */}
      <div style={{
        width: 280,
        flexShrink: 0,
        background: 'var(--bg1)',
        borderRight: '1px solid var(--border)',
        display: 'flex',
        flexDirection: 'column',
        height: '100%',
        overflow: 'hidden',
      }}>
        {/* Sidebar header */}
        <div style={{ padding: '20px 16px 14px', borderBottom: '1px solid var(--border)', flexShrink: 0 }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <LineChartIcon size={16} style={{ color: 'var(--green)' }} />
              <h1 style={{ fontSize: 17, fontWeight: 700, color: 'var(--text1)' }}>Paper Trading</h1>
            </div>
            <button
              onClick={() => refetch()}
              style={{ ...btn('ghost'), padding: '4px 6px', border: 'none' }}
            >
              <RotateCcw size={13} style={{ animation: isFetching ? 'spin 1s linear infinite' : 'none' }} />
            </button>
          </div>
          <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
            <span style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>
              {sessions.length} sessions · {activeCount} active
            </span>
            <button
              style={{ ...btn('primary'), marginLeft: 'auto', padding: '5px 10px', fontSize: 12 }}
              onClick={() => { setView('session'); setShowCreate(true); }}
            >
              <Plus size={12} /> New
            </button>
          </div>
        </div>

        {/* Auto daemon button */}
        <div
          onClick={() => setView(view === 'auto' ? 'session' : 'auto')}
          style={{
            padding: '11px 16px',
            cursor: 'pointer',
            borderBottom: '1px solid var(--border)',
            display: 'flex', alignItems: 'center', gap: 8,
            background: view === 'auto' ? 'var(--cyan-dim)' : 'transparent',
            borderLeft: `3px solid ${view === 'auto' ? 'var(--cyan)' : 'transparent'}`,
            transition: 'all 0.1s',
          }}
          onMouseEnter={e => { if (view !== 'auto') e.currentTarget.style.background = 'var(--bg2)'; }}
          onMouseLeave={e => { if (view !== 'auto') e.currentTarget.style.background = 'transparent'; }}
        >
          <Cpu size={14} style={{ color: view === 'auto' ? 'var(--cyan)' : 'var(--text3)' }} />
          <span style={{ fontSize: 14, fontWeight: 500, color: view === 'auto' ? 'var(--cyan)' : 'var(--text2)' }}>
            Auto Scheduler
          </span>
          <AutoDaemonBadge />
        </div>

        {/* Session list */}
        <div style={{ flex: 1, overflowY: 'auto' }}>
          {isLoading && <div style={{ padding: 20 }}><Loading /></div>}
          {error && <div style={{ padding: 16 }}><ErrorState error={error as Error} /></div>}
          {!isLoading && sessions.length === 0 && (
            <div style={{ padding: '32px 16px', textAlign: 'center', color: 'var(--text3)', fontSize: 13, lineHeight: 1.7 }}>
              No sessions yet.<br />
              <button style={{ color: 'var(--cyan)', background: 'none', border: 'none', cursor: 'pointer', fontSize: 13 }} onClick={() => setShowCreate(true)}>
                Create your first session
              </button>
            </div>
          )}
          {sessions.map(s => (
            <SessionItem
              key={s.session_id}
              session={s}
              selected={view === 'session' && s.session_id === selected?.session_id}
              onClick={() => { setView('session'); setSelectedId(s.session_id); }}
            />
          ))}
        </div>
      </div>

      {/* Main content area */}
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden', background: 'var(--bg)' }}>
        {/* Auto daemon view */}
        {view === 'auto' && (
          <div style={{ flex: 1, overflowY: 'auto', padding: '24px 28px' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 9, marginBottom: 20 }}>
              <Cpu size={16} style={{ color: 'var(--cyan)' }} />
              <h2 style={{ fontSize: 20, fontWeight: 700, color: 'var(--text1)' }}>Auto Scheduler</h2>
              <span style={{ fontSize: 12, color: 'var(--text3)', fontFamily: 'var(--font-mono)' }}>
                ET 장 스케줄 자동 실행
              </span>
            </div>
            <AutoDaemonPanel
              sessions={sessions.filter(s => s.status === 'active').map(s => s.session_name)}
            />
          </div>
        )}

        {/* Session view */}
        {view === 'session' && !selected && !isLoading && (
          <div style={{
            flex: 1, display: 'flex', flexDirection: 'column',
            alignItems: 'center', justifyContent: 'center', gap: 16, color: 'var(--text3)',
          }}>
            <LineChartIcon size={40} style={{ opacity: 0.3 }} />
            <div style={{ fontSize: 16, fontWeight: 500 }}>Select a session</div>
            <div style={{ fontSize: 13 }}>
              or{' '}
              <button
                style={{ color: 'var(--cyan)', background: 'none', border: 'none', cursor: 'pointer', fontSize: 13 }}
                onClick={() => setShowCreate(true)}
              >
                create a new one
              </button>
            </div>
          </div>
        )}
        {view === 'session' && selected && (
          <SessionDetail
            key={selected.session_id}
            session={selected}
            onRefresh={() => {
              qc.invalidateQueries({ queryKey: ['paper-sessions'] });
              qc.invalidateQueries({ queryKey: ['paper-session', selected.session_id] });
            }}
          />
        )}
      </div>

      {showCreate && (
        <CreateSessionModal
          onClose={() => setShowCreate(false)}
          onCreated={handleCreated}
        />
      )}
    </div>
  );
}
