import { useState, useEffect, useRef } from 'react';
import { useMutation, useQuery } from '@tanstack/react-query';
import {
  Target, Radar, CheckCircle2, XCircle, AlertCircle, Clock,
  TrendingDown, ChevronRight, RefreshCw, Minus, Plus,
} from 'lucide-react';
import {
  orbScannerApi,
  type OrbCheckResponse,
  type OrbExitCheckResponse,
  type GainersScanResponse,
  type GainerResult,
  type StrategiesResponse,
} from '../api/client';
import { Loading } from '../components/common/Loading';

// ── Styles ────────────────────────────────────────────────────────────────────

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

const inputStyle: React.CSSProperties = {
  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',
  width: '100%',
  boxSizing: 'border-box' as const,
};

const btn = (variant: 'primary' | 'danger' | 'ghost' | 'outline' = 'outline'): React.CSSProperties => ({
  display: 'inline-flex', alignItems: 'center', gap: 6,
  padding: '7px 16px', 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)',
});

const label: React.CSSProperties = {
  fontSize: 11, fontWeight: 600, color: 'var(--text3)',
  textTransform: 'uppercase' as const, letterSpacing: '0.06em',
  marginBottom: 4, display: 'block',
};

// ── Signal badge ──────────────────────────────────────────────────────────────

type Signal = 'ENTRY' | 'SCALE_ENTRY' | 'NO_ENTRY' | 'NOT_YET' | 'MARKET_CLOSED' | 'ERROR';

const SIGNAL_COLORS: Record<Signal, { bg: string; color: string; label: string }> = {
  ENTRY:        { bg: 'var(--green)',  color: '#fff', label: 'ENTRY' },
  SCALE_ENTRY:  { bg: 'var(--orange)', color: '#fff', label: 'SCALE ENTRY' },
  NO_ENTRY:     { bg: 'var(--red)',    color: '#fff', label: 'NO ENTRY' },
  NOT_YET:      { bg: 'var(--gold)',   color: '#fff', label: 'NOT YET' },
  MARKET_CLOSED:{ bg: 'var(--text3)', color: '#fff', label: 'CLOSED' },
  ERROR:        { bg: '#888',          color: '#fff', label: 'ERROR' },
};

function SignalBadge({ signal, large }: { signal: Signal; large?: boolean }) {
  const cfg = SIGNAL_COLORS[signal] ?? SIGNAL_COLORS.ERROR;
  return (
    <span style={{
      background: cfg.bg, color: cfg.color,
      borderRadius: 6, fontWeight: 700,
      fontSize: large ? 18 : 12,
      padding: large ? '6px 18px' : '3px 9px',
      letterSpacing: large ? '0.04em' : '0.05em',
    }}>
      {cfg.label}
    </span>
  );
}

// ── Filter table ──────────────────────────────────────────────────────────────

interface FilterItem {
  name: string;
  passed: boolean;
  value: string | null;
  threshold: string | null;
  note: string | null;
}

function FilterTable({ filters }: { filters: FilterItem[] }) {
  return (
    <div style={{ overflowX: 'auto' }}>
      <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
        <thead>
          <tr style={{ borderBottom: '1px solid var(--border)' }}>
            {['Filter', 'Value', 'Threshold', 'Pass'].map(h => (
              <th key={h} style={{ padding: '7px 12px', textAlign: 'left', fontSize: 11, color: 'var(--text3)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.05em' }}>{h}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {filters.map((f, i) => (
            <tr key={i} style={{ borderBottom: '1px solid var(--border-subtle)', background: i % 2 === 0 ? 'transparent' : 'var(--bg2)' }}>
              <td style={{ padding: '7px 12px', color: 'var(--text2)', fontWeight: 500 }}>{f.name}</td>
              <td style={{ padding: '7px 12px', fontFamily: 'var(--font-mono)', color: f.passed ? 'var(--green)' : 'var(--red)' }}>
                {f.value ?? '—'}
                {f.note && <span style={{ marginLeft: 6, fontSize: 11, color: 'var(--orange)', fontStyle: 'italic' }}>{f.note}</span>}
              </td>
              <td style={{ padding: '7px 12px', fontFamily: 'var(--font-mono)', color: 'var(--text3)', fontSize: 12 }}>{f.threshold ?? '—'}</td>
              <td style={{ padding: '7px 12px' }}>
                {f.passed
                  ? <CheckCircle2 size={15} color="var(--green)" />
                  : <XCircle size={15} color="var(--red)" />}
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

// ── Entry details card ────────────────────────────────────────────────────────

function EntryDetailsCard({ details }: { details: Record<string, unknown> }) {
  const fmt = (v: unknown, dp = 2) => (typeof v === 'number' ? v.toFixed(dp) : v != null ? String(v) : '—');
  const items = [
    { label: 'Entry Price', value: `$${fmt(details.entry_price)}` },
    { label: 'ATR at Entry', value: fmt(details.atr_at_entry, 3) },
    { label: 'RVOL', value: details.rvol != null ? `${fmt(details.rvol, 1)}x` : '—' },
    { label: 'Gap%', value: details.gap_pct != null ? `${((details.gap_pct as number) * 100).toFixed(2)}%` : '—' },
    { label: 'Direction', value: fmt(details.orb_direction) },
    { label: 'Body Ratio', value: fmt(details.body_ratio, 3) },
    { label: 'Close Loc', value: fmt(details.close_location, 3) },
    { label: 'Premarket $Vol', value: details.premarket_dollar_vol != null ? `$${((details.premarket_dollar_vol as number) / 1e6).toFixed(2)}M` : '—' },
    ...(details.hot_reclaim_size_scale != null && (details.hot_reclaim_size_scale as number) < 1.0
      ? [{ label: 'Size Scale', value: `${fmt(details.hot_reclaim_size_scale, 2)}x (hot reclaim)` }]
      : []),
  ];
  return (
    <div style={{ ...card, padding: '16px 20px', marginTop: 16, borderColor: 'var(--cyan)' }}>
      <div style={{ marginBottom: 10, fontSize: 12, fontWeight: 700, color: 'var(--cyan)', textTransform: 'uppercase', letterSpacing: '0.07em' }}>Entry Details</div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(160px, 1fr))', gap: '10px 20px' }}>
        {items.map(item => (
          <div key={item.label}>
            <div style={label}>{item.label}</div>
            <div style={{ fontFamily: 'var(--font-mono)', fontSize: 14, color: 'var(--text1)', fontWeight: 600 }}>{item.value}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ── Single Check panel ────────────────────────────────────────────────────────

function SingleCheckPanel({ onSelectTicker, selectedStrategy }: { onSelectTicker: (ticker: string, details: Record<string, unknown>) => void; selectedStrategy: string }) {
  const [ticker, setTicker] = useState('');

  const checkMut = useMutation({
    mutationFn: (t: string) => orbScannerApi.check({ ticker: t, strategy: selectedStrategy }),
  });

  const handleCheck = () => {
    if (!ticker.trim()) return;
    checkMut.mutate(ticker.trim().toUpperCase());
  };

  const result = checkMut.data as OrbCheckResponse | undefined;

  return (
    <div>
      {/* Input row */}
      <div style={{ display: 'flex', gap: 10, marginBottom: 20, alignItems: 'flex-end' }}>
        <div style={{ flex: '0 0 200px' }}>
          <span style={label}>Ticker Symbol</span>
          <input
            style={inputStyle}
            value={ticker}
            onChange={e => setTicker(e.target.value.toUpperCase())}
            onKeyDown={e => e.key === 'Enter' && handleCheck()}
            placeholder="e.g. NVDA"
            maxLength={10}
          />
        </div>
        <button style={btn('primary')} onClick={handleCheck} disabled={checkMut.isPending}>
          {checkMut.isPending ? <RefreshCw size={14} style={{ animation: 'spin 1s linear infinite' }} /> : <Target size={14} />}
          {checkMut.isPending ? 'Checking…' : 'Check Entry'}
        </button>
      </div>

      {checkMut.isPending && <Loading />}

      {checkMut.isError && (
        <div style={{ color: 'var(--red)', fontSize: 13, padding: '10px 0' }}>
          Error: {(checkMut.error as Error).message}
        </div>
      )}

      {result && (
        <div>
          {/* Status row */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 16, marginBottom: 16 }}>
            <SignalBadge signal={result.overall_signal as Signal} large />
            <div>
              <div style={{ fontFamily: 'var(--font-mono)', fontSize: 16, fontWeight: 700, color: 'var(--text1)' }}>{result.ticker}</div>
              <div style={{ fontSize: 12, color: 'var(--text3)' }}>{result.asof} · evaluated {new Date(result.evaluated_at).toLocaleTimeString()}</div>
            </div>
          </div>

          {result.warning && (
            <div style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '8px 12px', borderRadius: 7, background: 'color-mix(in srgb, var(--gold) 10%, transparent)', border: '1px solid color-mix(in srgb, var(--gold) 25%, transparent)', fontSize: 12, color: 'var(--gold)', marginBottom: 14 }}>
              <AlertCircle size={13} />{result.warning}
            </div>
          )}

          {result.filters.length > 0 && (
            <div style={card}>
              <FilterTable filters={result.filters} />
            </div>
          )}

          {result.entry_details && <EntryDetailsCard details={result.entry_details} />}

          {result.overall_signal === 'ENTRY' && result.entry_details && (
            <button
              style={{ ...btn('outline'), marginTop: 14 }}
              onClick={() => onSelectTicker(result.ticker, result.entry_details!)}
            >
              <ChevronRight size={14} />
              Open in Exit Monitor
            </button>
          )}
        </div>
      )}
    </div>
  );
}

// ── Exit Monitor panel ────────────────────────────────────────────────────────

interface Position {
  id: string;
  ticker: string;
  entryPrice: number | null;   // null = auto (current market price)
  atrAtEntry: number | null;   // null = auto from daily enrichment
  entryMode: 'now' | 'time';
  entryTime: string;
  addedAt: string;             // local time string when position was added, e.g. "14:32"
  strategy: string;            // locked at add-time
}

interface PositionStatus {
  isPending: boolean;
  result: OrbExitCheckResponse | null;
  error: string | null;
  lastChecked: Date | null;
}

const PHASE_LABELS: Record<string, string> = {
  initial: 'Initial', breakeven: 'Breakeven', trailing: 'Trailing',
  trailing_tight: 'Tight', force_exit: 'Force Exit',
};
const PHASE_COLORS: Record<string, string> = {
  initial: 'var(--text3)', breakeven: 'var(--cyan)', trailing: 'var(--green)',
  trailing_tight: 'var(--purple)', force_exit: 'var(--red)',
};

const POSITIONS_KEY = 'orb-monitor-positions';

function loadPositions(): Position[] {
  try {
    const raw = localStorage.getItem(POSITIONS_KEY);
    return raw ? (JSON.parse(raw) as Position[]) : [];
  } catch { return []; }
}

function ExitMonitorPanel({ prefill, selectedStrategy }: { prefill?: { ticker: string; details: Record<string, unknown> }; selectedStrategy: string }) {
  const [positions, setPositions] = useState<Position[]>(loadPositions);
  const [statuses, setStatuses] = useState<Record<string, PositionStatus>>({});
  const [form, setForm] = useState({ ticker: '', entryPrice: '', atrAtEntry: '', entryMode: 'now' as 'now' | 'time', entryTime: '09:35' });
  const [formError, setFormError] = useState<string | null>(null);
  const [autoRefresh, setAutoRefresh] = useState(() => {
    try { return localStorage.getItem('orb-monitor-autorefresh') === '1'; } catch { return false; }
  });
  const [countdown, setCountdown] = useState(300);
  const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);
  const positionsRef = useRef<Position[]>([]);

  useEffect(() => { positionsRef.current = positions; }, [positions]);

  // Persist positions and autoRefresh to localStorage
  useEffect(() => {
    try { localStorage.setItem(POSITIONS_KEY, JSON.stringify(positions)); } catch {}
  }, [positions]);

  useEffect(() => {
    try { localStorage.setItem('orb-monitor-autorefresh', autoRefresh ? '1' : '0'); } catch {}
  }, [autoRefresh]);

  // Re-check all restored positions on mount
  const didMountRef = useRef(false);
  useEffect(() => {
    if (!didMountRef.current) {
      didMountRef.current = true;
      if (positions.length > 0) {
        positions.forEach(pos => checkPosition(pos));
      }
    }
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  useEffect(() => {
    if (prefill) {
      const d = prefill.details;
      setForm(prev => ({
        ...prev,
        ticker: prefill.ticker,
        entryPrice: d.entry_price != null ? String((d.entry_price as number).toFixed(2)) : prev.entryPrice,
        atrAtEntry: d.atr_at_entry != null ? String((d.atr_at_entry as number).toFixed(4)) : prev.atrAtEntry,
      }));
    }
  }, [prefill]);

  const checkPosition = async (pos: Position) => {
    setStatuses(prev => ({ ...prev, [pos.id]: { ...(prev[pos.id] ?? { result: null, lastChecked: null }), isPending: true, error: null } }));
    try {
      const result = await orbScannerApi.exitCheck({
        ticker: pos.ticker,
        entry_price: pos.entryPrice ?? null,
        atr_at_entry: pos.atrAtEntry ?? null,
        entry_time: pos.entryMode === 'time' ? pos.entryTime : null,
        strategy: pos.strategy,
      });
      // Lock in auto-resolved entry_price and ATR for subsequent checks
      if (pos.entryPrice === null && result.entry_price_used != null) {
        setPositions(prev => prev.map(p =>
          p.id === pos.id ? { ...p, entryPrice: result.entry_price_used!, atrAtEntry: result.atr_at_entry_used ?? p.atrAtEntry } : p
        ));
      }
      setStatuses(prev => ({ ...prev, [pos.id]: { isPending: false, result, error: null, lastChecked: new Date() } }));
    } catch (e) {
      setStatuses(prev => ({ ...prev, [pos.id]: { ...(prev[pos.id] ?? { result: null, lastChecked: null }), isPending: false, error: (e as Error).message } }));
    }
  };

  const checkAll = () => {
    positionsRef.current.forEach(pos => checkPosition(pos));
    setCountdown(300);
  };

  const addPosition = () => {
    if (!form.ticker) { setFormError('Ticker를 입력하세요'); return; }
    let ep: number | null = null;
    let atr: number | null = null;
    if (form.entryMode === 'now') {
      // Auto-fetch from backend; entry price = current market price
    } else {
      const epVal = parseFloat(form.entryPrice);
      const atrVal = parseFloat(form.atrAtEntry);
      if (!form.entryPrice || isNaN(epVal)) { setFormError('Entry Price를 입력하세요'); return; }
      if (!form.atrAtEntry || isNaN(atrVal)) { setFormError('ATR at Entry를 입력하세요'); return; }
      ep = epVal;
      atr = atrVal;
    }
    const now = new Date();
    const addedAt = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`;
    const pos: Position = {
      id: `${form.ticker}-${Date.now()}`,
      ticker: form.ticker,
      entryPrice: ep,
      atrAtEntry: atr,
      entryMode: form.entryMode,
      entryTime: form.entryTime,
      addedAt,
      strategy: selectedStrategy,
    };
    setPositions(prev => [...prev, pos]);
    setStatuses(prev => ({ ...prev, [pos.id]: { isPending: true, result: null, error: null, lastChecked: null } }));
    setFormError(null);
    setForm(prev => ({ ...prev, ticker: '' }));
    setTimeout(() => checkPosition(pos), 0);
  };

  const removePosition = (id: string) => {
    setPositions(prev => prev.filter(p => p.id !== id));
    setStatuses(prev => { const s = { ...prev }; delete s[id]; return s; });
  };

  useEffect(() => {
    if (!autoRefresh) {
      if (timerRef.current) clearInterval(timerRef.current);
      return;
    }
    timerRef.current = setInterval(() => {
      setCountdown(c => {
        if (c <= 1) {
          positionsRef.current.forEach(pos => checkPosition(pos));
          return 300;
        }
        return c - 1;
      });
    }, 1000);
    return () => { if (timerRef.current) clearInterval(timerRef.current); };
  }, [autoRefresh]);

  return (
    <div>
      {/* Add position form */}
      <div style={{ ...card, padding: '16px', marginBottom: 16 }}>
        <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--text3)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 10 }}>
          Add Position
        </div>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10, marginBottom: 10 }}>
          <div style={{ flex: '0 0 110px' }}>
            <span style={label}>Ticker</span>
            <input
              style={inputStyle}
              value={form.ticker}
              onChange={e => setForm(prev => ({ ...prev, ticker: e.target.value.toUpperCase() }))}
              onKeyDown={e => e.key === 'Enter' && addPosition()}
              placeholder="NVDA"
              maxLength={10}
            />
          </div>
          {form.entryMode !== 'now' && (
            <>
              <div style={{ flex: 1, minWidth: 110 }}>
                <span style={label}>Entry Price</span>
                <input style={inputStyle} value={form.entryPrice} onChange={e => setForm(prev => ({ ...prev, entryPrice: e.target.value }))} placeholder="200.50" />
              </div>
              <div style={{ flex: 1, minWidth: 110 }}>
                <span style={label}>ATR at Entry</span>
                <input style={inputStyle} value={form.atrAtEntry} onChange={e => setForm(prev => ({ ...prev, atrAtEntry: e.target.value }))} placeholder="2.40" />
              </div>
            </>
          )}
          <div style={{ flex: '0 0 auto' }}>
            <span style={label}>Entry Time (ET)</span>
            <div style={{ display: 'flex', gap: 6 }}>
              <button style={{ ...btn(form.entryMode === 'now' ? 'primary' : 'outline') }} onClick={() => setForm(prev => ({ ...prev, entryMode: 'now' }))}>
                <Clock size={12} /> Current
              </button>
              <button style={{ ...btn(form.entryMode === 'time' ? 'primary' : 'outline') }} onClick={() => setForm(prev => ({ ...prev, entryMode: 'time' }))}>
                Specify
              </button>
              {form.entryMode === 'time' && (
                <input style={{ ...inputStyle, width: 68 }} value={form.entryTime} onChange={e => setForm(prev => ({ ...prev, entryTime: e.target.value }))} placeholder="09:35" />
              )}
            </div>
          </div>
        </div>
        {formError && <div style={{ color: 'var(--red)', fontSize: 12, marginBottom: 8 }}>{formError}</div>}
        <button style={btn('primary')} onClick={addPosition}>
          <Plus size={14} /> Add & Check
        </button>
      </div>

      {/* Controls */}
      {positions.length > 0 && (
        <div style={{ display: 'flex', gap: 10, alignItems: 'center', marginBottom: 16 }}>
          <button style={btn('outline')} onClick={checkAll}>
            <RefreshCw size={13} /> Check All Now
          </button>
          <button style={{ ...btn(autoRefresh ? 'danger' : 'outline') }} onClick={() => { setAutoRefresh(a => !a); setCountdown(300); }}>
            <Clock size={13} />
            {autoRefresh ? `Auto OFF (${countdown}s)` : 'Auto 5min'}
          </button>
        </div>
      )}

      {/* Position cards — 3-column grid */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12 }}>
        {positions.map(pos => {
          const status = statuses[pos.id];
          const r = status?.result;
          const phaseColor = PHASE_COLORS[r?.stop_phase ?? 'initial'] ?? 'var(--text3)';
          return (
            <div key={pos.id} style={{ ...card, padding: '14px 16px', borderColor: r ? (r.should_exit ? 'var(--red)' : 'var(--green)') : 'var(--border)' }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: r ? 10 : 0 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <span style={{ fontFamily: 'var(--font-mono)', fontWeight: 700, fontSize: 15 }}>{pos.ticker}</span>
                  {status?.isPending && <RefreshCw size={12} style={{ color: 'var(--text3)', animation: 'spin 1s linear infinite' }} />}
                  {r && (
                    <span style={{ fontSize: 11, fontWeight: 700, padding: '2px 8px', borderRadius: 5, background: r.should_exit ? 'var(--red)' : 'var(--green)', color: '#fff' }}>
                      {r.should_exit ? 'EXIT NOW' : 'HOLD'}
                    </span>
                  )}
                </div>
                <button style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--text3)', padding: '0 2px', fontSize: 16, lineHeight: 1 }} onClick={() => removePosition(pos.id)} title="Remove">×</button>
              </div>
              {status?.error && <div style={{ color: 'var(--red)', fontSize: 12 }}>{status.error}</div>}
              {r && (() => {
                const entryPx = r.entry_price_used ?? pos.entryPrice ?? 0;
                const pnlPct = entryPx > 0 ? (r.current_price - entryPx) / entryPx * 100 : null;
                const pnlColor = pnlPct == null ? 'var(--text3)' : pnlPct > 0 ? 'var(--green)' : pnlPct < 0 ? 'var(--red)' : 'var(--text3)';
                const entryLabel = `Entry @ ${pos.entryMode === 'now' ? pos.addedAt : (r.entry_time_used ?? pos.entryTime)}`;
                return (
                  <>
                    {/* Primary row: entry → current → P&L */}
                    <div style={{ display: 'grid', gridTemplateColumns: '1fr auto 1fr 1fr', alignItems: 'center', gap: '0 6px', marginBottom: 10 }}>
                      <div>
                        <div style={label}>{entryLabel}</div>
                        <div style={{ fontFamily: 'var(--font-mono)', fontSize: 16, fontWeight: 700, color: 'var(--text2)' }}>${entryPx.toFixed(2)}</div>
                      </div>
                      <div style={{ color: 'var(--text3)', fontSize: 14, paddingTop: 14 }}>→</div>
                      <div>
                        <div style={label}>Current</div>
                        <div style={{ fontFamily: 'var(--font-mono)', fontSize: 16, fontWeight: 700, color: 'var(--text1)' }}>${r.current_price.toFixed(2)}</div>
                      </div>
                      <div>
                        <div style={label}>P&L</div>
                        <div style={{ fontFamily: 'var(--font-mono)', fontSize: 18, fontWeight: 800, color: pnlColor }}>
                          {pnlPct != null ? `${pnlPct >= 0 ? '+' : ''}${pnlPct.toFixed(2)}%` : '—'}
                        </div>
                      </div>
                    </div>
                    {/* Secondary row: stop / phase / peak / R */}
                    <div style={{ display: 'flex', gap: '6px 20px', flexWrap: 'wrap', paddingTop: 10, borderTop: '1px solid var(--border-subtle)' }}>
                      <span style={{ fontSize: 12, color: 'var(--text3)' }}>
                        Stop <span style={{ fontFamily: 'var(--font-mono)', color: 'var(--red)', fontWeight: 600 }}>${r.current_stop.toFixed(2)}</span>
                      </span>
                      <span style={{ fontSize: 12, color: 'var(--text3)' }}>
                        Phase <span style={{ fontWeight: 600, color: phaseColor, textTransform: 'uppercase' }}>{PHASE_LABELS[r.stop_phase] ?? r.stop_phase}</span>
                      </span>
                      <span style={{ fontSize: 12, color: 'var(--text3)' }}>
                        Peak <span style={{ fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>${r.peak_price.toFixed(2)}</span>
                      </span>
                      <span style={{ fontSize: 12, color: 'var(--text3)' }}>
                        R <span style={{ fontFamily: 'var(--font-mono)', color: r.r_multiple > 1 ? 'var(--green)' : r.r_multiple > 0 ? 'var(--gold)' : 'var(--red)', fontWeight: 600 }}>{r.r_multiple > 0 ? '+' : ''}{r.r_multiple.toFixed(2)}</span>
                      </span>
                    </div>
                  </>
                );
              })()}
              {!r && !status?.isPending && (
                <div style={{ color: 'var(--text3)', fontSize: 12 }}>Checking…</div>
              )}
            </div>
          );
        })}
      </div>

      {positions.length === 0 && (
        <div style={{ color: 'var(--text3)', fontSize: 13, textAlign: 'center', padding: '32px 0' }}>
          포지션을 추가하세요. "Current" 모드: Ticker만 입력하면 현재가 자동 사용. "Specify" 모드: 매수 시간 직접 입력.
        </div>
      )}
    </div>
  );
}

// ── Gainers Scan panel ────────────────────────────────────────────────────────

const SIGNAL_ORDER: Record<string, number> = { ENTRY: 0, SCALE_ENTRY: 1, NO_ENTRY: 2 };

function GainersScanPanel({ onSelectTicker, selectedStrategy }: { onSelectTicker: (ticker: string) => void; selectedStrategy: string }) {
  const [showAll, setShowAll] = useState(false);

  const scanMut = useMutation({
    mutationFn: () => orbScannerApi.gainersScan(200, selectedStrategy),
  });

  const result = scanMut.data as GainersScanResponse | undefined;

  const sorted = result
    ? [...result.results].sort((a, b) => (SIGNAL_ORDER[a.signal] ?? 3) - (SIGNAL_ORDER[b.signal] ?? 3))
    : [];

  const passed = sorted.filter(r => r.signal !== 'NO_ENTRY');
  const failed = sorted.filter(r => r.signal === 'NO_ENTRY');
  const displayList = showAll ? sorted : [...passed, ...failed.slice(0, 5)];

  return (
    <div>
      <div style={{ display: 'flex', gap: 10, alignItems: 'center', marginBottom: 20 }}>
        <button style={btn('primary')} onClick={() => scanMut.mutate()} disabled={scanMut.isPending}>
          {scanMut.isPending ? <RefreshCw size={14} style={{ animation: 'spin 1s linear infinite' }} /> : <Radar size={14} />}
          {scanMut.isPending ? 'Scanning…' : 'Scan Gainers'}
        </button>
        <span style={{ fontSize: 12, color: 'var(--text3)' }}>
          Oracle gainers API · up to 200 tickers · {selectedStrategy}
        </span>
      </div>

      {scanMut.isPending && (
        <div style={{ padding: '20px 0' }}>
          <Loading />
          <div style={{ textAlign: 'center', marginTop: 10, fontSize: 12, color: 'var(--text3)' }}>
            Fetching gainers, running ORB simulation… (~5-10s)
          </div>
        </div>
      )}

      {scanMut.isError && (
        <div style={{ color: 'var(--red)', fontSize: 13 }}>
          Error: {(scanMut.error as Error).message}
        </div>
      )}

      {result && (
        <div>
          {/* Summary row */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 16, marginBottom: 16, flexWrap: 'wrap' }}>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
              <span style={{ fontFamily: 'var(--font-mono)', fontSize: 28, fontWeight: 800, color: result.count_passed > 0 ? 'var(--cyan)' : 'var(--text2)' }}>{result.count_passed}</span>
              <span style={{ fontSize: 14, color: 'var(--text3)' }}>/ {result.count_fetched} pass</span>
            </div>
            <div style={{ flex: 1, fontSize: 12, color: 'var(--text3)' }}>
              Scanned {new Date(result.scan_time).toLocaleTimeString()}
            </div>
            {result.market_status === 'closed' && (
              <div style={{ fontSize: 12, color: 'var(--text3)', background: 'var(--bg2)', padding: '4px 10px', borderRadius: 6 }}>
                Market closed — historical signal
              </div>
            )}
          </div>

          {/* Results table */}
          <div style={card}>
            <div style={{ overflowX: 'auto' }}>
              <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
                <thead>
                  <tr style={{ borderBottom: '1px solid var(--border)' }}>
                    {['Ticker', 'Price', 'Change%', 'Signal', 'Summary', 'Reason'].map(h => (
                      <th key={h} style={{ padding: '8px 12px', textAlign: 'left', fontSize: 11, color: 'var(--text3)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.05em' }}>{h}</th>
                    ))}
                  </tr>
                </thead>
                <tbody>
                  {displayList.map((r: GainerResult, i) => (
                    <tr
                      key={r.ticker}
                      style={{ borderBottom: '1px solid var(--border-subtle)', background: i % 2 === 0 ? 'transparent' : 'var(--bg2)', cursor: r.signal !== 'NO_ENTRY' ? 'pointer' : 'default' }}
                      onClick={() => r.signal !== 'NO_ENTRY' && onSelectTicker(r.ticker)}
                    >
                      <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', fontWeight: 700, color: r.signal === 'ENTRY' ? 'var(--cyan)' : r.signal === 'SCALE_ENTRY' ? 'var(--orange)' : 'var(--text2)' }}>
                        {r.ticker}
                      </td>
                      <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', color: 'var(--text1)' }}>
                        {r.price != null ? `$${r.price.toFixed(2)}` : '—'}
                      </td>
                      <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', color: r.change_pct != null && r.change_pct > 0 ? 'var(--green)' : 'var(--red)' }}>
                        {r.change_pct != null ? `${r.change_pct > 0 ? '+' : ''}${(r.change_pct * 100).toFixed(1)}%` : '—'}
                      </td>
                      <td style={{ padding: '8px 12px' }}>
                        <SignalBadge signal={r.signal as Signal} />
                        {r.scale_factor != null && r.scale_factor < 1.0 && (
                          <span style={{ marginLeft: 6, fontSize: 11, color: 'var(--orange)' }}>{r.scale_factor.toFixed(1)}x</span>
                        )}
                      </td>
                      <td style={{ padding: '8px 12px', fontSize: 12, color: 'var(--text2)', fontFamily: 'var(--font-mono)' }}>
                        {r.filter_summary}
                      </td>
                      <td style={{ padding: '8px 12px', fontSize: 12, color: 'var(--text3)', maxWidth: 200 }}>
                        {r.failure_reason ?? (r.signal !== 'NO_ENTRY' ? (
                          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, color: 'var(--cyan)' }}>
                            <ChevronRight size={12} />check single
                          </span>
                        ) : null)}
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>

          {failed.length > 5 && !showAll && (
            <button style={{ ...btn('ghost'), marginTop: 12, fontSize: 12 }} onClick={() => setShowAll(true)}>
              <Minus size={12} />
              Show all {failed.length} rejected tickers
            </button>
          )}
        </div>
      )}
    </div>
  );
}

// ── Main page ─────────────────────────────────────────────────────────────────

type Tab = 'check' | 'exit' | 'gainers';

const ORB_DEFAULT_STRATEGY = 'orb_gainers_v49_100_mid_hot_rtg_reserve';
const STRATEGY_KEY = 'orb-scanner-strategy';

export function OrbScannerPage() {
  const [activeTab, setActiveTab] = useState<Tab>('check');
  const [exitPrefill, setExitPrefill] = useState<{ ticker: string; details: Record<string, unknown> } | undefined>();
  const [selectedStrategy, setSelectedStrategy] = useState<string>(() => {
    try { return localStorage.getItem(STRATEGY_KEY) || ORB_DEFAULT_STRATEGY; } catch { return ORB_DEFAULT_STRATEGY; }
  });

  const { data: strategiesData } = useQuery<StrategiesResponse>({
    queryKey: ['orbStrategies'],
    queryFn: orbScannerApi.strategies,
    staleTime: Infinity,
  });

  useEffect(() => {
    try { localStorage.setItem(STRATEGY_KEY, selectedStrategy); } catch {}
  }, [selectedStrategy]);

  const handleSelectForExit = (ticker: string, details: Record<string, unknown>) => {
    setExitPrefill({ ticker, details });
    setActiveTab('exit');
  };

  const handleGainerClick = (_ticker: string) => {
    setActiveTab('check');
  };

  const tabs: { id: Tab; label: string; icon: React.ReactNode }[] = [
    { id: 'check',   label: 'Single Check',  icon: <Target size={14} /> },
    { id: 'exit',    label: 'Exit Monitor',   icon: <TrendingDown size={14} /> },
    { id: 'gainers', label: 'Gainers Scan',   icon: <Radar size={14} /> },
  ];

  const selectedName = strategiesData?.strategies.find(s => s.id === selectedStrategy)?.name ?? selectedStrategy;

  return (
    <div style={{ padding: '36px 40px', maxWidth: '80vw' }}>
      {/* Header */}
      <div style={{ marginBottom: 24, display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
        <Target size={22} color="var(--cyan)" />
        <div style={{ flex: 1 }}>
          <h1 style={{ margin: 0, fontSize: 22, fontWeight: 700, color: 'var(--text1)' }}>ORB Scanner</h1>
          <div style={{ fontSize: 12, color: 'var(--text3)', marginTop: 2 }}>{selectedName}</div>
        </div>
        {/* Strategy selector */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <span style={{ fontSize: 11, fontWeight: 600, color: 'var(--text3)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>Strategy</span>
          <select
            value={selectedStrategy}
            onChange={e => setSelectedStrategy(e.target.value)}
            style={{
              padding: '6px 10px',
              fontSize: 12,
              fontFamily: 'var(--font-mono)',
              background: 'var(--bg2)',
              border: '1px solid var(--border-md)',
              borderRadius: 7,
              color: 'var(--text1)',
              cursor: 'pointer',
              maxWidth: 320,
            }}
          >
            {(strategiesData?.strategies ?? [{ id: ORB_DEFAULT_STRATEGY, name: ORB_DEFAULT_STRATEGY }]).map(s => (
              <option key={s.id} value={s.id}>{s.name}</option>
            ))}
          </select>
        </div>
      </div>

      {/* Market status banner is shown inside tab content, driven by API responses */}

      {/* Tabs */}
      <div style={{ display: 'flex', gap: 4, marginBottom: 24, borderBottom: '1px solid var(--border)', paddingBottom: 0 }}>
        {tabs.map(tab => (
          <button
            key={tab.id}
            onClick={() => setActiveTab(tab.id)}
            style={{
              display: 'inline-flex', alignItems: 'center', gap: 7,
              padding: '8px 18px', fontSize: 13, fontWeight: activeTab === tab.id ? 600 : 400,
              background: 'transparent', border: 'none', cursor: 'pointer',
              borderBottom: activeTab === tab.id ? '2px solid var(--cyan)' : '2px solid transparent',
              marginBottom: -1,
              color: activeTab === tab.id ? 'var(--cyan)' : 'var(--text3)',
              transition: 'color 0.12s',
            }}
          >
            {tab.icon}{tab.label}
          </button>
        ))}
      </div>

      {/* Tab content */}
      <div style={card}>
        <div style={{ padding: '24px 28px' }}>
          {activeTab === 'check' && (
            <SingleCheckPanel
              onSelectTicker={handleSelectForExit}
              selectedStrategy={selectedStrategy}
            />
          )}
          {activeTab === 'exit' && (
            <ExitMonitorPanel prefill={exitPrefill} selectedStrategy={selectedStrategy} />
          )}
          {activeTab === 'gainers' && (
            <GainersScanPanel onSelectTicker={handleGainerClick} selectedStrategy={selectedStrategy} />
          )}
        </div>
      </div>
    </div>
  );
}
