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 {
  Zap, Play, Square, Plus, Trash2, Pause, RotateCcw,
  TrendingUp, TrendingDown, ChevronDown, PlayCircle, Eraser,
} from 'lucide-react';
import {
  orbTradingApi,
  type OrbSession,
  type OrbScheduleEvent,
  type OrbStrategyInfo,
} from '../api/client';
import { Loading, ErrorState } 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 = {
  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)',
});

function fmt(n: number, dp = 2) { return n.toFixed(dp); }
function fmtPct(n: number) { return `${n >= 0 ? '+' : ''}${n.toFixed(2)}%`; }
function fmtDollars(n: number) {
  return `${n >= 0 ? '+' : ''}$${Math.abs(n).toFixed(2)}`;
}

// ── Scheduler Panel ───────────────────────────────────────────────────────────

function SchedulerPanel({ selectedSessions }: { selectedSessions: string[] }) {
  const qc = useQueryClient();
  const [showLog, setShowLog] = useState(false);
  const logRef = useRef<HTMLPreElement>(null);

  const { data, isLoading } = useQuery({
    queryKey: ['orb-auto-status'],
    queryFn: orbTradingApi.autoStatus,
    refetchInterval: 5000,
  });

  const startMut = useMutation({
    mutationFn: () => orbTradingApi.autoStart(selectedSessions.length > 0 ? selectedSessions : []),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['orb-auto-status'] }),
    onError: (e: Error) => alert(`스케줄러 시작 실패: ${e.message}`),
  });

  const stopMut = useMutation({
    mutationFn: orbTradingApi.autoStop,
    onSuccess: () => qc.invalidateQueries({ queryKey: ['orb-auto-status'] }),
    onError: (e: Error) => alert(`스케줄러 중지 실패: ${e.message}`),
  });

  const clearLogMut = useMutation({
    mutationFn: orbTradingApi.clearLog,
    onSuccess: () => qc.invalidateQueries({ queryKey: ['orb-auto-status'] }),
  });

  const logLines = data?.log_tail ?? [];

  // Auto-scroll to bottom when new log lines arrive (must be before early return)
  useEffect(() => {
    if (showLog && logRef.current) {
      logRef.current.scrollTop = logRef.current.scrollHeight;
    }
  }, [logLines.length, showLog]);

  if (isLoading) return <div style={{ padding: 20 }}><Loading /></div>;

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

  // Find next upcoming event
  const nextEvent = schedule.find(e => !e.done && e.wait_secs > 0);

  return (
    <div style={{ ...card, marginBottom: 24 }}>
      <div style={{
        padding: '14px 20px',
        background: running ? 'color-mix(in srgb, var(--green) 8%, transparent)' : 'var(--bg2)',
        borderBottom: '1px solid var(--border)',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap',
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <div style={{
            width: 8, height: 8, borderRadius: '50%',
            background: running ? 'var(--green)' : 'var(--text3)',
            animation: running ? 'pulse-line 2s infinite' : 'none',
          }} />
          <span style={{ fontWeight: 600, fontSize: 15, color: 'var(--text1)' }}>
            ORB 자동 트레이딩 스케줄러
          </span>
          {running && data?.dry_run && (
            <span style={{ fontSize: 11, color: 'var(--orange)', background: 'color-mix(in srgb, var(--orange) 12%, transparent)', padding: '2px 8px', borderRadius: 4 }}>
              DRY RUN
            </span>
          )}
          {running && !data?.dry_run && (
            <span style={{ fontSize: 11, color: 'var(--green)', background: 'color-mix(in srgb, var(--green) 12%, transparent)', padding: '2px 8px', borderRadius: 4 }}>
              LIVE
            </span>
          )}
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          <button
            style={btn(running ? 'danger' : 'primary')}
            onClick={() => running ? stopMut.mutate() : startMut.mutate()}
            disabled={startMut.isPending || stopMut.isPending}
          >
            {running ? <><Square size={13} /> 중지</> : <><Play size={13} /> 시작</>}
          </button>
        </div>
      </div>

      {/* Schedule timeline — per-session rows */}
      <div style={{ padding: '12px 20px', borderBottom: '1px solid var(--border)', overflowX: 'auto' }}>
        {(() => {
          // Group events by session
          const sessionNames = Array.from(new Set(schedule.map((e: OrbScheduleEvent) => e.session))).filter(Boolean) as string[];

          const renderSessionRow = (sessionName: string) => {
            const sessionEvs = schedule.filter((e: OrbScheduleEvent) => e.session === sessionName);
            const breakouts = sessionEvs.filter((e: OrbScheduleEvent) => e.kind === 'breakout');
            const displayed = sessionEvs.filter((ev: OrbScheduleEvent) => {
              if (['orb_monitor', 'orb_detect', 'stop_check', 'eod_exit', 'post_close'].includes(ev.kind)) return true;
              if (ev.kind === 'breakout') return ev === breakouts[0] || ev === breakouts[breakouts.length - 1];
              return false;
            });
            const isNext = (ev: OrbScheduleEvent) => nextEvent && ev.name === nextEvent.name;

            return (
              <div key={sessionName} style={{ marginBottom: sessionNames.length > 1 ? 8 : 0 }}>
                {sessionNames.length > 1 && (
                  <div style={{ fontSize: 10, color: 'var(--text3)', marginBottom: 4, fontFamily: 'var(--font-mono)' }}>
                    {sessionName}
                  </div>
                )}
                <div style={{ display: 'flex', gap: 3, minWidth: 'max-content', flexWrap: 'nowrap' }}>
                  {displayed.map((ev: OrbScheduleEvent) => (
                    <div
                      key={ev.name}
                      title={`[${ev.session}] ${ev.label}\n${ev.et_time}${ev.done ? ' ✓' : ev.wait_secs > 0 ? ` — ${fmtCountdown(ev.wait_secs)}` : ''}`}
                      style={{
                        padding: '3px 7px',
                        borderRadius: 5,
                        fontSize: 10,
                        fontFamily: 'var(--font-mono)',
                        whiteSpace: 'nowrap',
                        background: ev.done
                          ? 'color-mix(in srgb, var(--green) 15%, transparent)'
                          : isNext(ev)
                          ? 'color-mix(in srgb, var(--cyan) 20%, transparent)'
                          : ev.kind === 'orb_monitor'
                          ? 'color-mix(in srgb, var(--yellow) 8%, transparent)'
                          : 'var(--bg2)',
                        color: ev.done ? 'var(--green)' : isNext(ev) ? 'var(--cyan)' : ev.kind === 'orb_monitor' ? 'color-mix(in srgb, var(--yellow) 70%, var(--text3))' : 'var(--text3)',
                        border: `1px solid ${ev.done ? 'var(--green)' : isNext(ev) ? 'var(--cyan)' : ev.kind === 'orb_monitor' ? 'color-mix(in srgb, var(--yellow) 30%, transparent)' : 'var(--border)'}`,
                        opacity: ev.kind === 'orb_monitor' && !ev.done && !isNext(ev) ? 0.65 : 1,
                      }}
                    >
                      {ev.et_time.replace(' ET', '')}
                      {ev.done && ' ✓'}
                      {ev.kind === 'breakout' && ev === breakouts[0] && breakouts.length > 1 && (
                        <span style={{ color: 'var(--text3)', marginLeft: 2 }}>
                          ~{breakouts[breakouts.length - 1]?.et_time?.replace(' ET', '')}
                        </span>
                      )}
                    </div>
                  ))}
                </div>
              </div>
            );
          };

          return sessionNames.length > 0 ? sessionNames.map(renderSessionRow) : (
            <div style={{ fontSize: 11, color: 'var(--text3)' }}>(스케줄 없음)</div>
          );
        })()}
        {nextEvent && (
          <div style={{ marginTop: 8, fontSize: 12, color: 'var(--text2)' }}>
            다음: <strong style={{ color: 'var(--cyan)' }}>{nextEvent.label}</strong>
            {' — '}<Countdown seconds={nextEvent.wait_secs} />
          </div>
        )}
      </div>

      {/* Log */}
      <div>
        <div style={{ display: 'flex', alignItems: 'center', borderTop: '1px solid var(--border)' }}>
          <button
            style={{ ...btn('ghost'), flex: 1, justifyContent: 'space-between', borderRadius: 0, border: 'none', padding: '8px 20px' }}
            onClick={() => setShowLog(v => !v)}
          >
            <span style={{ fontSize: 12 }}>
              스케줄러 로그
              {logLines.length > 0 && (
                <span style={{ marginLeft: 8, color: 'var(--text3)', fontWeight: 400 }}>
                  ({logLines.length}줄)
                </span>
              )}
            </span>
            <ChevronDown size={13} style={{ transform: showLog ? 'rotate(180deg)' : undefined, transition: 'transform 0.2s' }} />
          </button>
          <button
            style={{ ...btn('ghost'), borderRadius: 0, border: 'none', borderLeft: '1px solid var(--border)', padding: '8px 14px', color: 'var(--text3)' }}
            onClick={() => clearLogMut.mutate()}
            disabled={clearLogMut.isPending || logLines.length === 0}
            title="로그 초기화"
          >
            <Eraser size={13} />
          </button>
        </div>
        {showLog && (
          <pre ref={logRef} style={{
            margin: 0, padding: '10px 20px', maxHeight: 480, overflowY: 'auto',
            fontSize: 11, fontFamily: 'var(--font-mono)', color: 'var(--text2)',
            background: 'var(--bg2)', whiteSpace: 'pre-wrap', wordBreak: 'break-all',
          }}>
            {logLines.length > 0 ? logLines.join('\n') : '(로그 없음)'}
          </pre>
        )}
      </div>
    </div>
  );
}

function fmtCountdown(seconds: number): string {
  if (seconds <= 0) return 'now';
  const h = Math.floor(seconds / 3600);
  const m = Math.floor((seconds % 3600) / 60);
  const s = Math.floor(seconds % 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 Countdown({ seconds }: { seconds: number }) {
  const [remaining, setRemaining] = useState(seconds);
  useEffect(() => {
    setRemaining(seconds);
    const iv = setInterval(() => setRemaining(r => Math.max(0, r - 1)), 1000);
    return () => clearInterval(iv);
  }, [seconds]);
  return <span style={{ fontFamily: 'var(--font-mono)', color: 'var(--cyan)' }}>{fmtCountdown(remaining)}</span>;
}

// ── Session Card ──────────────────────────────────────────────────────────────

function SessionCard({
  session,
  selected,
  onSelect,
  onDelete,
  onPause,
  onResume,
  onRunToday,
  runTodayPending,
}: {
  session: OrbSession;
  selected: boolean;
  onSelect: () => void;
  onDelete: () => void;
  onPause: () => void;
  onResume: () => void;
  onRunToday: () => void;
  runTodayPending: boolean;
}) {
  const totalReturn = session.total_return_pct ?? 0;
  const equity = session.current_equity ?? session.initial_equity;

  return (
    <div
      onClick={onSelect}
      style={{
        ...card,
        cursor: 'pointer',
        border: `1px solid ${selected ? 'var(--cyan)' : 'var(--border)'}`,
        background: selected ? 'color-mix(in srgb, var(--cyan) 5%, var(--bg1))' : 'var(--bg1)',
        transition: 'all 0.12s',
      }}
    >
      <div style={{ padding: '14px 16px' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 8 }}>
          <div>
            <div style={{ fontWeight: 600, fontSize: 14, color: 'var(--text1)', marginBottom: 2 }}>
              {session.session_name}
            </div>
            <div style={{ fontSize: 11, color: 'var(--text3)', fontFamily: 'var(--font-mono)' }}>
              {session.status === 'active' ? '● active' : session.status === 'paused' ? '⏸ paused' : session.status}
            </div>
          </div>
          <div style={{ textAlign: 'right' }}>
            <div style={{ fontSize: 18, fontWeight: 700, color: totalReturn >= 0 ? 'var(--green)' : 'var(--red)', fontFamily: 'var(--font-mono)' }}>
              {fmtPct(totalReturn)}
            </div>
            <div style={{ fontSize: 11, color: 'var(--text3)' }}>${fmt(equity)}</div>
          </div>
        </div>

        <div style={{ fontSize: 11, color: 'var(--text3)', marginBottom: 10, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
          {session.config_path.split('/').pop()}
        </div>

        {/* "지금 시작" — only when this session hasn't run today */}
        {session.ran_today === false && (
          <div style={{ marginBottom: 8 }}>
            <button
              style={{
                ...btn('outline'),
                width: '100%', justifyContent: 'center',
                borderColor: 'var(--cyan)', color: 'var(--cyan)',
                background: 'color-mix(in srgb, var(--cyan) 6%, transparent)',
                fontSize: 12,
              }}
              onClick={e => { e.stopPropagation(); onRunToday(); }}
              disabled={runTodayPending}
              title="오늘 ORB 감지를 지금 즉시 실행 (스케줄러 실행 중이어야 함)"
            >
              <PlayCircle size={13} />
              {runTodayPending ? '감지 중...' : '지금 시작 (현재 가격 기준)'}
            </button>
          </div>
        )}

        <div style={{ display: 'flex', gap: 6, justifyContent: 'flex-end' }} onClick={e => e.stopPropagation()}>
          {session.status === 'active' ? (
            <button style={btn('ghost')} onClick={onPause} title="일시 정지">
              <Pause size={12} />
            </button>
          ) : (
            <button style={btn('ghost')} onClick={onResume} title="재개">
              <RotateCcw size={12} />
            </button>
          )}
          <button style={btn('danger')} onClick={onDelete} title="세션 삭제">
            <Trash2 size={12} />
          </button>
        </div>
      </div>
    </div>
  );
}

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

function StrategyBadge({ label, value }: { label: string; value: string }) {
  return (
    <span style={{
      display: 'inline-block', padding: '2px 7px', borderRadius: 5, background: 'var(--bg2)',
      fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--text3)',
      border: '1px solid var(--border)', whiteSpace: 'nowrap',
    }}>
      {label}: <span style={{ color: 'var(--text2)' }}>{value}</span>
    </span>
  );
}

function CreateSessionModal({ onClose }: { onClose: () => void }) {
  const qc = useQueryClient();
  const [name, setName] = useState('');
  const [selectedSlug, setSelectedSlug] = useState('');
  const [capital, setCapital] = useState('10000');

  const { data: stratData, isLoading: straLoading } = useQuery({
    queryKey: ['orb-strategies'],
    queryFn: orbTradingApi.strategies,
  });

  const strategies: OrbStrategyInfo[] = stratData?.strategies ?? [];

  // Auto-select first strategy when list loads
  useEffect(() => {
    if (!selectedSlug && strategies.length > 0) {
      setSelectedSlug(strategies[0].slug);
    }
  }, [strategies, selectedSlug]);

  const selected = strategies.find(s => s.slug === selectedSlug) ?? null;

  const createMut = useMutation({
    mutationFn: () => {
      if (!selected) throw new Error('전략을 선택하세요');
      return orbTradingApi.createSession(name, selected.config_path, parseFloat(capital));
    },
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['orb-sessions'] });
      onClose();
    },
  });

  return (
    <div style={{
      position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.6)', zIndex: 50,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
    }} onClick={onClose}>
      <div style={{ ...card, width: 520, padding: 24, maxHeight: '90vh', overflowY: 'auto' }}
        onClick={e => e.stopPropagation()}>
        <h3 style={{ margin: '0 0 18px', fontSize: 16, color: 'var(--text1)' }}>ORB 세션 생성</h3>

        {/* Session name */}
        <div style={{ marginBottom: 14 }}>
          <label style={{ fontSize: 12, color: 'var(--text3)', display: 'block', marginBottom: 4 }}>세션 이름</label>
          <input style={inputStyle} value={name} onChange={e => setName(e.target.value)} placeholder="예: v55_live" />
        </div>

        {/* Strategy selector */}
        <div style={{ marginBottom: 6 }}>
          <label style={{ fontSize: 12, color: 'var(--text3)', display: 'block', marginBottom: 4 }}>전략 선택</label>
          {straLoading ? (
            <div style={{ fontSize: 12, color: 'var(--text3)', padding: '8px 0' }}>전략 목록 로딩 중...</div>
          ) : (
            <select
              style={inputStyle}
              value={selectedSlug}
              onChange={e => setSelectedSlug(e.target.value)}
            >
              <option value="">— 전략 선택 —</option>
              {strategies.map(s => (
                <option key={s.slug} value={s.slug}>
                  {s.name}{s.builtin ? '' : ' ✦'}
                </option>
              ))}
            </select>
          )}
        </div>

        {/* Strategy detail card */}
        {selected && (
          <div style={{
            background: 'var(--bg2)', border: '1px solid var(--border)', borderRadius: 8,
            padding: '10px 14px', marginBottom: 14, fontSize: 12,
          }}>
            {selected.description && (
              <div style={{ color: 'var(--text2)', marginBottom: 8, lineHeight: 1.5 }}>
                {selected.description}
              </div>
            )}
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 5 }}>
              {selected.orb_minutes != null && (
                <StrategyBadge label="ORB" value={`${selected.orb_minutes}분`} />
              )}
              {selected.sim_bar_minutes != null && (
                <StrategyBadge label="Bar" value={`${selected.sim_bar_minutes}분`} />
              )}
              {selected.entry_direction && (
                <StrategyBadge
                  label="방향"
                  value={selected.entry_direction === 'both' ? 'Long+Short' : selected.entry_direction === 'long_only' ? 'Long only' : selected.entry_direction}
                />
              )}
              {selected.risk_per_trade_pct != null && (
                <StrategyBadge label="리스크" value={`${(selected.risk_per_trade_pct * 100).toFixed(2)}%`} />
              )}
              {selected.atr_stop_multiplier != null && (
                <StrategyBadge label="ATR스톱" value={`×${selected.atr_stop_multiplier}`} />
              )}
            </div>
            <div style={{ marginTop: 7, fontSize: 10, color: 'var(--text3)', fontFamily: 'var(--font-mono)' }}>
              {selected.config_path}
            </div>
          </div>
        )}

        {/* Capital */}
        <div style={{ marginBottom: 20 }}>
          <label style={{ fontSize: 12, color: 'var(--text3)', display: 'block', marginBottom: 4 }}>
            초기 자본 (USD) — 복리 모드 강제 적용
          </label>
          <input style={inputStyle} type="number" value={capital} onChange={e => setCapital(e.target.value)} />
        </div>

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

        <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
          <button style={btn('ghost')} onClick={onClose}>취소</button>
          <button
            style={btn('primary')}
            onClick={() => createMut.mutate()}
            disabled={!name || !selected || createMut.isPending}
          >
            {createMut.isPending ? '생성 중...' : '세션 생성'}
          </button>
        </div>
      </div>
    </div>
  );
}

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

function PositionsPanel({ sessionId }: { sessionId: string }) {
  const { data, isLoading } = useQuery({
    queryKey: ['orb-positions', sessionId],
    queryFn: () => orbTradingApi.positions(sessionId),
    refetchInterval: 30000,
  });

  if (isLoading) return <Loading />;
  const positions = data?.positions ?? [];
  if (positions.length === 0) {
    return (
      <div style={{ padding: '24px', textAlign: 'center', color: 'var(--text3)', fontSize: 13 }}>
        오늘 오픈 포지션 없음 ({data?.date ?? '—'})
      </div>
    );
  }

  return (
    <div style={{ overflowX: 'auto' }}>
      <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12 }}>
        <thead>
          <tr style={{ background: 'var(--bg2)', borderBottom: '1px solid var(--border)' }}>
            {['티커', '방향', '진입가', '수량', '현재가', '변동%', '현재 스톱', 'R', '미실현 P&L', '트레일'].map(h => (
              <th key={h} style={{ padding: '8px 12px', textAlign: 'left', fontWeight: 500, color: 'var(--text3)', fontFamily: 'var(--font-mono)', whiteSpace: 'nowrap' }}>{h}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {positions.map(pos => (
            <tr key={pos.ticker} style={{ borderBottom: '1px solid var(--border)' }}>
              <td style={{ padding: '8px 12px', fontWeight: 600, color: 'var(--text1)' }}>{pos.ticker}</td>
              <td style={{ padding: '8px 12px' }}>
                <span style={{
                  display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 11, fontWeight: 600,
                  color: pos.direction === 'long' ? 'var(--green)' : 'var(--red)',
                }}>
                  {pos.direction === 'long' ? <TrendingUp size={11} /> : <TrendingDown size={11} />}
                  {pos.direction.toUpperCase()}
                </span>
              </td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)' }}>${fmt(pos.entry_price)}</td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)' }}>{pos.shares}</td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)' }}>${fmt(pos.current_price)}</td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', color: pos.change_pct == null ? 'var(--text3)' : pos.change_pct >= 0 ? 'var(--green)' : 'var(--red)' }}>
                {pos.change_pct == null ? '—' : `${pos.change_pct >= 0 ? '+' : ''}${pos.change_pct.toFixed(2)}%`}
              </td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>${fmt(pos.current_stop)}</td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', color: pos.r_multiple >= 0 ? 'var(--green)' : 'var(--red)' }}>
                {pos.r_multiple >= 0 ? '+' : ''}{fmt(pos.r_multiple)}R
              </td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', color: pos.unrealized_pnl >= 0 ? 'var(--green)' : 'var(--red)' }}>
                {fmtDollars(pos.unrealized_pnl)}
              </td>
              <td style={{ padding: '8px 12px', color: pos.trailing_active ? 'var(--cyan)' : 'var(--text3)' }}>
                {pos.trailing_active ? '● 활성' : '—'}
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

function CandidatesPanel({ sessionId }: { sessionId: string }) {
  const { data } = useQuery({
    queryKey: ['orb-candidates', sessionId],
    queryFn: () => orbTradingApi.candidates(sessionId),
    refetchInterval: 60000,
  });

  const candidates = data?.candidates ?? [];
  if (candidates.length === 0) {
    return (
      <div style={{ padding: '24px', textAlign: 'center', color: 'var(--text3)', fontSize: 13 }}>
        오늘 ORB 후보 없음
      </div>
    );
  }

  return (
    <div style={{ overflowX: 'auto' }}>
      <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12 }}>
        <thead>
          <tr style={{ background: 'var(--bg2)', borderBottom: '1px solid var(--border)' }}>
            {['티커', '방향', '돌파 레벨', 'ORB High', 'ORB Low', 'ATR', 'RVOL', 'Gap%', '점수', '상태'].map(h => (
              <th key={h} style={{ padding: '8px 12px', textAlign: 'left', fontWeight: 500, color: 'var(--text3)', fontFamily: 'var(--font-mono)', whiteSpace: 'nowrap' }}>{h}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {candidates.map((c: any) => (
            <tr key={c.ticker} style={{ borderBottom: '1px solid var(--border)' }}>
              <td style={{ padding: '8px 12px', fontWeight: 600, color: 'var(--text1)' }}>{c.ticker}</td>
              <td style={{ padding: '8px 12px' }}>
                <span style={{ fontSize: 11, fontWeight: 600, color: c.direction === 'bullish' ? 'var(--green)' : 'var(--red)' }}>
                  {c.direction === 'bullish' ? '▲ LONG' : '▼ SHORT'}
                </span>
              </td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', fontWeight: 600 }}>${fmt(c.breakout_level)}</td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>${fmt(c.orb_high)}</td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>${fmt(c.orb_low)}</td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>${fmt(c.atr, 3)}</td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)' }}>{fmt(c.rvol, 1)}x</td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', color: c.gap_pct >= 0 ? 'var(--green)' : 'var(--red)' }}>
                {fmtPct(c.gap_pct * 100)}
              </td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)' }}>{fmt(c.composite_score, 3)}</td>
              <td style={{ padding: '8px 12px' }}>
                <span style={{
                  fontSize: 11, fontWeight: 500,
                  color: c.status === 'filled' ? 'var(--green)' : c.status === 'timeout' ? 'var(--red)' : c.status === 'pending' ? 'var(--cyan)' : 'var(--text3)',
                }}>
                  {c.status}
                </span>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

function TradesPanel({ sessionId }: { sessionId: string }) {
  const { data } = useQuery({
    queryKey: ['orb-trades', sessionId],
    queryFn: () => orbTradingApi.trades(sessionId, 100),
    refetchInterval: 60000,
  });

  const trades = data?.trades ?? [];
  if (trades.length === 0) {
    return <div style={{ padding: '24px', textAlign: 'center', color: 'var(--text3)', fontSize: 13 }}>트레이드 이력 없음</div>;
  }

  return (
    <div style={{ overflowX: 'auto' }}>
      <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12 }}>
        <thead>
          <tr style={{ background: 'var(--bg2)', borderBottom: '1px solid var(--border)' }}>
            {['날짜', '티커', '방향', '진입가', '청산가', '수량', 'P&L', 'R', '사유'].map(h => (
              <th key={h} style={{ padding: '8px 12px', textAlign: 'left', fontWeight: 500, color: 'var(--text3)', fontFamily: 'var(--font-mono)', whiteSpace: 'nowrap' }}>{h}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {trades.map((t: any) => (
            <tr key={t.trade_id} style={{ borderBottom: '1px solid var(--border)' }}>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>{t.date}</td>
              <td style={{ padding: '8px 12px', fontWeight: 600, color: 'var(--text1)' }}>{t.ticker}</td>
              <td style={{ padding: '8px 12px' }}>
                <span style={{ fontSize: 11, fontWeight: 600, color: t.direction === 'long' ? 'var(--green)' : 'var(--red)' }}>
                  {t.direction.toUpperCase()}
                </span>
              </td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)' }}>${fmt(t.entry_price)}</td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)' }}>${fmt(t.exit_price)}</td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)' }}>{t.shares}</td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', fontWeight: 600, color: t.pnl >= 0 ? 'var(--green)' : 'var(--red)' }}>
                {fmtDollars(t.pnl)}
              </td>
              <td style={{ padding: '8px 12px', fontFamily: 'var(--font-mono)', color: t.r_multiple >= 0 ? 'var(--green)' : 'var(--red)' }}>
                {t.r_multiple >= 0 ? '+' : ''}{fmt(t.r_multiple)}R
              </td>
              <td style={{ padding: '8px 12px' }}>
                <span style={{
                  fontSize: 11,
                  color: t.exit_reason === 'close' ? 'var(--text3)' : t.exit_reason === 'stop_loss' ? 'var(--red)' : t.exit_reason === 'trailing_stop' ? 'var(--cyan)' : 'var(--orange)',
                }}>
                  {t.exit_reason}
                </span>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

function EquityPanel({ sessionId, initialEquity }: { sessionId: string; initialEquity: number }) {
  const { data } = useQuery({
    queryKey: ['orb-equity', sessionId],
    queryFn: () => orbTradingApi.equity(sessionId),
    refetchInterval: 60000,
  });

  const snapshots = data?.snapshots ?? [];
  if (snapshots.length === 0) {
    return <div style={{ padding: '24px', textAlign: 'center', color: 'var(--text3)', fontSize: 13 }}>에쿼티 데이터 없음</div>;
  }

  const chartData = [
    { date: '시작', equity: initialEquity },
    ...snapshots.map((s: any) => ({ date: s.date, equity: s.equity, pnl: s.daily_pnl })),
  ];

  const latest = snapshots[snapshots.length - 1];
  const totalReturn = ((latest.equity - initialEquity) / initialEquity) * 100;

  return (
    <div style={{ padding: '16px 20px' }}>
      <div style={{ display: 'flex', gap: 20, marginBottom: 16, flexWrap: 'wrap' }}>
        <div>
          <div style={{ fontSize: 11, color: 'var(--text3)', marginBottom: 2 }}>총 수익률</div>
          <div style={{ fontSize: 22, fontWeight: 700, fontFamily: 'var(--font-mono)', color: totalReturn >= 0 ? 'var(--green)' : 'var(--red)' }}>
            {fmtPct(totalReturn)}
          </div>
        </div>
        <div>
          <div style={{ fontSize: 11, color: 'var(--text3)', marginBottom: 2 }}>현재 자산</div>
          <div style={{ fontSize: 22, fontWeight: 700, fontFamily: 'var(--font-mono)', color: 'var(--text1)' }}>
            ${fmt(latest.equity)}
          </div>
        </div>
        <div>
          <div style={{ fontSize: 11, color: 'var(--text3)', marginBottom: 2 }}>최대 낙폭</div>
          <div style={{ fontSize: 18, fontWeight: 600, fontFamily: 'var(--font-mono)', color: 'var(--red)' }}>
            {fmt(Math.min(...snapshots.map((s: any) => s.drawdown_pct)))}%
          </div>
        </div>
        <div>
          <div style={{ fontSize: 11, color: 'var(--text3)', marginBottom: 2 }}>총 트레이드</div>
          <div style={{ fontSize: 18, fontWeight: 600, fontFamily: 'var(--font-mono)', color: 'var(--text1)' }}>
            {snapshots.reduce((a: number, s: any) => a + s.trades_taken, 0)}
          </div>
        </div>
      </div>

      <ResponsiveContainer width="100%" height={220}>
        <LineChart data={chartData}>
          <CartesianGrid strokeDasharray="3 3" stroke="var(--border)" />
          <XAxis dataKey="date" tick={{ fontSize: 10, fill: 'var(--text3)' }} interval="preserveStartEnd" />
          <YAxis tick={{ fontSize: 10, fill: 'var(--text3)' }} domain={['auto', 'auto']} tickFormatter={v => `$${v.toFixed(0)}`} />
          <Tooltip
            formatter={(v) => [`$${(v as number).toFixed(2)}`, '에쿼티']}
            contentStyle={{ background: 'var(--bg1)', border: '1px solid var(--border)', borderRadius: 8, fontSize: 12 }}
          />
          <ReferenceLine y={initialEquity} stroke="var(--text3)" strokeDasharray="4 2" />
          <Line dataKey="equity" stroke="var(--cyan)" strokeWidth={2} dot={false} />
        </LineChart>
      </ResponsiveContainer>
    </div>
  );
}

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

type TabKey = 'positions' | 'candidates' | 'trades' | 'equity';

export function OrbTradingPage() {
  const qc = useQueryClient();
  const [selectedId, setSelectedId] = useState<string | null>(null);
  const [showCreate, setShowCreate] = useState(false);
  const [activeTab, setActiveTab] = useState<TabKey>('positions');

  const { data, isLoading, error } = useQuery({
    queryKey: ['orb-sessions'],
    queryFn: orbTradingApi.sessions,
    refetchInterval: 60000,
  });

  const pauseMut = useMutation({
    mutationFn: orbTradingApi.pauseSession,
    onSuccess: () => qc.invalidateQueries({ queryKey: ['orb-sessions'] }),
  });
  const resumeMut = useMutation({
    mutationFn: orbTradingApi.resumeSession,
    onSuccess: () => qc.invalidateQueries({ queryKey: ['orb-sessions'] }),
  });
  const runTodayMut = useMutation({
    mutationFn: orbTradingApi.runToday,
    onSuccess: (result) => {
      qc.invalidateQueries({ queryKey: ['orb-sessions'] });
      qc.invalidateQueries({ queryKey: ['orb-auto-status'] });
      alert(`${result.session_name} 백그라운드 시작됨\n\n` +
            `ORB 감지 → 브레이크아웃 체크 순으로 실행됩니다 (약 1~2분 소요).\n` +
            `스케줄러 로그에서 진행상황을 확인하세요.`);
    },
    onError: (e: Error) => alert(`지금 시작 실패: ${e.message}`),
  });
  const deleteMut = useMutation({
    mutationFn: orbTradingApi.closeSession,
    onSuccess: (result, id) => {
      qc.invalidateQueries({ queryKey: ['orb-sessions'] });
      if (selectedId === id) setSelectedId(null);
      if (result.close_errors && result.close_errors.length > 0) {
        alert(
          `세션 삭제 완료 (포지션 ${result.positions_closed}개 청산)\n\n` +
          `청산 실패 (수동 처리 필요):\n${result.close_errors.join('\n')}`
        );
      }
    },
    onError: (e: Error) => alert(`세션 삭제 실패: ${e.message}`),
  });

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

  // Collect active session names for scheduler
  const activeSessions = sessions.filter(s => s.status === 'active').map(s => s.session_name);

  if (isLoading) return <div style={{ padding: 32 }}><Loading /></div>;
  if (error) return <div style={{ padding: 32 }}><ErrorState error={error} /></div>;

  const tabs: { key: TabKey; label: string }[] = [
    { key: 'positions', label: '포지션' },
    { key: 'candidates', label: 'ORB 후보' },
    { key: 'trades', label: '트레이드' },
    { key: 'equity', label: '에쿼티' },
  ];

  return (
    <div style={{ padding: '24px 28px', maxWidth: 1300, margin: '0 auto' }}>
      {/* Header */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 24 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <Zap size={20} color="var(--cyan)" />
          <h1 style={{ margin: 0, fontSize: 22, fontWeight: 700, color: 'var(--text1)' }}>
            ORB 인트라데이 트레이딩
          </h1>
        </div>
        <button style={btn('primary')} onClick={() => setShowCreate(true)}>
          <Plus size={14} /> 세션 생성
        </button>
      </div>

      {/* Auto Scheduler */}
      <SchedulerPanel selectedSessions={activeSessions} />

      {/* Sessions grid */}
      <div style={{ marginBottom: 24 }}>
        <div style={{ fontSize: 12, color: 'var(--text3)', fontFamily: 'var(--font-mono)', marginBottom: 10, textTransform: 'uppercase', letterSpacing: '0.08em' }}>
          세션 ({sessions.length})
        </div>
        {sessions.length === 0 ? (
          <div style={{ ...card, padding: '28px', textAlign: 'center', color: 'var(--text3)', fontSize: 13 }}>
            세션이 없습니다. 위의 "세션 생성" 버튼으로 시작하세요.
          </div>
        ) : (
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(260px, 1fr))', gap: 12 }}>
            {sessions.map(session => (
              <SessionCard
                key={session.session_id}
                session={session}
                selected={selectedId === session.session_id || selectedId === session.session_name}
                onSelect={() => setSelectedId(session.session_id)}
                onDelete={() => {
                  if (window.confirm(`"${session.session_name}" 세션을 삭제하시겠습니까? 오픈 포지션이 청산됩니다.`)) {
                    deleteMut.mutate(session.session_id);
                  }
                }}
                onPause={() => pauseMut.mutate(session.session_id)}
                onResume={() => resumeMut.mutate(session.session_id)}
                onRunToday={() => {
                  if (window.confirm(`"${session.session_name}" 세션을 현재 가격 기준으로 지금 시작하시겠습니까?\n(스케줄러가 실행 중이어야 합니다)`)) {
                    runTodayMut.mutate(session.session_id);
                  }
                }}
                runTodayPending={runTodayMut.isPending && runTodayMut.variables === session.session_id}
              />
            ))}
          </div>
        )}
      </div>

      {/* Session detail */}
      {selectedSession && (
        <div style={card}>
          <div style={{ padding: '12px 20px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', gap: 14 }}>
            <span style={{ fontWeight: 600, fontSize: 15, color: 'var(--text1)' }}>
              {selectedSession.session_name}
            </span>
            <span style={{ fontSize: 12, color: 'var(--text3)', fontFamily: 'var(--font-mono)' }}>
              ${fmt(selectedSession.initial_equity)} → ${fmt(selectedSession.current_equity ?? selectedSession.initial_equity)}
            </span>
          </div>

          {/* Tabs */}
          <div style={{ display: 'flex', gap: 0, borderBottom: '1px solid var(--border)', background: 'var(--bg2)' }}>
            {tabs.map(tab => (
              <button
                key={tab.key}
                onClick={() => setActiveTab(tab.key)}
                style={{
                  padding: '10px 18px', fontSize: 13, fontWeight: 500, cursor: 'pointer',
                  background: 'none', border: 'none', borderBottom: `2px solid ${activeTab === tab.key ? 'var(--cyan)' : 'transparent'}`,
                  color: activeTab === tab.key ? 'var(--cyan)' : 'var(--text3)',
                  transition: 'all 0.12s',
                }}
              >
                {tab.label}
              </button>
            ))}
          </div>

          {activeTab === 'positions' && <PositionsPanel sessionId={selectedSession.session_id} />}
          {activeTab === 'candidates' && <CandidatesPanel sessionId={selectedSession.session_id} />}
          {activeTab === 'trades' && <TradesPanel sessionId={selectedSession.session_id} />}
          {activeTab === 'equity' && (
            <EquityPanel sessionId={selectedSession.session_id} initialEquity={selectedSession.initial_equity} />
          )}
        </div>
      )}

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