import { useState, useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import {
  Area, AreaChart, CartesianGrid, ResponsiveContainer, Tooltip, XAxis, YAxis,
} from 'recharts';
import {
  ArrowLeft, CheckCircle, ChevronRight, ChevronDown, Clock, Copy, Edit2,
  Loader, Play, Plus, Trash2, XCircle, Ban,
} from 'lucide-react';
import { intradayApi } from '../api/client';
import type { IntradayStrategy, IntradayTask, IntradayResult, IntradayTrade } from '../api/client';

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

function fmt(v: number | null | undefined, digits = 2) {
  if (v == null) return '—';
  return v.toFixed(digits);
}

function fmtPct(v: number | null | undefined, digits = 1, alreadyPct = false) {
  if (v == null) return '—';
  const val = alreadyPct ? v : v * 100;
  const sign = val >= 0 ? '+' : '';
  return `${sign}${val.toFixed(digits)}%`;
}

function fmtMoney(v: number | null | undefined) {
  if (v == null) return '—';
  return `$${v.toLocaleString('en-US', { minimumFractionDigits: 0, maximumFractionDigits: 0 })}`;
}

function fmtTime(iso: string): string {
  try {
    return new Date(iso).toLocaleTimeString('en-US', {
      timeZone: 'America/New_York',
      hour: '2-digit',
      minute: '2-digit',
      hour12: false,
    });
  } catch { return iso; }
}

function elapsedStr(task: IntradayTask): string {
  const start = task.started_at || task.created_at;
  const end = task.finished_at || new Date().toISOString();
  const s = Math.floor((new Date(end).getTime() - new Date(start).getTime()) / 1000);
  if (s < 60) return `${s}s`;
  const m = Math.floor(s / 60);
  if (m < 60) return `${m}m ${s % 60}s`;
  return `${Math.floor(m / 60)}h ${m % 60}m`;
}

function taskPeriodLabel(task: IntradayTask): string {
  if (task.start_date) {
    const end = task.end_date ? ` → ${task.end_date}` : '';
    return `${task.start_date}${end}`;
  }
  return `last ${task.days}d`;
}

const RUN_UNIVERSE_OPTIONS = [
  { value: 'broad', label: 'Broad Snapshot (3408)' },
  { value: 'midlarge', label: 'Mid+Large Cap (971)' },
  { value: 'midcap', label: 'Mid Cap' },
  { value: 'largecap', label: 'Large Cap' },
  { value: 'smallmid', label: 'Small+Mid' },
  { value: 'sp500', label: 'S&P 500' },
  { value: 'nasdaq100', label: 'NASDAQ 100' },
];

const STRATEGY_UNIVERSE_OPTIONS = [
  { value: 'broad', label: 'Broad Snapshot (3408)' },
  { value: 'midlarge', label: 'Mid+Large Cap (971)' },
  { value: 'midcap', label: 'Mid Cap' },
  { value: 'largecap', label: 'Large Cap' },
  { value: 'smallmid', label: 'Small+Mid' },
  { value: 'sp500', label: 'S&P 500' },
  { value: 'nasdaq100', label: 'NASDAQ 100' },
];

function buildRunUniverseOptions(strategy: IntradayStrategy) {
  const options = [...RUN_UNIVERSE_OPTIONS];
  if (strategy.universe === 'yaml') {
    const yamlLabel = strategy.universe_symbols_file
      ? `Strategy YAML (${strategy.universe_symbols_file.split('/').slice(-1)[0]})`
      : 'Strategy YAML Universe';
    options.unshift({ value: 'yaml', label: yamlLabel });
  }
  return options;
}

const inputStyle: React.CSSProperties = {
  padding: '7px 10px', background: 'var(--bg2)', border: '1px solid var(--border)',
  borderRadius: 6, color: 'var(--text1)', fontSize: 13, width: '100%',
  outline: 'none', boxSizing: 'border-box',
};
const selectStyle: React.CSSProperties = { ...inputStyle, cursor: 'pointer' };

// ---------------------------------------------------------------------------
// Shared UI pieces
// ---------------------------------------------------------------------------

function StatusDot({ status }: { status: IntradayTask['status'] }) {
  const map: Record<IntradayTask['status'], { color: string; icon: React.ReactNode }> = {
    queued:    { color: 'var(--text3)', icon: <Clock size={13} /> },
    running:   { color: 'var(--cyan)',  icon: <Loader size={13} style={{ animation: 'spin 1s linear infinite' }} /> },
    completed: { color: 'var(--green)', icon: <CheckCircle size={13} /> },
    failed:    { color: 'var(--red)',   icon: <XCircle size={13} /> },
    cancelled: { color: 'var(--text3)', icon: <Ban size={13} /> },
  };
  const { color, icon } = map[status];
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, color, fontWeight: 500, fontSize: 13 }}>
      {icon} {status.charAt(0).toUpperCase() + status.slice(1)}
    </span>
  );
}

function MetricCard({ label, value, color }: { label: string; value: string; color?: string }) {
  return (
    <div style={{ background: 'var(--bg2)', border: '1px solid var(--border)', borderRadius: 8, padding: '14px 18px', minWidth: 110 }}>
      <div style={{ fontSize: 11, color: 'var(--text3)', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 6 }}>{label}</div>
      <div style={{ fontSize: 22, fontWeight: 700, fontFamily: 'var(--font-mono)', color: color || 'var(--text1)' }}>{value}</div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Trade Table
// ---------------------------------------------------------------------------

const EXIT_COLOR: Record<string, string> = {
  trailing_stop: 'var(--cyan)', time_exit: 'var(--text3)',
  stop_loss: 'var(--red)', breakeven: 'var(--text2)',
};

function TradeTable({ trades }: { trades: IntradayTrade[] }) {
  const [sortKey, setSortKey] = useState<keyof IntradayTrade>('date');
  const [sortDir, setSortDir] = useState<'asc' | 'desc'>('desc');
  const [page, setPage] = useState(0);
  const PAGE = 50;

  function toggleSort(k: keyof IntradayTrade) {
    if (sortKey === k) setSortDir(d => d === 'asc' ? 'desc' : 'asc');
    else { setSortKey(k); setSortDir('desc'); }
    setPage(0);
  }

  const sorted = [...trades].sort((a, b) => {
    const av = a[sortKey], bv = b[sortKey];
    if (av == null && bv == null) return 0;
    if (av == null) return 1; if (bv == null) return -1;
    const c = av < bv ? -1 : av > bv ? 1 : 0;
    return sortDir === 'asc' ? c : -c;
  });
  const totalPages = Math.ceil(sorted.length / PAGE);
  const paged = sorted.slice(page * PAGE, (page + 1) * PAGE);

  const th = (key: keyof IntradayTrade, label: string) => (
    <th key={key} onClick={() => toggleSort(key)}
      style={{ padding: '9px 10px', textAlign: 'left', fontSize: 11, color: 'var(--text3)', textTransform: 'uppercase', letterSpacing: '0.07em', fontWeight: 600, cursor: 'pointer', whiteSpace: 'nowrap', userSelect: 'none' }}>
      {label}{sortKey === key ? (sortDir === 'asc' ? ' ↑' : ' ↓') : ''}
    </th>
  );

  return (
    <div>
      {/* Pagination header */}
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 }}>
        <span style={{ fontSize: 13, color: 'var(--text3)' }}>{trades.length} trades</span>
        {totalPages > 1 && (
          <div style={{ display: 'flex', gap: 4, alignItems: 'center', fontSize: 12, color: 'var(--text3)' }}>
            {(['«', '‹'] as const).map((label, i) => {
              const isFirst = i === 0;
              const disabled = page === 0;
              return (
                <button key={label} onClick={() => setPage(isFirst ? 0 : p => Math.max(0, p - 1))} disabled={disabled}
                  style={{ padding: '3px 9px', borderRadius: 5, border: '1px solid var(--border)', background: 'var(--bg2)', cursor: disabled ? 'not-allowed' : 'pointer', color: disabled ? 'var(--text3)' : 'var(--text2)', opacity: disabled ? 0.4 : 1 }}>
                  {label}
                </button>
              );
            })}
            <span style={{ padding: '3px 8px' }}>{page + 1} / {totalPages}</span>
            {(['›', '»'] as const).map((label, i) => {
              const isLast = i === 1;
              const disabled = page === totalPages - 1;
              return (
                <button key={label} onClick={() => setPage(isLast ? totalPages - 1 : p => Math.min(totalPages - 1, p + 1))} disabled={disabled}
                  style={{ padding: '3px 9px', borderRadius: 5, border: '1px solid var(--border)', background: 'var(--bg2)', cursor: disabled ? 'not-allowed' : 'pointer', color: disabled ? 'var(--text3)' : 'var(--text2)', opacity: disabled ? 0.4 : 1 }}>
                  {label}
                </button>
              );
            })}
          </div>
        )}
      </div>
      <div style={{ overflowX: 'auto', borderRadius: 8, border: '1px solid var(--border)' }}>
        <table style={{ width: '100%', borderCollapse: 'collapse', minWidth: 820 }}>
          <thead>
            <tr style={{ background: 'var(--bg2)', borderBottom: '1px solid var(--border)' }}>
              {th('date', 'Date')}{th('ticker', 'Ticker')}{th('entry_price', 'Entry')}
              {th('exit_price', 'Exit')}{th('entry_time', 'In')}{th('exit_time', 'Out')}
              {th('shares', 'Shares')}{th('pnl', 'P&L ($)')}{th('pnl_pct', 'P&L %')}
              {th('r_multiple_at_exit', 'R-mult')}{th('rvol', 'RVOL')}{th('exit_reason', 'Exit')}
            </tr>
          </thead>
          <tbody>
            {paged.map((t, i) => {
              const pc = t.pnl >= 0 ? 'var(--green)' : 'var(--red)';
              return (
                <tr key={i} style={{ borderBottom: '1px solid var(--border)' }}
                  onMouseEnter={e => (e.currentTarget.style.background = 'var(--bg2)')}
                  onMouseLeave={e => (e.currentTarget.style.background = 'transparent')}>
                  <td style={{ padding: '8px 10px', fontSize: 12, color: 'var(--text3)', fontFamily: 'var(--font-mono)' }}>{t.date}</td>
                  <td style={{ padding: '8px 10px', fontSize: 13, fontWeight: 700, color: 'var(--cyan)', fontFamily: 'var(--font-mono)' }}>{t.ticker}</td>
                  <td style={{ padding: '8px 10px', fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>${t.entry_price.toFixed(2)}</td>
                  <td style={{ padding: '8px 10px', fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>${t.exit_price.toFixed(2)}</td>
                  <td style={{ padding: '8px 10px', fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>{fmtTime(t.entry_time)}</td>
                  <td style={{ padding: '8px 10px', fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text3)' }}>{fmtTime(t.exit_time)}</td>
                  <td style={{ padding: '8px 10px', fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>{Math.round(t.shares)}</td>
                  <td style={{ padding: '8px 10px', fontSize: 13, fontFamily: 'var(--font-mono)', fontWeight: 600, color: pc }}>
                    {t.pnl >= 0 ? '+' : ''}{t.pnl.toFixed(2)}
                  </td>
                  <td style={{ padding: '8px 10px', fontSize: 13, fontFamily: 'var(--font-mono)', fontWeight: 600, color: pc }}>
                    {fmtPct(t.pnl_pct, 2)}
                  </td>
                  <td style={{ padding: '8px 10px', fontSize: 12, fontFamily: 'var(--font-mono)', color: t.r_multiple_at_exit != null && t.r_multiple_at_exit >= 0 ? 'var(--green)' : 'var(--red)' }}>
                    {t.r_multiple_at_exit != null ? `${t.r_multiple_at_exit >= 0 ? '+' : ''}${t.r_multiple_at_exit.toFixed(2)}` : '—'}
                  </td>
                  <td style={{ padding: '8px 10px', fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>
                    {t.rvol != null ? t.rvol.toFixed(1) : '—'}
                  </td>
                  <td style={{ padding: '8px 10px', fontSize: 11 }}>
                    <span style={{ padding: '2px 7px', borderRadius: 4, background: 'var(--bg3)', color: EXIT_COLOR[t.exit_reason] || 'var(--text3)', fontFamily: 'var(--font-mono)' }}>
                      {t.exit_reason.replace(/_/g, ' ')}
                    </span>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Daily Breakdown Table
// ---------------------------------------------------------------------------

interface DailySummary {
  date: string;
  daily_pnl: number;
  daily_return_pct: number;
  candidates_found: number;
  trades: number;
  activity_count?: number;
  idle_sleeve_positions_opened?: number;
  idle_sleeve_symbols_opened?: string[];
  idle_sleeve_labels_opened?: string[];
}

function DailyBreakdownTable({ daily_summary, initial_capital }: { daily_summary: DailySummary[]; initial_capital: number }) {
  const [sortKey, setSortKey] = useState<'date' | 'pnl' | 'trades' | 'candidates'>('date');
  const [sortDir, setSortDir] = useState<'asc' | 'desc'>('desc');

  // Build cumulative equity
  let eq = initial_capital;
  const rows = daily_summary.map(d => {
    eq += d.daily_pnl;
    const opened = d.idle_sleeve_positions_opened ?? 0;
    return { ...d, activity_count: d.activity_count ?? d.trades + opened, equity: eq };
  });

  // Stats for highlights
  const activityDays = rows.filter(r => (r.activity_count ?? 0) > 0);
  const pnlDays = rows.filter(r => r.trades > 0);
  const bestDay = pnlDays.reduce<(typeof rows)[0] | null>((best, r) => (!best || r.daily_pnl > best.daily_pnl ? r : best), null);
  const worstDay = pnlDays.reduce<(typeof rows)[0] | null>((worst, r) => (!worst || r.daily_pnl < worst.daily_pnl ? r : worst), null);
  const winDays = pnlDays.filter(r => r.daily_pnl > 0).length;
  const totalPnl = rows.reduce((s, r) => s + r.daily_pnl, 0);

  function toggleSort(k: typeof sortKey) {
    if (sortKey === k) setSortDir(d => d === 'asc' ? 'desc' : 'asc');
    else { setSortKey(k); setSortDir('desc'); }
  }

  const sorted = [...rows].sort((a, b) => {
    let av: number, bv: number;
    if (sortKey === 'date') { av = a.date < b.date ? -1 : 1; return sortDir === 'asc' ? av : -av; }
    if (sortKey === 'pnl') { av = a.daily_pnl; bv = b.daily_pnl; }
    else if (sortKey === 'trades') { av = a.activity_count ?? a.trades; bv = b.activity_count ?? b.trades; }
    else { av = a.candidates_found; bv = b.candidates_found; }
    return sortDir === 'asc' ? av! - bv! : bv! - av!;
  });

  const th = (key: typeof sortKey, label: string, align: 'left' | 'right' = 'right') => (
    <th key={key} onClick={() => toggleSort(key)} style={{
      padding: '9px 12px', textAlign: align, fontSize: 11, color: 'var(--text3)',
      textTransform: 'uppercase', letterSpacing: '0.07em', fontWeight: 600,
      cursor: 'pointer', whiteSpace: 'nowrap', userSelect: 'none',
    }}>
      {label}{sortKey === key ? (sortDir === 'asc' ? ' ↑' : ' ↓') : ''}
    </th>
  );

  return (
    <div>
      {/* Summary stats strip */}
      <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginBottom: 16 }}>
        {[
          { label: 'Total P&L', value: `${totalPnl >= 0 ? '+' : ''}$${totalPnl.toFixed(2)}`, color: totalPnl >= 0 ? 'var(--green)' : 'var(--red)' },
          { label: 'Win Days', value: `${winDays} / ${pnlDays.length}`, color: 'var(--text1)' },
          { label: 'Activity Days', value: `${activityDays.length} / ${rows.length}`, color: 'var(--text1)' },
          { label: 'Best Day', value: bestDay ? `${bestDay.date}  +$${bestDay.daily_pnl.toFixed(2)}` : '—', color: 'var(--green)' },
          { label: 'Worst Day', value: worstDay && worstDay.daily_pnl < 0 ? `${worstDay.date}  -$${Math.abs(worstDay.daily_pnl).toFixed(2)}` : '—', color: 'var(--red)' },
        ].map(s => (
          <div key={s.label} style={{ background: 'var(--bg2)', border: '1px solid var(--border)', borderRadius: 8, padding: '10px 14px', minWidth: 140 }}>
            <div style={{ fontSize: 11, color: 'var(--text3)', textTransform: 'uppercase', letterSpacing: '0.07em', marginBottom: 4 }}>{s.label}</div>
            <div style={{ fontSize: 13, fontWeight: 700, fontFamily: 'var(--font-mono)', color: s.color }}>{s.value}</div>
          </div>
        ))}
      </div>

      <div style={{ overflowX: 'auto', borderRadius: 8, border: '1px solid var(--border)' }}>
        <table style={{ width: '100%', borderCollapse: 'collapse', minWidth: 560 }}>
          <thead>
            <tr style={{ background: 'var(--bg2)', borderBottom: '1px solid var(--border)' }}>
              {th('date', 'Date', 'left')}
              {th('trades', 'Activity')}
              {th('candidates', 'Candidates')}
              {th('pnl', 'Day P&L ($)')}
              <th style={{ padding: '9px 12px', textAlign: 'right', fontSize: 11, color: 'var(--text3)', textTransform: 'uppercase', letterSpacing: '0.07em', fontWeight: 600, whiteSpace: 'nowrap' }}>Day Ret%</th>
              <th style={{ padding: '9px 12px', textAlign: 'right', fontSize: 11, color: 'var(--text3)', textTransform: 'uppercase', letterSpacing: '0.07em', fontWeight: 600, whiteSpace: 'nowrap' }}>Equity</th>
            </tr>
          </thead>
          <tbody>
            {sorted.map(r => {
              const isBest = bestDay?.date === r.date && r.daily_pnl > 0;
              const isWorst = worstDay?.date === r.date && r.daily_pnl < 0;
              const opened = r.idle_sleeve_positions_opened ?? 0;
              const activityCount = r.activity_count ?? r.trades + opened;
              const noTrade = activityCount === 0;
              const openedSymbols = (r.idle_sleeve_symbols_opened ?? []).join(', ');
              const pendingOpen = Math.max(0, activityCount - r.trades);
              const pnlColor = r.daily_pnl > 0 ? 'var(--green)' : r.daily_pnl < 0 ? 'var(--red)' : 'var(--text3)';
              const rowBg = isBest ? 'rgba(34,197,94,0.07)' : isWorst ? 'rgba(239,68,68,0.07)' : 'transparent';
              return (
                <tr key={r.date} style={{ borderBottom: '1px solid var(--border)', background: rowBg, opacity: noTrade ? 0.45 : 1 }}
                  onMouseEnter={e => !isBest && !isWorst && (e.currentTarget.style.background = 'var(--bg2)')}
                  onMouseLeave={e => (e.currentTarget.style.background = rowBg)}>
                  <td style={{ padding: '7px 12px', fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>
                    <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                      {r.date}
                      {isBest && <span style={{ fontSize: 10, padding: '1px 5px', borderRadius: 4, background: 'rgba(34,197,94,0.15)', color: 'var(--green)', fontWeight: 700 }}>BEST</span>}
                      {isWorst && <span style={{ fontSize: 10, padding: '1px 5px', borderRadius: 4, background: 'rgba(239,68,68,0.15)', color: 'var(--red)', fontWeight: 700 }}>WORST</span>}
                      {opened > 0 && <span title={openedSymbols ? `Idle sleeve entries: ${openedSymbols}` : 'Idle sleeve entries'} style={{ fontSize: 10, padding: '1px 5px', borderRadius: 4, background: 'rgba(37,99,235,0.13)', color: '#2563eb', fontWeight: 700 }}>IDLE {opened}</span>}
                    </span>
                  </td>
                  <td title={`${r.trades} closed, ${pendingOpen} pending opens`} style={{ padding: '7px 12px', fontSize: 12, fontFamily: 'var(--font-mono)', textAlign: 'right', color: activityCount > 0 ? 'var(--text1)' : 'var(--text3)' }}>
                    {activityCount}
                  </td>
                  <td style={{ padding: '7px 12px', fontSize: 12, fontFamily: 'var(--font-mono)', textAlign: 'right', color: 'var(--text3)' }}>{r.candidates_found}</td>
                  <td style={{ padding: '7px 12px', fontSize: 13, fontFamily: 'var(--font-mono)', fontWeight: 600, textAlign: 'right', color: noTrade ? 'var(--text3)' : pnlColor }}>
                    {noTrade ? '—' : `${r.daily_pnl >= 0 ? '+' : ''}$${r.daily_pnl.toFixed(2)}`}
                  </td>
                  <td style={{ padding: '7px 12px', fontSize: 12, fontFamily: 'var(--font-mono)', textAlign: 'right', color: noTrade ? 'var(--text3)' : pnlColor }}>
                    {noTrade ? '—' : `${r.daily_return_pct >= 0 ? '+' : ''}${(r.daily_return_pct * 100).toFixed(2)}%`}
                  </td>
                  <td style={{ padding: '7px 12px', fontSize: 12, fontFamily: 'var(--font-mono)', textAlign: 'right', color: 'var(--text2)' }}>
                    ${r.equity.toLocaleString('en-US', { minimumFractionDigits: 0, maximumFractionDigits: 0 })}
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Grouped Trade Table (trades bucketed by day, collapsible)
// ---------------------------------------------------------------------------

function GroupedTradeTable({ trades }: { trades: IntradayTrade[] }) {
  // Build day buckets preserving date order
  const dayMap = new Map<string, { trades: IntradayTrade[]; dayPnl: number }>();
  for (const t of [...trades].sort((a, b) => a.date < b.date ? -1 : 1)) {
    let bucket = dayMap.get(t.date);
    if (!bucket) { bucket = { trades: [], dayPnl: 0 }; dayMap.set(t.date, bucket); }
    bucket.trades.push(t);
    bucket.dayPnl += t.pnl;
  }
  const days = Array.from(dayMap.entries()).sort((a, b) => a[0] < b[0] ? 1 : -1); // newest first

  const [collapsed, setCollapsed] = useState<Set<string>>(new Set());
  const allCollapsed = collapsed.size === days.length;

  function toggleDay(date: string) {
    setCollapsed(s => { const n = new Set(s); n.has(date) ? n.delete(date) : n.add(date); return n; });
  }
  function toggleAll() {
    setCollapsed(allCollapsed ? new Set() : new Set(days.map(d => d[0])));
  }

  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 }}>
        <span style={{ fontSize: 13, color: 'var(--text3)' }}>{trades.length} trades · {days.length} days</span>
        <button onClick={toggleAll} style={{ padding: '4px 10px', fontSize: 11, borderRadius: 5, border: '1px solid var(--border)', background: 'var(--bg2)', color: 'var(--text2)', cursor: 'pointer' }}>
          {allCollapsed ? 'Expand All' : 'Collapse All'}
        </button>
      </div>
      <div style={{ borderRadius: 8, border: '1px solid var(--border)', overflow: 'hidden' }}>
        {days.map(([date, bucket], dayIdx) => {
          const isOpen = !collapsed.has(date);
          const pnlColor = bucket.dayPnl > 0 ? 'var(--green)' : bucket.dayPnl < 0 ? 'var(--red)' : 'var(--text3)';
          const dayGain = bucket.trades.filter(t => t.pnl > 0).reduce((s, t) => s + t.pnl, 0);
          const dayLoss = bucket.trades.filter(t => t.pnl < 0).reduce((s, t) => s + t.pnl, 0);
          return (
            <div key={date} style={{ borderBottom: dayIdx < days.length - 1 ? '1px solid var(--border)' : 'none' }}>
              {/* Day header row */}
              <div onClick={() => toggleDay(date)} style={{
                display: 'flex', alignItems: 'center', gap: 12, padding: '9px 14px',
                background: 'var(--bg2)', cursor: 'pointer', userSelect: 'none',
              }}
                onMouseEnter={e => (e.currentTarget.style.background = 'var(--bg3)')}
                onMouseLeave={e => (e.currentTarget.style.background = 'var(--bg2)')}>
                <ChevronDown size={13} style={{ color: 'var(--text3)', transform: isOpen ? 'rotate(0deg)' : 'rotate(-90deg)', transition: 'transform 0.15s', flexShrink: 0 }} />
                <span style={{ fontFamily: 'var(--font-mono)', fontSize: 13, fontWeight: 600, color: 'var(--text2)', minWidth: 100 }}>{date}</span>
                <span style={{ fontSize: 12, color: 'var(--text3)' }}>{bucket.trades.length} trade{bucket.trades.length !== 1 ? 's' : ''}</span>
                <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 6 }}>
                  {dayGain > 0 && (
                    <span style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--green)', background: 'rgba(34,197,94,0.08)', padding: '2px 7px', borderRadius: 5 }}>
                      +${dayGain.toFixed(2)}
                    </span>
                  )}
                  {dayLoss < 0 && (
                    <span style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--red)', background: 'rgba(239,68,68,0.08)', padding: '2px 7px', borderRadius: 5 }}>
                      -${Math.abs(dayLoss).toFixed(2)}
                    </span>
                  )}
                  <span style={{ fontFamily: 'var(--font-mono)', fontSize: 13, fontWeight: 700, color: pnlColor, minWidth: 70, textAlign: 'right' }}>
                    {bucket.dayPnl >= 0 ? '+' : ''}${bucket.dayPnl.toFixed(2)}
                  </span>
                </div>
              </div>
              {/* Trade rows */}
              {isOpen && (
                <table style={{ width: '100%', borderCollapse: 'collapse', minWidth: 680 }}>
                  <thead>
                    <tr style={{ borderBottom: '1px solid var(--border)' }}>
                      {[
                        { key: 'ticker', label: 'Ticker' },
                        { key: 'entry_price', label: 'Entry' },
                        { key: 'exit_price', label: 'Exit' },
                        { key: 'entry_time', label: 'In' },
                        { key: 'exit_time', label: 'Out' },
                        { key: 'shares', label: 'Shares' },
                        { key: 'pnl', label: 'P&L ($)' },
                        { key: 'pnl_pct', label: 'P&L %' },
                        { key: 'r_mult', label: 'R-mult' },
                        { key: 'rvol', label: 'RVOL' },
                        { key: 'exit_reason', label: 'Exit' },
                      ].map(h => (
                        <th key={h.key} style={{ padding: '6px 10px', textAlign: h.key === 'ticker' ? 'left' : 'right', fontSize: 11, color: 'var(--text3)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600, whiteSpace: 'nowrap', background: 'var(--bg1)' }}>{h.label}</th>
                      ))}
                    </tr>
                  </thead>
                  <tbody>
                    {bucket.trades.map((t, i) => {
                      const pc = t.pnl >= 0 ? 'var(--green)' : 'var(--red)';
                      return (
                        <tr key={i} style={{ borderBottom: i < bucket.trades.length - 1 ? '1px solid var(--border)' : 'none' }}
                          onMouseEnter={e => (e.currentTarget.style.background = 'var(--bg2)')}
                          onMouseLeave={e => (e.currentTarget.style.background = 'transparent')}>
                          <td style={{ padding: '7px 10px', fontSize: 13, fontWeight: 700, color: 'var(--cyan)', fontFamily: 'var(--font-mono)' }}>{t.ticker}</td>
                          <td style={{ padding: '7px 10px', fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text2)', textAlign: 'right' }}>${t.entry_price.toFixed(2)}</td>
                          <td style={{ padding: '7px 10px', fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text2)', textAlign: 'right' }}>${t.exit_price.toFixed(2)}</td>
                          <td style={{ padding: '7px 10px', fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text3)', textAlign: 'right' }}>{fmtTime(t.entry_time)}</td>
                          <td style={{ padding: '7px 10px', fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text3)', textAlign: 'right' }}>{fmtTime(t.exit_time)}</td>
                          <td style={{ padding: '7px 10px', fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text2)', textAlign: 'right' }}>{Math.round(t.shares)}</td>
                          <td style={{ padding: '7px 10px', fontSize: 13, fontFamily: 'var(--font-mono)', fontWeight: 600, color: pc, textAlign: 'right' }}>{t.pnl >= 0 ? '+' : ''}{t.pnl.toFixed(2)}</td>
                          <td style={{ padding: '7px 10px', fontSize: 13, fontFamily: 'var(--font-mono)', fontWeight: 600, color: pc, textAlign: 'right' }}>{fmtPct(t.pnl_pct, 2)}</td>
                          <td style={{ padding: '7px 10px', fontSize: 12, fontFamily: 'var(--font-mono)', textAlign: 'right', color: t.r_multiple_at_exit != null && t.r_multiple_at_exit >= 0 ? 'var(--green)' : 'var(--red)' }}>
                            {t.r_multiple_at_exit != null ? `${t.r_multiple_at_exit >= 0 ? '+' : ''}${t.r_multiple_at_exit.toFixed(2)}` : '—'}
                          </td>
                          <td style={{ padding: '7px 10px', fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text2)', textAlign: 'right' }}>{t.rvol != null ? t.rvol.toFixed(1) : '—'}</td>
                          <td style={{ padding: '7px 10px', fontSize: 11, textAlign: 'right' }}>
                            <span style={{ padding: '2px 6px', borderRadius: 4, background: 'var(--bg3)', color: EXIT_COLOR[t.exit_reason] || 'var(--text3)', fontFamily: 'var(--font-mono)' }}>
                              {t.exit_reason.replace(/_/g, ' ')}
                            </span>
                          </td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Intraday Task Detail Page  /intraday/tasks/:taskId
// ---------------------------------------------------------------------------

export function IntradayTaskDetailPage() {
  const { taskId } = useParams<{ taskId: string }>();
  const navigate = useNavigate();
  const qc = useQueryClient();
  const [activeTab, setActiveTab] = useState<'metrics' | 'daily' | 'trades' | 'log'>('metrics');
  const [tabAutoSet, setTabAutoSet] = useState(false);
  const [tradesView, setTradesView] = useState<'grouped' | 'flat'>('grouped');

  const { data: task, isLoading } = useQuery({
    queryKey: ['intraday-task', taskId],
    queryFn: () => intradayApi.task(taskId!),
    enabled: !!taskId,
    staleTime: 0,
    refetchInterval: q => {
      const s = q.state.data?.status;
      return s === 'running' || s === 'queued' ? 2000 : false;
    },
  });

  useEffect(() => {
    if (!tabAutoSet && task?.status === 'failed') {
      setActiveTab('log');
      setTabAutoSet(true);
    }
  }, [task?.status, tabAutoSet]);

  const { data: logData } = useQuery({
    queryKey: ['intraday-task-log', taskId],
    queryFn: () => intradayApi.taskLog(taskId!),
    enabled: !!taskId,
    staleTime: 0,
    refetchInterval: () => (task?.status === 'running' || task?.status === 'queued' ? 3000 : false),
  });

  const { data: result } = useQuery<IntradayResult>({
    queryKey: ['intraday-task-result', taskId],
    queryFn: () => intradayApi.taskResult(taskId!),
    enabled: task?.status === 'completed',
    staleTime: 60_000,
  });

  const cancelMutation = useMutation({
    mutationFn: () => intradayApi.cancel(taskId!),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['intraday-task', taskId] }),
  });

  // Resolve strategy name from cached strategy list
  const { data: strategiesData } = useQuery({
    queryKey: ['intraday-strategies'],
    queryFn: intradayApi.strategies,
    staleTime: 60_000,
  });
  const strategyName = task
    ? (strategiesData?.strategies.find(s => s.slug === task.config)?.name ?? task.config)
    : '';

  if (isLoading || !task) {
    return (
      <div style={{ padding: '40px', display: 'flex', alignItems: 'center', gap: 10, color: 'var(--text3)' }}>
        <Loader size={16} style={{ animation: 'spin 1s linear infinite' }} /> Loading…
      </div>
    );
  }

  const isActive = task.status === 'running' || task.status === 'queued';
  const r = task.result_summary;

  const equityData = result ? (() => {
    let eq = result.metrics.initial_capital;
    return result.daily_summary.map(d => { eq += d.daily_pnl; return { date: d.date, equity: Math.round(eq) }; });
  })() : [];

  const tabBtn = (tab: typeof activeTab, label: string) => (
    <button key={tab} onClick={() => setActiveTab(tab)} style={{
      padding: '7px 16px', fontSize: 13, fontWeight: 500,
      background: activeTab === tab ? 'var(--bg3)' : 'none',
      color: activeTab === tab ? 'var(--text1)' : 'var(--text3)',
      border: 'none', cursor: 'pointer', borderRadius: 6,
    }}>
      {label}
    </button>
  );

  return (
    <div style={{ padding: '32px 40px', maxWidth: 1100, margin: '0 auto' }}>
      <style>{`@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }`}</style>

      {/* Breadcrumb */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 22, fontFamily: 'var(--font-mono)', fontSize: 13, color: 'var(--text3)' }}>
        <button onClick={() => navigate('/intraday')}
          style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--text3)', fontFamily: 'var(--font-mono)', fontSize: 13, padding: 0, display: 'flex', alignItems: 'center', gap: 4 }}
          onMouseEnter={e => (e.currentTarget.style.color = 'var(--text1)')}
          onMouseLeave={e => (e.currentTarget.style.color = 'var(--text3)')}>
          <ArrowLeft size={12} /> intraday
        </button>
        <ChevronRight size={13} />
        <span style={{ color: 'var(--text2)' }}>{taskId}</span>
      </div>

      {/* Header */}
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 24 }}>
        <div>
          <h1 style={{ fontSize: 22, fontWeight: 700, color: 'var(--text1)', margin: '0 0 6px' }}>{strategyName}</h1>
          <div style={{ fontSize: 13, color: 'var(--text3)', fontFamily: 'var(--font-mono)' }}>
            {taskPeriodLabel(task)} · {task.universe_label ?? task.universe}
          </div>
        </div>
        {isActive && (
          <button onClick={() => cancelMutation.mutate()}
            style={{ padding: '8px 16px', borderRadius: 7, background: 'none', border: '1px solid var(--red)', color: 'var(--red)', cursor: 'pointer', fontSize: 13, fontWeight: 500 }}>
            Cancel
          </button>
        )}
      </div>

      {/* Status bar */}
      <div style={{ display: 'flex', gap: 24, alignItems: 'center', padding: '10px 16px', background: 'var(--bg2)', borderRadius: 8, border: '1px solid var(--border)', marginBottom: 24 }}>
        <StatusDot status={task.status} />
        {task.started_at && <span style={{ fontSize: 13, color: 'var(--text3)' }}>Elapsed: {elapsedStr(task)}</span>}
        {task.finished_at && task.status === 'completed' && (
          <span style={{ fontSize: 13, color: 'var(--text3)' }}>
            Finished: {new Date(task.finished_at).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })}
          </span>
        )}
        {task.error && <span style={{ fontSize: 12, color: 'var(--red)', fontFamily: 'var(--font-mono)' }}>failed — see Log tab</span>}
      </div>

      {/* Summary metric cards */}
      {r && (
        <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginBottom: 24 }}>
          <MetricCard label="Return" value={r.return_pct != null ? fmtPct(r.return_pct) : '—'} color={r.return_pct != null ? (r.return_pct >= 0 ? 'var(--green)' : 'var(--red)') : undefined} />
          <MetricCard label="Equity" value={fmtMoney(r.final_equity)} />
          <MetricCard label="Max DD" value={r.max_dd_pct != null ? fmtPct(r.max_dd_pct) : '—'} color={r.max_dd_pct != null && r.max_dd_pct < 0 ? 'var(--red)' : 'var(--text1)'} />
          <MetricCard label="Loss Score" value={r.loss_containment_score != null ? fmt(r.loss_containment_score) : '—'} color={r.loss_containment_score != null && r.loss_containment_score >= 70 ? 'var(--green)' : undefined} />
          <MetricCard label="Sharpe" value={fmt(r.sharpe)} color={r.sharpe != null && r.sharpe >= 1 ? 'var(--green)' : undefined} />
          <MetricCard label="Win Rate" value={r.win_rate != null ? `${r.win_rate.toFixed(1)}%` : '—'} />
          <MetricCard label="Trades" value={r.trade_count != null ? String(r.trade_count) : '—'} />
          {r.calmar != null && <MetricCard label="Calmar" value={fmt(r.calmar)} />}
        </div>
      )}

      {/* Tabs (completed: all tabs; failed: log only) */}
      {(task.status === 'completed' || task.status === 'failed') && (
        <div style={{ display: 'flex', gap: 4, marginBottom: 20, background: 'var(--bg2)', borderRadius: 8, padding: 4, width: 'fit-content' }}>
          {task.status === 'completed' && tabBtn('metrics', 'Metrics & Chart')}
          {task.status === 'completed' && tabBtn('daily', `Daily${result ? ` (${result.daily_summary.length})` : ''}`)}
          {task.status === 'completed' && tabBtn('trades', `Trades${result ? ` (${result.trades.length})` : ''}`)}
          {tabBtn('log', 'Log')}
        </div>
      )}

      {/* ── Tab: Metrics & Chart ── */}
      {(activeTab === 'metrics' || (task.status !== 'completed' && task.status !== 'failed')) && (
        <>
          {result && (
            <div style={{ marginBottom: 28 }}>
              <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--text3)', marginBottom: 12, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                Full Metrics
              </div>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(170px, 1fr))', gap: 8 }}>
                {([
                  ['Period', `${result.metrics.start_date} → ${result.metrics.end_date}`],
                  ['Trading Days', String(result.metrics.trading_days)],
                  ['Activity Days', result.metrics.days_with_activity != null ? String(result.metrics.days_with_activity) : '—'],
                  ['Total Return', fmtPct(result.metrics.total_return_pct)],
                  ['Ann. Return', fmtPct(result.metrics.annualized_return_pct)],
                  ['Max Drawdown', fmtPct(result.metrics.max_drawdown_pct)],
                  ['Sharpe', fmt(result.metrics.sharpe_ratio)],
                  ['Calmar', fmt(result.metrics.calmar_ratio)],
                  ['Win Rate', result.metrics.win_rate != null ? `${(result.metrics.win_rate * 100).toFixed(1)}%` : '—'],
                  ['Avg Win', fmtPct(result.metrics.avg_win_pct)],
                  ['Avg Loss', fmtPct(result.metrics.avg_loss_pct)],
                  ['Avg Losing Day', fmtPct(result.metrics.avg_loss_day_pct)],
                  ['Tail Loss (20%)', fmtPct(result.metrics.tail_loss_20_pct)],
                  ['Worst Day', fmtPct(result.metrics.worst_day_return_pct)],
                  ['Loss Score', fmt(result.metrics.loss_containment_score)],
                  ['Profit Factor', fmt(result.metrics.profit_factor)],
                  ['Total Trades', String(result.metrics.total_trades)],
                  ['Idle Entries', result.metrics.idle_sleeve_positions_opened != null ? `${result.metrics.idle_sleeve_positions_opened} / ${result.metrics.idle_sleeve_entry_days ?? 0}d` : '—'],
                  ['Initial Capital', fmtMoney(result.metrics.initial_capital)],
                  ['Final Equity', fmtMoney(result.metrics.final_equity)],
                ] as [string, string][]).map(([label, value]) => (
                  <div key={label} style={{ background: 'var(--bg2)', border: '1px solid var(--border)', borderRadius: 6, padding: '8px 12px' }}>
                    <div style={{ fontSize: 11, color: 'var(--text3)', marginBottom: 3 }}>{label}</div>
                    <div style={{ fontSize: 14, fontWeight: 600, fontFamily: 'var(--font-mono)', color: 'var(--text1)' }}>{value}</div>
                  </div>
                ))}
              </div>
            </div>
          )}

          {equityData.length > 0 && (
            <div style={{ marginBottom: 28 }}>
              <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--text3)', marginBottom: 12, textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                Equity Curve
              </div>
              <div style={{ height: 280, minWidth: 0, background: 'var(--bg2)', border: '1px solid var(--border)', borderRadius: 8, padding: '14px 6px 6px' }}>
                <ResponsiveContainer width="100%" height={260}>
                  <AreaChart data={equityData} margin={{ top: 4, right: 20, bottom: 0, left: 10 }}>
                    <defs>
                      <linearGradient id="orbEqGrad" x1="0" y1="0" x2="0" y2="1">
                        <stop offset="0%" stopColor="var(--cyan)" stopOpacity={0.3} />
                        <stop offset="100%" stopColor="var(--cyan)" stopOpacity={0.02} />
                      </linearGradient>
                    </defs>
                    <CartesianGrid strokeDasharray="3 3" stroke="var(--border)" vertical={false} />
                    <XAxis dataKey="date" tick={{ fontSize: 11, fill: 'var(--text3)' }} tickLine={false} axisLine={false} interval={Math.floor(equityData.length / 7)} />
                    <YAxis tick={{ fontSize: 11, fill: 'var(--text3)' }} tickLine={false} axisLine={false} width={64}
                      tickFormatter={v => v >= 1_000_000 ? `$${(v/1_000_000).toFixed(1)}M` : v >= 1_000 ? `$${(v/1_000).toFixed(0)}k` : `$${v}`} />
                    <Tooltip contentStyle={{ background: 'var(--bg1)', border: '1px solid var(--border)', borderRadius: 8, fontSize: 12 }}
                      formatter={(v: unknown) => [fmtMoney(v as number), 'Equity']} labelStyle={{ color: 'var(--text2)' }} />
                    <Area type="monotone" dataKey="equity" stroke="var(--cyan)" strokeWidth={2} fill="url(#orbEqGrad)" dot={false} />
                  </AreaChart>
                </ResponsiveContainer>
              </div>
            </div>
          )}

          {/* Live log while running */}
          {isActive && logData?.log && (
            <div>
              <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--text3)', marginBottom: 8, textTransform: 'uppercase', letterSpacing: '0.06em' }}>Log</div>
              <pre style={{ background: 'var(--bg0, #0d1117)', border: '1px solid var(--border)', borderRadius: 8, padding: '12px 14px', fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text2)', maxHeight: 360, overflowY: 'auto', whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}>
                {logData.log}
              </pre>
            </div>
          )}
        </>
      )}

      {/* ── Tab: Daily ── */}
      {activeTab === 'daily' && result && (
        result.daily_summary.length > 0
          ? <DailyBreakdownTable daily_summary={result.daily_summary} initial_capital={result.metrics.initial_capital} />
          : <div style={{ padding: '40px 0', textAlign: 'center', color: 'var(--text3)', fontSize: 14 }}>No daily data.</div>
      )}

      {/* ── Tab: Trades ── */}
      {activeTab === 'trades' && result && (
        result.trades.length > 0 ? (
          <div>
            {/* View toggle */}
            <div style={{ display: 'flex', gap: 4, marginBottom: 14, background: 'var(--bg2)', borderRadius: 7, padding: 3, width: 'fit-content' }}>
              {(['grouped', 'flat'] as const).map(v => (
                <button key={v} onClick={() => setTradesView(v)} style={{
                  padding: '5px 13px', fontSize: 12, fontWeight: 500,
                  background: tradesView === v ? 'var(--bg3)' : 'none',
                  color: tradesView === v ? 'var(--text1)' : 'var(--text3)',
                  border: 'none', cursor: 'pointer', borderRadius: 5,
                }}>
                  {v === 'grouped' ? 'By Day' : 'All'}
                </button>
              ))}
            </div>
            {tradesView === 'grouped'
              ? <GroupedTradeTable trades={result.trades} />
              : <TradeTable trades={result.trades} />
            }
          </div>
        ) : <div style={{ padding: '40px 0', textAlign: 'center', color: 'var(--text3)', fontSize: 14 }}>No trades in this period.</div>
      )}

      {/* ── Tab: Log ── */}
      {activeTab === 'log' && (
        <div>
          <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--text3)', marginBottom: 8, textTransform: 'uppercase', letterSpacing: '0.06em' }}>Log</div>
          <pre style={{ background: 'var(--bg0, #0d1117)', border: '1px solid var(--border)', borderRadius: 8, padding: '14px 16px', fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text2)', maxHeight: 600, overflowY: 'auto', whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}>
            {logData?.log || '(no log)'}
          </pre>
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Run Config Popup
// ---------------------------------------------------------------------------

type DateMode = 'days' | 'year' | 'range';

interface RunConfig {
  dateMode: DateMode;
  days: number;
  year: string;
  startDate: string;
  endDate: string;
  universe: string;
  compound_returns: boolean;
  daily_budget_reset: boolean;
  initialCapital: number;
}

type ReturnsMode = 'simple' | 'compound' | 'reset';
function modeFromCfg(c: { compound_returns: boolean; daily_budget_reset: boolean }): ReturnsMode {
  if (c.daily_budget_reset) return 'reset';
  return c.compound_returns ? 'compound' : 'simple';
}

function RunConfigPopup({
  strategy,
  initialConfig,
  onRun,
  onClose,
  isSubmitting,
}: {
  strategy: IntradayStrategy;
  initialConfig?: Partial<RunConfig>;
  onRun: (cfg: RunConfig) => void;
  onClose: () => void;
  isSubmitting: boolean;
}) {
  const [cfg, setCfg] = useState<RunConfig>({
    dateMode: 'days',
    days: strategy.days,
    year: String(new Date().getFullYear() - 1),
    startDate: '',
    endDate: '',
    universe: strategy.universe,
    compound_returns: strategy.compound_returns ?? false,
    daily_budget_reset: strategy.daily_budget_reset ?? false,
    initialCapital: strategy.initial_capital ?? 10000,
    ...initialConfig,
  });

  const set = <K extends keyof RunConfig>(k: K, v: RunConfig[K]) => setCfg(c => ({ ...c, [k]: v }));

  const modeBtn = (mode: DateMode, label: string) => (
    <button onClick={() => set('dateMode', mode)}
      style={{ padding: '6px 12px', fontSize: 12, fontFamily: 'var(--font-mono)', background: cfg.dateMode === mode ? 'var(--cyan-dim)' : 'var(--bg2)', border: 'none', borderRight: '1px solid var(--border)', color: cfg.dateMode === mode ? 'var(--cyan)' : 'var(--text3)', cursor: 'pointer', fontWeight: cfg.dateMode === mode ? 600 : 400 }}>
      {label}
    </button>
  );

  const labelStyle: React.CSSProperties = {
    fontSize: 12, color: 'var(--text3)', display: 'block',
    marginBottom: 6, textTransform: 'uppercase', letterSpacing: '0.07em', fontWeight: 600,
  };

  return (
    <div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.55)', zIndex: 200, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
    <div style={{ background: 'var(--bg1)', border: '1px solid var(--border)', borderRadius: 12, padding: '28px 32px', width: 500, boxShadow: '0 12px 40px rgba(0,0,0,0.35)' }}>

      {/* Header */}
      <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 24 }}>
        <div>
          <div style={{ fontSize: 17, fontWeight: 700, color: 'var(--text1)', marginBottom: 3 }}>Run Backtest</div>
          <div style={{ fontSize: 13, color: 'var(--text3)', fontFamily: 'var(--font-mono)' }}>{strategy.name}</div>
        </div>
        <button onClick={onClose}
          style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--text3)', padding: '2px 4px', borderRadius: 4, display: 'flex', lineHeight: 1 }}
          onMouseEnter={e => (e.currentTarget.style.color = 'var(--text1)')}
          onMouseLeave={e => (e.currentTarget.style.color = 'var(--text3)')}>
          <XCircle size={18} />
        </button>
      </div>

      {/* Period */}
      <div style={{ marginBottom: 18 }}>
        <label style={labelStyle}>Period</label>
        <div style={{ display: 'flex', border: '1px solid var(--border)', borderRadius: 8, overflow: 'hidden' }}>
          {modeBtn('days', 'Last N')}
          {modeBtn('year', 'Year')}
          {modeBtn('range', 'Range')}
        </div>
      </div>

      {cfg.dateMode === 'days' && (
        <div style={{ marginBottom: 18 }}>
          <label style={labelStyle}>Trading Days</label>
          <input type="number" value={cfg.days} onChange={e => set('days', Number(e.target.value))} min={10} max={500} style={inputStyle} />
        </div>
      )}
      {cfg.dateMode === 'year' && (
        <div style={{ marginBottom: 18 }}>
          <label style={labelStyle}>Year</label>
          <input type="text" value={cfg.year} onChange={e => set('year', e.target.value)} placeholder="e.g. 2025" style={inputStyle} />
        </div>
      )}
      {cfg.dateMode === 'range' && (
        <div style={{ marginBottom: 18, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <div>
            <label style={labelStyle}>Start Date</label>
            <input type="text" value={cfg.startDate} onChange={e => set('startDate', e.target.value)} placeholder="YYYY / YYYY-MM / YYYY-MM-DD" style={inputStyle} />
          </div>
          <div>
            <label style={labelStyle}>End Date <span style={{ fontWeight: 400, textTransform: 'none', letterSpacing: 0 }}>(optional)</span></label>
            <input type="text" value={cfg.endDate} onChange={e => set('endDate', e.target.value)} placeholder="default: today" style={inputStyle} />
          </div>
        </div>
      )}

      {/* Two-column row: Capital + Universe */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16, marginBottom: 18 }}>
        <div>
          <label style={labelStyle}>Initial Capital ($)</label>
          <input type="number" value={cfg.initialCapital} onChange={e => set('initialCapital', Number(e.target.value))} min={1000} step={1000} style={inputStyle} />
        </div>
        <div>
          <label style={labelStyle}>Universe</label>
          <select value={cfg.universe} onChange={e => set('universe', e.target.value)} style={selectStyle}>
            {buildRunUniverseOptions(strategy).map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
          </select>
        </div>
      </div>

      {/* Returns mode: 3-way selector */}
      {(() => {
        const mode = modeFromCfg(cfg);
        const setMode = (m: ReturnsMode) => {
          setCfg(c => ({
            ...c,
            compound_returns: m === 'compound',
            daily_budget_reset: m === 'reset',
          }));
        };
        const opt = (m: ReturnsMode, label: string, sub: string) => {
          const active = mode === m;
          return (
            <button key={m} onClick={() => setMode(m)}
              style={{
                flex: 1, padding: '8px 10px', fontSize: 12, fontFamily: 'var(--font-mono)',
                background: active ? 'var(--cyan-dim)' : 'var(--bg2)',
                border: 'none', borderRight: '1px solid var(--border)',
                color: active ? 'var(--cyan)' : 'var(--text3)',
                cursor: 'pointer', fontWeight: active ? 600 : 400,
                display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 2,
              }}>
              <span>{label}</span>
              <span style={{ fontSize: 10, opacity: 0.75 }}>{sub}</span>
            </button>
          );
        };
        return (
          <div style={{ marginBottom: 28 }}>
            <label style={labelStyle}>Returns Mode</label>
            <div style={{ display: 'flex', border: '1px solid var(--border)', borderRadius: 8, overflow: 'hidden' }}>
              {opt('simple', '단리', 'fixed capital')}
              {opt('compound', '복리', 'grows w/ equity')}
              {opt('reset', '리셋', 'daily reset (연구용)')}
            </div>
          </div>
        );
      })()}

      {/* Buttons */}
      <div style={{ display: 'flex', gap: 10 }}>
        <button onClick={onClose} style={{ flex: 1, padding: '10px', borderRadius: 8, background: 'var(--bg2)', border: '1px solid var(--border)', color: 'var(--text2)', cursor: 'pointer', fontSize: 14 }}>Cancel</button>
        <button onClick={() => onRun(cfg)} disabled={isSubmitting}
          style={{ flex: 2, padding: '10px', borderRadius: 8, background: isSubmitting ? 'var(--bg3)' : 'var(--cyan)', color: 'white', border: 'none', cursor: isSubmitting ? 'not-allowed' : 'pointer', fontSize: 14, fontWeight: 600, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 7 }}>
          <Play size={14} /> {isSubmitting ? 'Submitting…' : 'Run'}
        </button>
      </div>
    </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Strategy Form Modal
// ---------------------------------------------------------------------------

const DEFAULT_FORM: Omit<IntradayStrategy, 'slug'> = {
  name: '', description: '', days: 200, universe: 'midlarge',
  initial_capital: 10000, risk_per_trade_pct: 0.02, max_position_pct: 0.60,
  atr_stop_multiplier: 0.50, min_rvol: 1.0, max_candidates: 20,
  daily_max_loss_pct: 0.06, max_stops_per_day: 5, breakeven_at_r: 1.0,
  trailing_at_r: 2.0, trailing_stop_atr_multiplier: 0.0, order_timeout_minutes: 45,
  settlement_days: 1, max_gap_pct: 0.10, sim_bar_minutes: 30,
  orb_minutes: 5, compound_returns: false, daily_budget_reset: false,
};

function StrategyModal({
  mode, initial, onSave, onClose, isSaving,
}: {
  mode: 'create' | 'edit';
  initial: Omit<IntradayStrategy, 'slug'>;
  onSave: (d: Omit<IntradayStrategy, 'slug'>) => void;
  onClose: () => void;
  isSaving: boolean;
}) {
  const [form, setForm] = useState(initial);
  const set = (key: keyof typeof form) => (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
    const v = e.target.type === 'number' ? Number(e.target.value) : e.target.value;
    setForm(f => ({ ...f, [key]: v }));
  };

  const fields: { key: keyof typeof form; label: string; type: 'text' | 'number' | 'select' | 'textarea' | 'checkbox'; options?: { value: string; label: string }[]; step?: number; min?: number; max?: number; hint?: string; offLabel?: string; onLabel?: string }[] = [
    { key: 'name', label: 'Strategy Name', type: 'text', hint: 'Unique name' },
    { key: 'description', label: 'Description', type: 'textarea', hint: 'Optional' },
    { key: 'days', label: 'Default Lookback Days', type: 'number', min: 20, max: 500, step: 1 },
    { key: 'universe', label: 'Default Universe', type: 'select', options: STRATEGY_UNIVERSE_OPTIONS },
    { key: 'initial_capital', label: 'Initial Capital ($)', type: 'number', min: 1000, step: 1000 },
    { key: 'risk_per_trade_pct', label: 'Risk / Trade', type: 'number', min: 0.001, max: 0.5, step: 0.001, hint: '0.02 = 2%' },
    { key: 'max_position_pct', label: 'Max Position', type: 'number', min: 0.05, max: 1.0, step: 0.05, hint: '0.6 = 60%' },
    { key: 'atr_stop_multiplier', label: 'ATR Stop ×', type: 'number', min: 0.05, max: 2.0, step: 0.05 },
    { key: 'min_rvol', label: 'Min RVOL', type: 'number', min: 0.5, max: 5.0, step: 0.1 },
    { key: 'max_candidates', label: 'Max Candidates', type: 'number', min: 1, max: 50, step: 1 },
    { key: 'daily_max_loss_pct', label: 'Daily Max Loss', type: 'number', min: 0.005, max: 0.5, step: 0.005, hint: '0.06 = 6%' },
    { key: 'max_stops_per_day', label: 'Max Stops / Day', type: 'number', min: 1, max: 10, step: 1 },
    { key: 'breakeven_at_r', label: 'Breakeven at R', type: 'number', min: 0.5, max: 10.0, step: 0.5 },
    { key: 'trailing_at_r', label: 'Trailing at R', type: 'number', min: 1.0, max: 15.0, step: 0.5 },
    { key: 'trailing_stop_atr_multiplier', label: 'Trail ATR Mult', type: 'number', min: 0.0, max: 5.0, step: 0.25, hint: '0=swing-low mode; >0 = ATR×mult below peak (bar-size independent)' },
    { key: 'order_timeout_minutes', label: 'Order Timeout (min)', type: 'number', min: 10, max: 120, step: 5 },
    { key: 'settlement_days', label: 'Settlement (T+N)', type: 'number', min: 0, max: 2, step: 1, hint: '0=off, 1=T+1' },
    { key: 'max_gap_pct', label: 'Max Gap %', type: 'number', min: 0.005, max: 1.0, step: 0.005, hint: '0.01 = 1%' },
    { key: 'orb_minutes', label: 'ORB Window (min)', type: 'number', min: 5, max: 30, step: 5, hint: '5/10/15/20 — opening range width' },
    { key: 'sim_bar_minutes', label: 'Sim Bar (min)', type: 'number', min: 5, max: 120, step: 5, hint: '30/60/90/120 — stop check interval' },
    { key: 'compound_returns', label: 'Compound Returns (복리)', type: 'checkbox', hint: 'On=position size grows with equity; Off=fixed initial capital (단리)', offLabel: '단리', onLabel: '복리' },
    { key: 'daily_budget_reset', label: 'Daily Budget Reset (연구용)', type: 'checkbox', hint: 'Research mode: each day resets sizing to initial_capital (overrides compound)', offLabel: '일반', onLabel: '리셋' },
  ];

  return (
    <div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.6)', zIndex: 200, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24 }} onClick={onClose}>
      <div style={{ background: 'var(--bg1)', border: '1px solid var(--border)', borderRadius: 12, width: '100%', maxWidth: 640, maxHeight: '90vh', overflowY: 'auto', padding: 28 }} onClick={e => e.stopPropagation()}>
        <div style={{ fontSize: 18, fontWeight: 700, color: 'var(--text1)', marginBottom: 20 }}>
          {mode === 'create' ? 'New Strategy' : `Edit: ${initial.name}`}
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '14px 20px' }}>
          {fields.map(f => (
            <div key={f.key} style={f.key === 'name' || f.key === 'description' || f.key === 'compound_returns' || f.key === 'daily_budget_reset' ? { gridColumn: '1 / -1' } : {}}>
              <label style={{ display: 'block', fontSize: 12, color: 'var(--text3)', marginBottom: 4 }}>
                {f.label}{f.hint && <span style={{ marginLeft: 6, fontSize: 11, opacity: 0.7 }}>— {f.hint}</span>}
              </label>
              {f.type === 'select' ? (
                <select value={String(form[f.key])} onChange={set(f.key)} style={selectStyle}>
                  {f.options?.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
                </select>
              ) : f.type === 'textarea' ? (
                <textarea value={String(form[f.key])} onChange={set(f.key)} rows={2} style={{ ...inputStyle, resize: 'vertical', fontFamily: 'inherit' }} />
              ) : f.type === 'checkbox' ? (
                <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 4 }}>
                  <span style={{ fontSize: 13, color: form[f.key] ? 'var(--text3)' : 'var(--cyan)', fontWeight: form[f.key] ? 400 : 600 }}>{f.offLabel ?? 'Off'}</span>
                  <div onClick={() => setForm(prev => ({ ...prev, [f.key]: !prev[f.key] }))}
                    style={{ width: 40, height: 22, borderRadius: 11, background: form[f.key] ? 'var(--cyan)' : 'var(--bg3)', border: '1px solid var(--border)', cursor: 'pointer', position: 'relative', transition: 'background 0.2s' }}>
                    <div style={{ position: 'absolute', top: 2, left: form[f.key] ? 19 : 2, width: 16, height: 16, borderRadius: '50%', background: 'white', transition: 'left 0.2s', boxShadow: '0 1px 3px rgba(0,0,0,0.3)' }} />
                  </div>
                  <span style={{ fontSize: 13, color: form[f.key] ? 'var(--cyan)' : 'var(--text3)', fontWeight: form[f.key] ? 600 : 400 }}>{f.onLabel ?? 'On'}</span>
                </div>
              ) : (
                <input type={f.type} value={String(form[f.key])} onChange={set(f.key)} min={f.min} max={f.max} step={f.step} style={inputStyle} />
              )}
            </div>
          ))}
        </div>
        <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 10, marginTop: 24 }}>
          <button onClick={onClose} style={{ padding: '8px 18px', borderRadius: 7, background: 'var(--bg2)', border: '1px solid var(--border)', color: 'var(--text2)', cursor: 'pointer', fontSize: 14 }}>Cancel</button>
          <button onClick={() => onSave(form)} disabled={isSaving || !form.name.trim()}
            style={{ padding: '8px 20px', borderRadius: 7, background: isSaving || !form.name.trim() ? 'var(--bg3)' : 'var(--cyan)', color: 'white', border: 'none', cursor: isSaving || !form.name.trim() ? 'not-allowed' : 'pointer', fontSize: 14, fontWeight: 600 }}>
            {isSaving ? 'Saving…' : mode === 'create' ? 'Create' : 'Save'}
          </button>
        </div>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Strategy Table (replaces cards — compact leaderboard with latest results)
// ---------------------------------------------------------------------------

const sthStyle: React.CSSProperties = {
  padding: '8px 8px', textAlign: 'left', fontSize: 10, color: 'var(--text3)',
  textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600, whiteSpace: 'nowrap',
};
const stdStyle: React.CSSProperties = {
  padding: '7px 8px', fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text2)', whiteSpace: 'nowrap',
};

function isOrbStrategy(s: IntradayStrategy): boolean {
  return (s.strategy_mode ?? 'orb') === 'orb';
}

function isAdaptiveStrategy(s: IntradayStrategy): boolean {
  return (s.strategy_mode ?? '') === 'adaptive';
}

function isCompDeploymentStrategy(s: IntradayStrategy): boolean {
  return Boolean(s.is_comp_equity_deployment)
    || (
      isOrbStrategy(s)
      && s.compound_returns === true
      && s.daily_budget_reset === false
      && s.single_trade_loss_cap_basis === 'equity'
    );
}

function strategyModeLabel(s: IntradayStrategy): string {
  if (isCompDeploymentStrategy(s)) return 'ORB Comp';
  if (isOrbStrategy(s)) return 'ORB';
  if (isAdaptiveStrategy(s)) return 'Adaptive';
  return 'Momentum';
}

function strategySummaryLabel(s: IntradayStrategy): string {
  if (isOrbStrategy(s)) {
    return `risk ${fmtPct(s.risk_per_trade_pct, 1)} · atr ${fmt(s.atr_stop_multiplier)} · rvol ${fmt(s.min_rvol, 1)}`;
  }
  if (isAdaptiveStrategy(s)) {
    const sizing = s.position_sizing && s.position_sizing !== 'equal_weight' ? ` · ${s.position_sizing}` : '';
    return `entry +${s.entry_minutes_after_open ?? '—'}m · top ${s.top_n ?? '—'} · gain ${fmtPct(s.min_morning_gain_pct, 1)} · stop ${fmtPct(s.stop_loss_pct, 1)}${sizing}`;
  }
  return `entry +${s.entry_minutes_after_open ?? '—'}m · top ${s.top_n ?? '—'} · gain ${fmtPct(s.min_morning_gain_pct, 1)}`;
}

function StrategyTable({
  strategies, onEdit, onDelete, onRun, onCopy, onCreateComp, creatingCompSlug,
}: {
  strategies: IntradayStrategy[];
  onEdit: (s: IntradayStrategy) => void;
  onDelete: (slug: string) => void;
  onRun: (s: IntradayStrategy) => void;
  onCopy: (slug: string) => void;
  onCreateComp: (slug: string) => void;
  creatingCompSlug: string | null;
}) {
  return (
    <div style={{ overflowX: 'auto', borderRadius: 10, border: '1px solid var(--border)', background: 'var(--bg1)' }}>
      <table style={{ width: '100%', borderCollapse: 'collapse', minWidth: 600 }}>
        <thead>
          <tr style={{ background: 'var(--bg2)', borderBottom: '1px solid var(--border)' }}>
            <th style={sthStyle}>Name</th>
            <th style={{ ...sthStyle, textAlign: 'center' }}>Mode</th>
            <th style={{ ...sthStyle, textAlign: 'right' }}>Universe</th>
            <th style={{ ...sthStyle, textAlign: 'right' }}>Profile</th>
            <th style={{ ...sthStyle, textAlign: 'right' }}>Days</th>
            <th style={{ ...sthStyle, textAlign: 'center' }}></th>
          </tr>
        </thead>
        <tbody>
          {strategies.map(s => (
            <tr key={s.slug} style={{ borderBottom: '1px solid var(--border)' }}
              onMouseEnter={e => (e.currentTarget.style.background = 'var(--bg2)')}
              onMouseLeave={e => (e.currentTarget.style.background = 'transparent')}>
              <td style={{ ...stdStyle, color: 'var(--text1)', fontWeight: 600, fontSize: 13 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                  {s.id != null && (
                    <span style={{ fontSize: 10, fontWeight: 700, color: 'var(--text3)', background: 'var(--bg2)', border: '1px solid var(--border)', borderRadius: 4, padding: '1px 5px', fontFamily: 'var(--font-mono)', flexShrink: 0 }}>#{s.id}</span>
                  )}
                  <span>{s.name}</span>
                  {isOrbStrategy(s) && (
                    <>
                      <button onClick={() => onEdit(s)} title="Edit"
                        style={{ padding: '2px 4px', background: 'none', border: 'none', color: 'var(--text3)', cursor: 'pointer', display: 'flex', flexShrink: 0 }}
                        onMouseEnter={e => (e.currentTarget.style.color = 'var(--cyan)')}
                        onMouseLeave={e => (e.currentTarget.style.color = 'var(--text3)')}>
                        <Edit2 size={11} />
                      </button>
                      <button onClick={() => onCopy(s.slug)} title="Copy"
                        style={{ padding: '2px 4px', background: 'none', border: 'none', color: 'var(--text3)', cursor: 'pointer', display: 'flex', flexShrink: 0 }}
                        onMouseEnter={e => (e.currentTarget.style.color = 'var(--cyan)')}
                        onMouseLeave={e => (e.currentTarget.style.color = 'var(--text3)')}>
                        <Copy size={11} />
                      </button>
                      {!isCompDeploymentStrategy(s) && (
                        <button onClick={() => onCreateComp(s.slug)} title="Create comp deployment strategy"
                          disabled={creatingCompSlug === s.slug}
                          style={{
                            padding: '2px 6px', background: 'var(--bg2)', border: '1px solid var(--border)',
                            color: creatingCompSlug === s.slug ? 'var(--text3)' : 'var(--yellow)',
                            cursor: creatingCompSlug === s.slug ? 'not-allowed' : 'pointer',
                            borderRadius: 4, fontSize: 10, fontFamily: 'var(--font-mono)', fontWeight: 700,
                            display: 'flex', flexShrink: 0,
                          }}
                          onMouseEnter={e => {
                            if (creatingCompSlug !== s.slug) {
                              e.currentTarget.style.borderColor = 'var(--yellow)';
                            }
                          }}
                          onMouseLeave={e => (e.currentTarget.style.borderColor = 'var(--border)')}>
                          {creatingCompSlug === s.slug ? '...' : 'Comp'}
                        </button>
                      )}
                    </>
                  )}
                  <button onClick={() => onDelete(s.slug)} title="Delete"
                    style={{ padding: '2px 4px', background: 'none', border: 'none', color: 'var(--text3)', cursor: 'pointer', display: 'flex', flexShrink: 0 }}
                    onMouseEnter={e => (e.currentTarget.style.color = 'var(--red)')}
                    onMouseLeave={e => (e.currentTarget.style.color = 'var(--text3)')}>
                    <Trash2 size={11} />
                  </button>
                </div>
              </td>
              <td style={{ ...stdStyle, textAlign: 'center' }}>
                <span style={{
                  padding: '2px 7px',
                  borderRadius: 4,
                  background: 'var(--bg2)',
                  color: isCompDeploymentStrategy(s) ? 'var(--yellow)' : isOrbStrategy(s) ? 'var(--cyan)' : 'var(--green)',
                }}>
                  {strategyModeLabel(s)}
                </span>
              </td>
              <td style={{ ...stdStyle, textAlign: 'right' }}>{s.universe_label ?? s.universe}</td>
              <td style={{ ...stdStyle, textAlign: 'right', maxWidth: 320, overflow: 'hidden', textOverflow: 'ellipsis' }} title={strategySummaryLabel(s)}>
                {strategySummaryLabel(s)}
              </td>
              <td style={{ ...stdStyle, textAlign: 'right' }}>{s.days}</td>
              <td style={{ padding: '5px 8px', textAlign: 'center' }}>
                <button onClick={e => { e.stopPropagation(); onRun(s); }}
                  style={{ padding: '4px 12px', borderRadius: 5, background: 'var(--cyan)', color: 'white', border: 'none', cursor: 'pointer', fontSize: 12, fontWeight: 600, display: 'inline-flex', alignItems: 'center', gap: 4 }}>
                  <Play size={11} /> Run
                </button>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Main Page  /intraday
// ---------------------------------------------------------------------------

export function IntradayBacktestPage() {
  const navigate = useNavigate();
  const qc = useQueryClient();

  const { data: tasksData, isLoading: tasksLoading } = useQuery({
    queryKey: ['intraday-tasks'],
    queryFn: intradayApi.tasks,
    refetchInterval: 5000,
  });
  const tasks = tasksData?.tasks ?? [];


  const { data: strategiesData, isLoading: strategiesLoading } = useQuery({
    queryKey: ['intraday-strategies'],
    queryFn: intradayApi.strategies,
    staleTime: 30_000,
  });
  const strategies = strategiesData?.strategies ?? [];

  const [runningFor, setRunningFor] = useState<IntradayStrategy | null>(null);
  const [duplicateTask, setDuplicateTask] = useState<IntradayTask | null>(null);
  const [modalMode, setModalMode] = useState<'create' | 'edit' | null>(null);
  const [modalInitial, setModalInitial] = useState<Omit<IntradayStrategy, 'slug'>>(DEFAULT_FORM);
  const [editingSlug, setEditingSlug] = useState<string | null>(null);
  const [confirmDeleteSlug, setConfirmDeleteSlug] = useState<string | null>(null);
  const [creatingCompSlug, setCreatingCompSlug] = useState<string | null>(null);

  const submitMutation = useMutation({
    mutationFn: (req: Parameters<typeof intradayApi.submit>[0]) => intradayApi.submit(req),
    onSuccess: (data) => {
      qc.invalidateQueries({ queryKey: ['intraday-tasks'] });
      setRunningFor(null);
      setDuplicateTask(null);
      navigate(`/intraday/tasks/${data.task_id}`);
    },
  });

  const createMutation = useMutation({
    mutationFn: (p: Omit<IntradayStrategy, 'slug'>) => intradayApi.createStrategy(p),
    onSuccess: () => { qc.invalidateQueries({ queryKey: ['intraday-strategies'] }); setModalMode(null); },
  });

  const updateMutation = useMutation({
    mutationFn: ({ slug, payload }: { slug: string; payload: Partial<Omit<IntradayStrategy, 'slug'>> }) =>
      intradayApi.updateStrategy(slug, payload),
    onSuccess: () => { qc.invalidateQueries({ queryKey: ['intraday-strategies'] }); setModalMode(null); },
  });

  const deleteMutation = useMutation({
    mutationFn: (slug: string) => intradayApi.deleteStrategy(slug),
    onSuccess: () => { qc.invalidateQueries({ queryKey: ['intraday-strategies'] }); setConfirmDeleteSlug(null); },
  });

  const copyMutation = useMutation({
    mutationFn: (slug: string) => intradayApi.copyStrategy(slug),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['intraday-strategies'] }),
  });

  const createCompMutation = useMutation({
    mutationFn: async (slug: string) => {
      setCreatingCompSlug(slug);
      return intradayApi.createCompStrategy(slug);
    },
    onSuccess: () => qc.invalidateQueries({ queryKey: ['intraday-strategies'] }),
    onSettled: () => setCreatingCompSlug(null),
  });

  const deleteTaskMutation = useMutation({
    mutationFn: (taskId: string) => intradayApi.deleteTask(taskId),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['intraday-tasks'] }),
  });

  function handleRunSubmit(cfg: RunConfig) {
    if (!runningFor) return;
    const req: Parameters<typeof intradayApi.submit>[0] = {
      config: runningFor.slug, days: cfg.days, universe: cfg.universe,
      compound_returns: cfg.compound_returns,
      daily_budget_reset: cfg.daily_budget_reset,
      initial_capital: cfg.initialCapital,
    };
    if (cfg.dateMode === 'year') req.year = cfg.year;
    else if (cfg.dateMode === 'range') {
      req.start_date = cfg.startDate || null;
      req.end_date = cfg.endDate || null;
    }
    submitMutation.mutate(req);
  }

  function getTaskInitialConfig(task: IntradayTask): Partial<RunConfig> {
    const base: Partial<RunConfig> = {
      days: task.days,
      universe: task.universe,
      compound_returns: task.compound_returns ?? false,
      daily_budget_reset: task.daily_budget_reset ?? false,
    };
    if (task.year) return { ...base, dateMode: 'year', year: task.year };
    if (task.start_date) return { ...base, dateMode: 'range', startDate: task.start_date, endDate: task.end_date ?? '' };
    return { ...base, dateMode: 'days' };
  }

  function handleDuplicateSubmit(cfg: RunConfig) {
    if (!duplicateTask) return;
    const req: Parameters<typeof intradayApi.submit>[0] = {
      config: duplicateTask.config, days: cfg.days, universe: cfg.universe,
      compound_returns: cfg.compound_returns,
      daily_budget_reset: cfg.daily_budget_reset,
      initial_capital: cfg.initialCapital,
    };
    if (cfg.dateMode === 'year') req.year = cfg.year;
    else if (cfg.dateMode === 'range') {
      req.start_date = cfg.startDate || null;
      req.end_date = cfg.endDate || null;
    }
    submitMutation.mutate(req);
  }

  function handleEdit(s: IntradayStrategy) {
    setEditingSlug(s.slug);
    const { slug: _s, ...rest } = s;
    setModalInitial(rest);
    setModalMode('edit');
  }

  function handleSave(data: Omit<IntradayStrategy, 'slug'>) {
    if (modalMode === 'create') createMutation.mutate(data);
    else if (modalMode === 'edit' && editingSlug) updateMutation.mutate({ slug: editingSlug, payload: data });
  }

  function getStrategyName(slug: string) {
    return strategies.find(s => s.slug === slug)?.name ?? slug;
  }

  return (
    <div style={{ padding: '28px 32px' }}>
      <style>{`@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }`}</style>

      {/* Header */}
      <div style={{ marginBottom: 28 }}>
        <h1 style={{ fontSize: 24, fontWeight: 700, color: 'var(--text1)', margin: '0 0 6px' }}>Intraday ORB Backtest</h1>
        <p style={{ fontSize: 14, color: 'var(--text3)', margin: 0 }}>
          Opening Range Breakout — first 5-min candle breakout, ATR-based stops, RVOL-ranked candidates
        </p>
      </div>

      {/* Strategies */}
      <div style={{ marginBottom: 32 }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 }}>
          <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--text2)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>
            Strategies {!strategiesLoading && `(${strategies.length})`}
          </div>
          <button
            onClick={e => { e.stopPropagation(); setModalInitial(DEFAULT_FORM); setModalMode('create'); }}
            style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '7px 14px', borderRadius: 7, background: 'var(--bg2)', border: '1px solid var(--border)', color: 'var(--text2)', cursor: 'pointer', fontSize: 13, fontWeight: 500 }}
            onMouseEnter={e => { e.currentTarget.style.borderColor = 'var(--cyan)'; e.currentTarget.style.color = 'var(--cyan)'; }}
            onMouseLeave={e => { e.currentTarget.style.borderColor = 'var(--border)'; e.currentTarget.style.color = 'var(--text2)'; }}>
            <Plus size={14} /> New Strategy
          </button>
        </div>

        {strategiesLoading ? (
          <div style={{ color: 'var(--text3)', fontSize: 14 }}>Loading strategies…</div>
        ) : (
          <StrategyTable strategies={strategies}
            onEdit={handleEdit} onDelete={slug => setConfirmDeleteSlug(slug)}
            onRun={s => setRunningFor(s)} onCopy={slug => copyMutation.mutate(slug)}
            onCreateComp={slug => createCompMutation.mutate(slug)}
            creatingCompSlug={creatingCompSlug} />
        )}
        {submitMutation.isError && (
          <div style={{ marginTop: 10, fontSize: 13, color: 'var(--red)' }}>
            Submit failed: {(submitMutation.error as Error).message}
          </div>
        )}
        {createCompMutation.isError && (
          <div style={{ marginTop: 10, fontSize: 13, color: 'var(--red)' }}>
            Comp strategy creation failed: {(createCompMutation.error as Error).message}
          </div>
        )}

        {/* Run config modal (shared for all strategies) */}
        {runningFor && (
          <RunConfigPopup strategy={runningFor} onRun={handleRunSubmit} onClose={() => setRunningFor(null)} isSubmitting={submitMutation.isPending} />
        )}
        {/* Duplicate run config modal */}
        {duplicateTask && strategies.find(s => s.slug === duplicateTask.config) && (
          <RunConfigPopup
            strategy={strategies.find(s => s.slug === duplicateTask.config)!}
            initialConfig={getTaskInitialConfig(duplicateTask)}
            onRun={handleDuplicateSubmit}
            onClose={() => setDuplicateTask(null)}
            isSubmitting={submitMutation.isPending}
          />
        )}
      </div>

      {/* Run History */}
      <div style={{ background: 'var(--bg1)', border: '1px solid var(--border)', borderRadius: 10, overflow: 'hidden' }}>
        <div style={{ padding: '14px 20px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <span style={{ fontSize: 14, fontWeight: 600, color: 'var(--text2)' }}>Run History ({tasks.length})</span>
          {tasksLoading && <Loader size={14} style={{ color: 'var(--text3)', animation: 'spin 1s linear infinite' }} />}
        </div>

        {tasks.length === 0 ? (
          <div style={{ padding: '40px 20px', textAlign: 'center', color: 'var(--text3)', fontSize: 14 }}>
            No runs yet — click Run on a strategy above.
          </div>
        ) : (
          <table style={{ width: '100%', borderCollapse: 'collapse' }}>
            <thead>
              <tr style={{ borderBottom: '1px solid var(--border)' }}>
                {['Status', 'Strategy', 'Period', 'Universe', '수익방식', 'Return', 'Max DD', 'Sharpe', 'WR', 'Trades', 'Started', ''].map(h => (
                  <th key={h} style={{ padding: '9px 14px', textAlign: 'left', fontSize: 11, color: 'var(--text3)', textTransform: 'uppercase', letterSpacing: '0.07em', fontWeight: 600 }}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {tasks.map(task => {
                const r = task.result_summary;
                const ret = r?.return_pct;
                const compoundLabel = task.daily_budget_reset === true
                  ? '리셋'
                  : task.compound_returns === true
                    ? '복리'
                    : task.compound_returns === false
                      ? '단리'
                      : '—';
                const compoundColor = task.daily_budget_reset === true
                  ? 'var(--yellow)'
                  : task.compound_returns === true
                    ? 'var(--cyan)'
                    : 'var(--text3)';
                return (
                  <tr key={task.task_id}
                    onClick={() => navigate(`/intraday/tasks/${task.task_id}`)}
                    style={{ borderBottom: '1px solid var(--border)', cursor: 'pointer', transition: 'background 0.1s' }}
                    onMouseEnter={e => (e.currentTarget.style.background = 'var(--bg2)')}
                    onMouseLeave={e => (e.currentTarget.style.background = 'transparent')}>
                    <td style={{ padding: '10px 14px' }}><StatusDot status={task.status} /></td>
                    <td style={{ padding: '10px 14px', fontSize: 13, color: 'var(--text2)', fontFamily: 'var(--font-mono)' }}>{getStrategyName(task.config)}</td>
                    <td style={{ padding: '10px 14px', fontSize: 12, color: 'var(--text3)', fontFamily: 'var(--font-mono)' }}>{taskPeriodLabel(task)}</td>
                    <td style={{ padding: '10px 14px', fontSize: 13, color: 'var(--text2)' }}>{task.universe_label ?? task.universe}</td>
                    <td style={{ padding: '10px 14px', fontSize: 12, color: compoundColor, fontWeight: 600 }}>{compoundLabel}</td>
                    <td style={{ padding: '10px 14px', fontSize: 13, fontFamily: 'var(--font-mono)', fontWeight: 600, color: ret != null ? (ret >= 0 ? 'var(--green)' : 'var(--red)') : 'var(--text3)' }}>
                      {ret != null ? `${ret >= 0 ? '+' : ''}${(ret * 100).toFixed(1)}%` : task.status === 'running' ? '…' : '—'}
                    </td>
                    <td style={{ padding: '10px 14px', fontSize: 13, fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>
                      {r?.max_dd_pct != null ? `${(r.max_dd_pct * 100).toFixed(1)}%` : '—'}
                    </td>
                    <td style={{ padding: '10px 14px', fontSize: 13, fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>
                      {r?.sharpe != null ? r.sharpe.toFixed(2) : '—'}
                    </td>
                    <td style={{ padding: '10px 14px', fontSize: 13, fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>
                      {r?.win_rate != null ? `${r.win_rate.toFixed(1)}%` : '—'}
                    </td>
                    <td style={{ padding: '10px 14px', fontSize: 13, fontFamily: 'var(--font-mono)', color: 'var(--text2)' }}>
                      {r?.trade_count ?? '—'}
                    </td>
                    <td style={{ padding: '10px 14px', fontSize: 12, color: 'var(--text3)' }}>
                      {task.started_at
                        ? new Date(task.started_at).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })
                        : new Date(task.created_at).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })}
                    </td>
                    <td style={{ padding: '10px 14px' }} onClick={e => e.stopPropagation()}>
                      <div style={{ display: 'flex', gap: 2 }}>
                        <button onClick={() => setDuplicateTask(task)}
                          title="Duplicate Run"
                          style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--text3)', padding: '2px 4px', borderRadius: 4, display: 'flex', alignItems: 'center' }}
                          onMouseEnter={e => (e.currentTarget.style.color = 'var(--cyan)')}
                          onMouseLeave={e => (e.currentTarget.style.color = 'var(--text3)')}>
                          <Copy size={13} />
                        </button>
                        <button onClick={() => deleteTaskMutation.mutate(task.task_id)}
                          title="Delete"
                          style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--text3)', padding: '2px 4px', borderRadius: 4, display: 'flex', alignItems: 'center' }}
                          onMouseEnter={e => (e.currentTarget.style.color = 'var(--red)')}
                          onMouseLeave={e => (e.currentTarget.style.color = 'var(--text3)')}>
                          <Trash2 size={13} />
                        </button>
                      </div>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        )}
      </div>

      {/* Strategy Modal */}
      {modalMode && (
        <StrategyModal mode={modalMode} initial={modalInitial} onSave={handleSave} onClose={() => setModalMode(null)}
          isSaving={createMutation.isPending || updateMutation.isPending} />
      )}

      {/* Delete Confirmation */}
      {confirmDeleteSlug && (
        <div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.5)', zIndex: 200, display: 'flex', alignItems: 'center', justifyContent: 'center' }} onClick={() => setConfirmDeleteSlug(null)}>
          <div style={{ background: 'var(--bg1)', border: '1px solid var(--border)', borderRadius: 10, padding: '24px 28px', maxWidth: 400, width: '100%' }} onClick={e => e.stopPropagation()}>
            <div style={{ fontSize: 16, fontWeight: 700, color: 'var(--text1)', marginBottom: 8 }}>Delete Strategy?</div>
            <div style={{ fontSize: 13, color: 'var(--text3)', marginBottom: 20 }}>
              Delete <strong style={{ color: 'var(--text2)' }}>{getStrategyName(confirmDeleteSlug)}</strong>? This cannot be undone.
            </div>
            <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end' }}>
              <button onClick={() => setConfirmDeleteSlug(null)} style={{ padding: '7px 16px', borderRadius: 6, background: 'var(--bg2)', border: '1px solid var(--border)', color: 'var(--text2)', cursor: 'pointer', fontSize: 13 }}>Cancel</button>
              <button onClick={() => deleteMutation.mutate(confirmDeleteSlug)} disabled={deleteMutation.isPending}
                style={{ padding: '7px 16px', borderRadius: 6, background: 'var(--red)', color: 'white', border: 'none', cursor: 'pointer', fontSize: 13, fontWeight: 600 }}>
                {deleteMutation.isPending ? 'Deleting…' : 'Delete'}
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
