// ===== Backtesting Dashboard — Strategy Evaluation & Grid Search =====

function exportToCsv(filename, headers, rows) {
  const escape = v => '"' + String(v ?? '').replace(/"/g, '""') + '"';
  const csv = [headers.join(',')].concat(rows.map(r => r.map(escape).join(','))).join('\n');
  const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a'); a.href = url; a.download = filename; a.click();
  URL.revokeObjectURL(url);
}

function BacktestingPage() {
  const [tab, setTab] = React.useState('run');       // run | history | detail | grid
  const [detailId, setDetailId] = React.useState(null);

  function openDetail(id) { setDetailId(id); setTab('detail'); }
  function backToHistory() { setTab('history'); setDetailId(null); }

  const tabs = [
    { key: 'run',     icon: '🚀', label: 'New Run' },
    { key: 'history', icon: '📋', label: 'History' },
    { key: 'grid',    icon: '🔬', label: 'Parameter Optimizer' },
  ];

  return React.createElement('div', { className: 'bt-page' },
    React.createElement('div', { className: 'bt-header' },
      React.createElement('h1', null, '🧪 ', 'Backtesting Lab'),
      React.createElement('p', { className: 'bt-subtitle' }, 'Evaluate strategies against historical data with institutional-grade analytics')
    ),
    tab !== 'detail' && React.createElement('div', { className: 'bt-tabs' },
      tabs.map(t => React.createElement('button', {
        key: t.key,
        className: 'bt-tab' + (tab === t.key ? ' active' : ''),
        onClick: () => setTab(t.key)
      }, t.icon, ' ', t.label))
    ),
    tab === 'run' && React.createElement(NewRunTab, { onSubmitted: () => setTab('history') }),
    tab === 'history' && React.createElement(HistoryTab, { onOpenDetail: openDetail }),
    tab === 'detail' && React.createElement(RunDetailView, { runId: detailId, onBack: backToHistory }),
    tab === 'grid' && React.createElement(GridSearchTab, { onOpenDetail: openDetail })
  );
}

// ═══════════════════════════════════════════════════════════════
//  NEW RUN TAB
// ═══════════════════════════════════════════════════════════════

function NewRunTab({ onSubmitted }) {
  const [form, setForm] = React.useState({
    strategy: 'Phantom', root: 'NIFTY',
    startDate: '', endDate: '',
    catastropheSlPct: 10, takeProfitPct: 15, trailingFloorPct: 10,
    maxOrdersPerDay: 3, dailyProfitTargetPct: 10,
    onnxMinConfidence: 55, lots: 1, label: '',
  });
  const [submitting, setSubmitting] = React.useState(false);
  const [result, setResult] = React.useState(null);
  const toast = useToast();

  function upd(k, v) { setForm(prev => ({ ...prev, [k]: v })); }

  async function submit() {
    if (!form.startDate || !form.endDate) { toast('Start and end dates are required', 'error'); return; }
    setSubmitting(true);
    try {
      const body = {
        strategy: form.strategy, root: form.root,
        startDate: form.startDate, endDate: form.endDate,
        catastropheSlPct: form.catastropheSlPct / 100,
        takeProfitPct: form.takeProfitPct / 100,
        trailingFloorPct: form.trailingFloorPct / 100,
        maxOrdersPerDay: parseInt(form.maxOrdersPerDay),
        dailyProfitTargetPct: form.dailyProfitTargetPct / 100,
        onnxMinConfidence: form.onnxMinConfidence / 100,
        lots: parseInt(form.lots),
        label: form.label || null,
      };
      const res = await API.post('/api/backtest/run', body);
      setResult(res);
      toast('Backtest queued — RunId: ' + res.runId.substring(0, 8), 'success');
    } catch (e) { toast('Failed: ' + e.message, 'error'); }
    setSubmitting(false);
  }

  const strategies = ['Phantom', 'OnnxWithPhantomGate', 'OnnxRaw'];
  const isOnnx = form.strategy !== 'Phantom';

  return React.createElement('div', { className: 'bt-card' },
    React.createElement('h2', { className: 'bt-card-title' }, '⚙️ Configure Backtest'),

    React.createElement('div', { className: 'bt-form-grid' },
      // Strategy & Root
      FormSelect('Strategy', form.strategy, v => upd('strategy', v), strategies),
      FormSelect('Root Symbol', form.root, v => upd('root', v), ['NIFTY', 'SENSEX']),

      // Dates
      FormInput('Start Date', 'date', form.startDate, v => upd('startDate', v)),
      FormInput('End Date', 'date', form.endDate, v => upd('endDate', v)),

      // Risk params
      FormInput('Catastrophe SL %', 'number', form.catastropheSlPct, v => upd('catastropheSlPct', v), { min: 1, max: 50, step: 1 }),
      FormInput('Take Profit %', 'number', form.takeProfitPct, v => upd('takeProfitPct', v), { min: 1, max: 100, step: 1 }),
      FormInput('Trailing Floor %', 'number', form.trailingFloorPct, v => upd('trailingFloorPct', v), { min: 1, max: 50, step: 1 }),
      FormInput('Max Orders/Day', 'number', form.maxOrdersPerDay, v => upd('maxOrdersPerDay', v), { min: 1, max: 20, step: 1 }),
      FormInput('Daily Target %', 'number', form.dailyProfitTargetPct, v => upd('dailyProfitTargetPct', v), { min: 1, max: 50, step: 1 }),

      // ONNX
      isOnnx && FormInput('ONNX Min Confidence %', 'number', form.onnxMinConfidence, v => upd('onnxMinConfidence', v), { min: 30, max: 95, step: 5 }),

      // Trade sim
      FormInput('Lots', 'number', form.lots, v => upd('lots', v), { min: 1, max: 100, step: 1 }),
      FormInput('Label (optional)', 'text', form.label, v => upd('label', v)),
    ),

    React.createElement('div', { className: 'bt-form-actions' },
      React.createElement('button', {
        className: 'bt-btn bt-btn-primary',
        onClick: submit,
        disabled: submitting
      }, submitting ? '⏳ Queuing...' : '🚀 Run Backtest'),
      result && React.createElement('span', { className: 'bt-success-msg' },
        '✅ Queued! RunId: ', result.runId.substring(0, 8),
        ' — ',
        React.createElement('a', { href: '#', onClick: e => { e.preventDefault(); onSubmitted(); } }, 'View History →')
      )
    )
  );
}

// ═══════════════════════════════════════════════════════════════
//  HISTORY TAB
// ═══════════════════════════════════════════════════════════════

function HistoryTab({ onOpenDetail }) {
  const [runs, setRuns] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [sortCol, setSortCol] = React.useState(null);
  const [sortDir, setSortDir] = React.useState('desc');

  async function load() {
    setLoading(true);
    try {
      const data = await API.get('/api/backtest/runs?count=50');
      setRuns(data);
    } catch (e) { console.error(e); }
    setLoading(false);
  }

  React.useEffect(() => { load(); const iv = setInterval(load, 15000); return () => clearInterval(iv); }, []);

  function toggleSort(col) {
    if (sortCol === col) setSortDir(d => d === 'asc' ? 'desc' : 'asc');
    else { setSortCol(col); setSortDir('desc'); }
  }

  const sorted = React.useMemo(() => {
    if (!sortCol) return runs;
    return [...runs].sort((a, b) => {
      const va = a[sortCol] ?? 0, vb = b[sortCol] ?? 0;
      return sortDir === 'asc' ? (va > vb ? 1 : -1) : (va < vb ? 1 : -1);
    });
  }, [runs, sortCol, sortDir]);

  const sortIcon = (col) => sortCol === col ? (sortDir === 'asc' ? ' ▲' : ' ▼') : '';

  if (loading && runs.length === 0) return React.createElement('div', { className: 'bt-loading' }, '⏳ Loading runs...');

  return React.createElement('div', { className: 'bt-card' },
    React.createElement('div', { className: 'bt-card-header' },
      React.createElement('h2', { className: 'bt-card-title' }, '📋 Backtest History'),
      React.createElement('button', { className: 'bt-btn bt-btn-sm', onClick: load }, '🔄 Refresh')
    ),
    runs.length === 0
      ? React.createElement('p', { className: 'bt-empty' }, 'No backtest runs yet. Go to "New Run" to start.')
      : React.createElement('div', { className: 'bt-table-wrap' },
          React.createElement('table', { className: 'bt-table' },
            React.createElement('thead', null,
              React.createElement('tr', null,
                [['Status',null],['Strategy',null],['Dates',null],['Trades','totalTrades'],['Win%','winRate'],['PnL','totalPnlPoints'],['Sharpe','sharpeRatio'],['PF','profitFactor'],['Time','durationMs'],['',null]].map(([h,col]) =>
                  React.createElement('th', {
                    key: h,
                    className: (col ? 'bt-sortable ' : '') + (!col || h === 'Status' || h === 'Strategy' || h === 'Dates' ? '' : 'bt-right'),
                    onClick: col ? () => toggleSort(col) : undefined,
                    style: col ? { cursor: 'pointer', userSelect: 'none' } : {}
                  }, h + (col ? sortIcon(col) : ''))
                )
              )
            ),
            React.createElement('tbody', null,
              sorted.map(r => React.createElement('tr', { key: r.runId, className: r.status === 'FAILED' ? 'bt-row-failed' : '' },
                React.createElement('td', null, StatusBadge(r.status)),
                React.createElement('td', null, StrategyBadge(r.strategy)),
                React.createElement('td', { className: 'bt-mono' }, r.startDate, ' → ', r.endDate),
                React.createElement('td', { className: 'bt-right' }, r.totalTrades),
                React.createElement('td', { className: 'bt-right' }, r.winRate.toFixed(1) + '%'),
                React.createElement('td', { className: 'bt-right ' + (r.totalPnlPoints >= 0 ? 'bt-green' : 'bt-red') },
                  (r.totalPnlPoints >= 0 ? '+' : '') + r.totalPnlPoints.toFixed(1)),
                React.createElement('td', { className: 'bt-right' }, r.sharpeRatio.toFixed(2)),
                React.createElement('td', { className: 'bt-right' }, r.profitFactor > 999 ? '∞' : r.profitFactor.toFixed(2)),
                React.createElement('td', { className: 'bt-mono bt-muted bt-right' }, r.durationMs ? (r.durationMs / 1000).toFixed(1) + 's' : '—'),
                React.createElement('td', null,
                  r.status === 'COMPLETED' && React.createElement('button', {
                    className: 'bt-btn bt-btn-xs',
                    onClick: () => onOpenDetail(r.runId)
                  }, '🔍')
                )
              ))
            )
          )
        )
  );
}

// ═══════════════════════════════════════════════════════════════
//  RUN DETAIL VIEW (Equity Curve + Trade Log)
// ═══════════════════════════════════════════════════════════════

function RunDetailView({ runId, onBack }) {
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [tradeFilter, setTradeFilter] = React.useState('all'); // all | winners | losers
  const [tSortCol, setTSortCol] = React.useState(null);
  const [tSortDir, setTSortDir] = React.useState('asc');
  const chartRef = React.useRef(null);
  const chartInstance = React.useRef(null);

  React.useEffect(() => {
    (async () => {
      setLoading(true);
      try {
        const d = await API.get('/api/backtest/' + runId);
        setData(d);
      } catch (e) { console.error(e); }
      setLoading(false);
    })();
  }, [runId]);

  // Equity curve chart
  React.useEffect(() => {
    if (!data?.equityCurve || !chartRef.current) return;
    if (chartInstance.current) chartInstance.current.destroy();

    const ctx = chartRef.current.getContext('2d');
    const curve = data.equityCurve;
    chartInstance.current = new Chart(ctx, {
      type: 'line',
      data: {
        labels: curve.map(p => '#' + p.tradeNumber),
        datasets: [
          {
            label: 'Cumulative PnL (points)',
            data: curve.map(p => p.cumulativePnlPoints),
            borderColor: '#1565C0',
            backgroundColor: 'rgba(21,101,192,0.08)',
            fill: true,
            tension: 0.3,
            pointRadius: 2,
          },
          {
            label: 'Drawdown (pts)',
            data: curve.map(p => -p.drawdownPct),
            borderColor: '#DC2626',
            backgroundColor: 'rgba(220,38,38,0.06)',
            fill: true,
            tension: 0.3,
            pointRadius: 0,
            yAxisID: 'dd',
          }
        ]
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        interaction: { intersect: false, mode: 'index' },
        plugins: { legend: { position: 'top' } },
        scales: {
          y: { title: { display: true, text: 'PnL (points)' } },
          dd: { position: 'right', title: { display: true, text: 'Drawdown' },
            grid: { drawOnChartArea: false } }
        }
      }
    });

    return () => { if (chartInstance.current) chartInstance.current.destroy(); };
  }, [data]);

  if (loading) return React.createElement('div', { className: 'bt-loading' }, '⏳ Loading run details...');
  if (!data) return React.createElement('div', { className: 'bt-empty' }, '❌ Run not found.');

  const trades = Array.isArray(data.trades) ? data.trades : [];
  const filteredTrades = trades.filter(t => {
    if (tradeFilter === 'winners') return t.pnlPoints > 0;
    if (tradeFilter === 'losers') return t.pnlPoints < 0;
    return true;
  });

  function tToggleSort(col) {
    if (tSortCol === col) setTSortDir(d => d === 'asc' ? 'desc' : 'asc');
    else { setTSortCol(col); setTSortDir('desc'); }
  }
  const tSortIcon = (col) => tSortCol === col ? (tSortDir === 'asc' ? ' ▲' : ' ▼') : '';
  let sortedTrades = filteredTrades;
  if (tSortCol) {
    sortedTrades = [...filteredTrades].sort((a, b) => {
      let va = a[tSortCol] ?? 0, vb = b[tSortCol] ?? 0;
      if (typeof va === 'string') return tSortDir === 'asc' ? va.localeCompare(vb) : vb.localeCompare(va);
      return tSortDir === 'asc' ? (va > vb ? 1 : -1) : (va < vb ? 1 : -1);
    });
  }

  return React.createElement('div', null,
    React.createElement('button', { className: 'bt-btn bt-btn-sm bt-mb-4', onClick: onBack }, '← Back to History'),

    // Summary cards
    React.createElement('div', { className: 'bt-stats-grid' },
      BtStatCard('Total Trades', data.totalTrades ?? 0, '📊'),
      BtStatCard('Win Rate', (data.winRate ?? 0).toFixed(1) + '%', '🎯', (data.winRate ?? 0) >= 50 ? 'success' : 'danger'),
      BtStatCard('PnL (points)', (data.totalPnlPoints ?? 0).toFixed(1), '💰', (data.totalPnlPoints ?? 0) >= 0 ? 'success' : 'danger'),
      BtStatCard('PnL (₹)', '₹' + Math.round(data.totalPnlRupees ?? 0).toLocaleString(), '💵', (data.totalPnlRupees ?? 0) >= 0 ? 'success' : 'danger'),
      BtStatCard('Max Drawdown', (data.maxDrawdownPct ?? 0).toFixed(1) + ' pts', '📉', 'danger'),
      BtStatCard('Sharpe Ratio', (data.sharpeRatio ?? 0).toFixed(2), '📐', (data.sharpeRatio ?? 0) >= 1 ? 'success' : (data.sharpeRatio ?? 0) >= 0.5 ? 'warning' : 'danger'),
      BtStatCard('Profit Factor', (data.profitFactor ?? 0) > 999 ? '∞' : (data.profitFactor ?? 0).toFixed(2), '⚖️', (data.profitFactor ?? 0) >= 1.5 ? 'success' : 'warning'),
      BtStatCard('Trading Days', data.tradingDays ?? 0, '📅'),
    ),

    // Equity curve
    React.createElement('div', { className: 'bt-card bt-mb-4' },
      React.createElement('h3', { className: 'bt-card-title' }, '📈 Equity Curve'),
      React.createElement('div', { style: { height: '320px' } },
        React.createElement('canvas', { ref: chartRef })
      )
    ),

    // Trade log
    React.createElement('div', { className: 'bt-card' },
      React.createElement('div', { className: 'bt-card-header' },
        React.createElement('h3', { className: 'bt-card-title' }, '📝 Trade Log (' + filteredTrades.length + ')'),
        React.createElement('div', { className: 'bt-trade-filters' },
          ['all', 'winners', 'losers'].map(f =>
            React.createElement('button', {
              key: f,
              className: 'bt-btn bt-btn-xs' + (tradeFilter === f ? ' active' : ''),
              onClick: () => setTradeFilter(f)
            }, f === 'all' ? 'All' : f === 'winners' ? '✅ Winners' : '❌ Losers')
          )
        )
      ),
      React.createElement('div', { className: 'bt-table-wrap' },
        React.createElement('table', { className: 'bt-table bt-table-sm' },
          React.createElement('thead', null,
            React.createElement('tr', null,
              [['#','tradeNumber'],['Date','tradeDate'],['Type',null],['Entry','entryPrice'],['Exit','exitPrice'],['PnL','pnlPoints'],['PnL%','pnlPct'],['Reason',null],['Conf','onnxConfidence']].map(([h,col]) =>
                React.createElement('th', {
                  key: h,
                  className: (col ? 'bt-sortable ' : '') + (h === '#' || h === 'Date' || h === 'Type' || h === 'Reason' ? '' : 'bt-right'),
                  onClick: col ? () => tToggleSort(col) : undefined,
                  style: col ? { cursor: 'pointer', userSelect: 'none' } : {}
                }, h + (col ? tSortIcon(col) : ''))
              )
            )
          ),
          React.createElement('tbody', null,
            sortedTrades.map(t => React.createElement('tr', { key: t.tradeNumber },
              React.createElement('td', { className: 'bt-mono' }, t.tradeNumber),
              React.createElement('td', { className: 'bt-mono' }, String(t.tradeDate ?? '')),
              React.createElement('td', null, t.optionType === 'CE'
                ? React.createElement('span', { className: 'bt-badge bt-badge-green' }, 'CE')
                : React.createElement('span', { className: 'bt-badge bt-badge-red' }, 'PE')),
              React.createElement('td', { className: 'bt-mono bt-right' }, (t.entryPrice ?? 0).toFixed(2)),
              React.createElement('td', { className: 'bt-mono bt-right' }, (t.exitPrice ?? 0).toFixed(2)),
              React.createElement('td', { className: 'bt-right ' + ((t.pnlPoints ?? 0) >= 0 ? 'bt-green' : 'bt-red') },
                ((t.pnlPoints ?? 0) >= 0 ? '+' : '') + (t.pnlPoints ?? 0).toFixed(2)),
              React.createElement('td', { className: 'bt-right ' + ((t.pnlPct ?? 0) >= 0 ? 'bt-green' : 'bt-red') },
                (t.pnlPct ?? 0).toFixed(1) + '%'),
              React.createElement('td', { className: 'bt-mono bt-muted bt-text-xs' }, String(t.exitReason ?? '')),
              React.createElement('td', { className: 'bt-mono bt-right' }, t.onnxConfidence ? (t.onnxConfidence * 100).toFixed(0) + '%' : '—')
            ))
          )
        )
      )
    )
  );
}

// ═══════════════════════════════════════════════════════════════
//  GRID SEARCH TAB
// ═══════════════════════════════════════════════════════════════

function GridSearchTab({ onOpenDetail }) {
  const [form, setForm] = React.useState({
    strategy: 'Phantom', root: 'NIFTY',
    startDate: '', endDate: '',
    slMin: 8, slMax: 16, slStep: 4,
    tpMin: 8, tpMax: 20, tpStep: 4,
    trailMin: 5, trailMax: 10, trailStep: 5,
    confMin: 50, confMax: 70, confStep: 10,
    maxOrders: '2,3',
  });
  const [submitting, setSubmitting] = React.useState(false);
  const [batchId, setBatchId] = React.useState(() => localStorage.getItem('grid_batchId') || null);
  const [batchPrefix, setBatchPrefix] = React.useState(() => localStorage.getItem('grid_batchPrefix') || null);
  const [results, setResults] = React.useState([]);
  const [polling, setPolling] = React.useState(false);
  const [pastBatches, setPastBatches] = React.useState([]);
  const toast = useToast();

  // Load past batches on mount + auto-load last viewed batch
  React.useEffect(() => {
    API.get('/api/backtest/grid-search/batches').then(setPastBatches).catch(() => {});
    // Resume last session
    const savedId = localStorage.getItem('grid_batchId');
    const savedPrefix = localStorage.getItem('grid_batchPrefix');
    if (savedId || savedPrefix) setPolling(true);
  }, []);

  // Persist current selection
  React.useEffect(() => {
    if (batchId) localStorage.setItem('grid_batchId', batchId); else localStorage.removeItem('grid_batchId');
    if (batchPrefix) localStorage.setItem('grid_batchPrefix', batchPrefix); else localStorage.removeItem('grid_batchPrefix');
  }, [batchId, batchPrefix]);

  function loadBatchByPrefix(prefix) {
    if (!prefix) return;
    setBatchPrefix(prefix);
    setBatchId(null);
    setResults([]);
    setPolling(true);
  }

  function upd(k, v) { setForm(prev => ({ ...prev, [k]: v })); }

  // Calculate combo count
  const comboCount = React.useMemo(() => {
    const count = (min, max, step) => step > 0 ? Math.floor((max - min) / step) + 1 : 1;
    const sl = count(form.slMin, form.slMax, form.slStep);
    const tp = count(form.tpMin, form.tpMax, form.tpStep);
    const trail = count(form.trailMin, form.trailMax, form.trailStep);
    const conf = form.strategy !== 'Phantom' ? count(form.confMin, form.confMax, form.confStep) : 1;
    const maxOrd = (form.maxOrders || '3').split(',').length;
    return sl * tp * trail * conf * maxOrd;
  }, [form]);

  async function submit() {
    if (!form.startDate || !form.endDate) { toast('Dates required', 'error'); return; }
    if (comboCount > 500) { toast('Too many combinations (' + comboCount + '). Max is 500.', 'error'); return; }
    setSubmitting(true);
    try {
      const body = {
        strategy: form.strategy, root: form.root,
        startDate: form.startDate, endDate: form.endDate,
        catastropheSlPctRange: form.slMin / 100 + ',' + form.slMax / 100 + ',' + form.slStep / 100,
        takeProfitPctRange: form.tpMin / 100 + ',' + form.tpMax / 100 + ',' + form.tpStep / 100,
        trailingFloorPctRange: form.trailMin / 100 + ',' + form.trailMax / 100 + ',' + form.trailStep / 100,
        onnxMinConfidenceRange: form.strategy !== 'Phantom'
          ? form.confMin / 100 + ',' + form.confMax / 100 + ',' + form.confStep / 100 : null,
        maxOrdersPerDayValues: form.maxOrders.split(',').map(v => parseInt(v.trim())).filter(v => !isNaN(v)),
      };
      const res = await API.post('/api/backtest/grid-search', body);
      setBatchId(res.batchId);
      setBatchPrefix(null);
      setPolling(true);
      toast('Grid search queued: ' + res.totalRuns + ' runs', 'success');
      // Refresh batch list
      API.get('/api/backtest/grid-search/batches').then(setPastBatches).catch(() => {});
    } catch (e) { toast('Failed: ' + e.message, 'error'); }
    setSubmitting(false);
  }

  // Poll/load grid search results
  React.useEffect(() => {
    if (!polling || (!batchId && !batchPrefix)) return;
    let active = true;
    const url = batchId
      ? '/api/backtest/grid-search/' + batchId
      : '/api/backtest/grid-search/by-prefix/' + encodeURIComponent(batchPrefix);
    const poll = async () => {
      try {
        const data = await API.get(url);
        if (active) {
          setResults(data);
          const pending = data.filter(r => r.status === 'PENDING' || r.status === 'RUNNING');
          if (pending.length === 0) setPolling(false);
        }
      } catch (e) { console.error(e); }
    };
    poll();
    const iv = setInterval(poll, 5000);
    return () => { active = false; clearInterval(iv); };
  }, [batchId, batchPrefix, polling]);

  const completed = results.filter(r => r.status === 'COMPLETED');
  const pendingCount = results.filter(r => r.status === 'PENDING' || r.status === 'RUNNING').length;

  const [gSortCol, setGSortCol] = React.useState('totalPnlPoints');
  const [gSortDir, setGSortDir] = React.useState('desc');
  function gToggleSort(col) {
    if (gSortCol === col) setGSortDir(d => d === 'asc' ? 'desc' : 'asc');
    else { setGSortCol(col); setGSortDir('desc'); }
  }
  const gSortIcon = (col) => gSortCol === col ? (gSortDir === 'asc' ? ' ▲' : ' ▼') : '';
  const sortedGrid = React.useMemo(() => {
    return [...completed].sort((a, b) => {
      const va = a[gSortCol] ?? 0, vb = b[gSortCol] ?? 0;
      return gSortDir === 'asc' ? (va > vb ? 1 : -1) : (va < vb ? 1 : -1);
    });
  }, [completed, gSortCol, gSortDir]);

  return React.createElement('div', null,
    // Config form
    React.createElement('div', { className: 'bt-card bt-mb-4' },
      React.createElement('h2', { className: 'bt-card-title' }, '🔬 Parameter Optimizer — Find Best Strategy Settings'),
      React.createElement('p', { className: 'bt-subtitle bt-mb-2' },
        'Sweep parameter ranges to find optimal SL/TP/Trailing/Confidence combinations. All permutations are tested against historical data.'
      ),
      React.createElement('p', { className: 'bt-subtitle bt-mb-4', style: { fontSize: '0.85em', opacity: 0.8 } },
        '📌 Recommended: SL 8–16% (step 4) · TP 8–20% (step 4) · Trail 5–10% (step 5) · Confidence 50–70% (step 10) · 2–3 orders/day. ',
        React.createElement('strong', null, comboCount + ' combinations'),
        comboCount > 500 ? React.createElement('span', { className: 'bt-red' }, ' ⚠️ Exceeds limit (500)') : null
      ),

      React.createElement('div', { className: 'bt-form-grid' },
        FormSelect('Strategy', form.strategy, v => upd('strategy', v), ['Phantom', 'OnnxWithPhantomGate', 'OnnxRaw']),
        FormSelect('Root Symbol', form.root, v => upd('root', v), ['NIFTY', 'SENSEX']),
        FormInput('Start Date', 'date', form.startDate, v => upd('startDate', v)),
        FormInput('End Date', 'date', form.endDate, v => upd('endDate', v)),
      ),

      React.createElement('h3', { className: 'bt-section-title' }, 'Parameter Ranges (%)'),
      React.createElement('div', { className: 'bt-range-grid' },
        RangeRow('Stop Loss %', 'sl', form, upd),
        RangeRow('Take Profit %', 'tp', form, upd),
        RangeRow('Trailing Floor %', 'trail', form, upd),
        form.strategy !== 'Phantom' && RangeRow('ONNX Confidence %', 'conf', form, upd),
      ),

      React.createElement('div', { className: 'bt-form-grid' },
        FormInput('Max Orders/Day (comma-sep)', 'text', form.maxOrders, v => upd('maxOrders', v)),
      ),

      React.createElement('div', { className: 'bt-form-actions' },
        React.createElement('button', {
          className: 'bt-btn bt-btn-primary',
          onClick: submit,
          disabled: submitting || comboCount > 500
        }, submitting ? '⏳ Queuing...' : '🔬 Launch Grid Search (' + comboCount + ' runs)')
      )
    ),

    // Past Batches selector
    pastBatches.length > 0 && React.createElement('div', { className: 'bt-card bt-mb-4' },
      React.createElement('h3', { className: 'bt-card-title' }, '📂 Previous Grid Searches'),
      React.createElement('div', { className: 'bt-table-wrap' },
        React.createElement('table', { className: 'bt-table bt-table-sm' },
          React.createElement('thead', null,
            React.createElement('tr', null,
              ['Strategy', 'Root', 'Dates', 'Runs', 'Done', 'Last Activity', ''].map(h =>
                React.createElement('th', { key: h }, h))
            )
          ),
          React.createElement('tbody', null,
            pastBatches.map(b => React.createElement('tr', {
              key: b.batchPrefix,
              style: { background: (batchPrefix === b.batchPrefix) ? 'var(--primary-light)' : '' }
            },
              React.createElement('td', null, b.strategy),
              React.createElement('td', null, b.root),
              React.createElement('td', { className: 'bt-mono' }, b.startDate + ' → ' + b.endDate),
              React.createElement('td', { className: 'bt-right' }, b.totalRuns),
              React.createElement('td', { className: 'bt-right' }, b.completedRuns + '/' + b.totalRuns),
              React.createElement('td', { className: 'bt-mono bt-muted' }, b.lastActivity ? new Date(b.lastActivity).toLocaleString() : '—'),
              React.createElement('td', null,
                React.createElement('button', {
                  className: 'bt-btn bt-btn-xs',
                  onClick: () => loadBatchByPrefix(b.batchPrefix)
                }, '📊 View')
              )
            ))
          )
        )
      )
    ),

    // Results
    (batchId || batchPrefix) && results.length > 0 && React.createElement('div', { className: 'bt-card' },
      React.createElement('div', { className: 'bt-card-header' },
        React.createElement('h2', { className: 'bt-card-title' },
          '📊 Grid Search Results',
          polling && React.createElement('span', { className: 'bt-badge bt-badge-blue bt-ml-2' },
            '⏳ ' + pendingCount + ' running')
        ),
        React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '12px' } },
          React.createElement('span', { className: 'bt-muted' },
            completed.length + '/' + results.length + ' completed'),
          completed.length > 0 && React.createElement('button', {
            className: 'bt-btn bt-btn-sm',
            onClick: () => {
              const hdrs = ['Rank','SL%','TP%','Trail%','Conf%','MaxOrd','Trades','Win%','PnL_Pts','PnL_Rs','DD','Sharpe','PF'];
              const rows = sortedGrid.map((r, i) => {
                const p = parseGridLabel(r.label);
                return [i+1, p.sl, p.tp, p.trail, p.conf, p.max, r.totalTrades, r.winRate.toFixed(1),
                  r.totalPnlPoints.toFixed(1), Math.round(r.totalPnlRupees), r.maxDrawdownPct.toFixed(1),
                  r.sharpeRatio.toFixed(2), r.profitFactor > 999 ? 'Inf' : r.profitFactor.toFixed(2)];
              });
              exportToCsv('grid-search-' + (batchId || batchPrefix || 'export') + '.csv', hdrs, rows);
            }
          }, '📥 Export CSV')
        )
      ),

      // Progress bar
      results.length > 0 && React.createElement('div', { className: 'bt-progress-bar' },
        React.createElement('div', {
          className: 'bt-progress-fill',
          style: { width: (completed.length / results.length * 100) + '%' }
        })
      ),

      // Heatmap-style results table
      completed.length > 0 && React.createElement('div', { className: 'bt-table-wrap' },
        React.createElement('table', { className: 'bt-table bt-table-sm' },
          React.createElement('thead', null,
            React.createElement('tr', null,
              [['#',null],['SL%',null],['TP%',null],['Trail%',null],['Conf%',null],['Max',null],['Trades','totalTrades'],['Win%','winRate'],['PnL','totalPnlPoints'],['Sharpe','sharpeRatio'],['PF','profitFactor'],['',null]].map(([h,col]) =>
                React.createElement('th', {
                  key: h,
                  className: (col ? 'bt-sortable ' : '') + (h === '#' || h === '' || !col ? '' : 'bt-right'),
                  onClick: col ? () => gToggleSort(col) : undefined,
                  style: col ? { cursor: 'pointer', userSelect: 'none' } : {}
                }, h + (col ? gSortIcon(col) : ''))
              )
            )
          ),
          React.createElement('tbody', null,
            sortedGrid.map((r, i) => {
              const params = parseGridLabel(r.label);
              const bg = getHeatColor(r.totalPnlPoints, completed);
              return React.createElement('tr', { key: r.runId, style: { background: bg } },
                React.createElement('td', { className: 'bt-mono' }, i === 0 ? '🥇' : i === 1 ? '🥈' : i === 2 ? '🥉' : (i + 1)),
                React.createElement('td', { className: 'bt-mono' }, params.sl),
                React.createElement('td', { className: 'bt-mono' }, params.tp),
                React.createElement('td', { className: 'bt-mono' }, params.trail),
                React.createElement('td', { className: 'bt-mono' }, params.conf),
                React.createElement('td', { className: 'bt-mono' }, params.max),
                React.createElement('td', { className: 'bt-right' }, r.totalTrades),
                React.createElement('td', { className: 'bt-right' }, r.winRate.toFixed(1) + '%'),
                React.createElement('td', { className: 'bt-right ' + (r.totalPnlPoints >= 0 ? 'bt-green' : 'bt-red') },
                  (r.totalPnlPoints >= 0 ? '+' : '') + r.totalPnlPoints.toFixed(1)),
                React.createElement('td', { className: 'bt-right' }, r.sharpeRatio.toFixed(2)),
                React.createElement('td', { className: 'bt-right' }, r.profitFactor > 999 ? '∞' : r.profitFactor.toFixed(2)),
                React.createElement('td', null,
                  React.createElement('button', {
                    className: 'bt-btn bt-btn-xs',
                    onClick: () => onOpenDetail(r.runId)
                  }, '🔍')
                )
              );
            })
          )
        )
      )
    )
  );
}

// ═══════════════════════════════════════════════════════════════
//  SHARED HELPERS
// ═══════════════════════════════════════════════════════════════

function FormInput(label, type, value, onChange, extra = {}) {
  return React.createElement('div', { className: 'bt-field' },
    React.createElement('label', { className: 'bt-label' }, label),
    React.createElement('input', {
      className: 'bt-input',
      type, value,
      onChange: e => onChange(e.target.value),
      ...extra
    })
  );
}

function FormSelect(label, value, onChange, options) {
  return React.createElement('div', { className: 'bt-field' },
    React.createElement('label', { className: 'bt-label' }, label),
    React.createElement('select', {
      className: 'bt-input',
      value,
      onChange: e => onChange(e.target.value)
    }, options.map(o => React.createElement('option', { key: o, value: o }, o)))
  );
}

function RangeRow(label, prefix, form, upd) {
  return React.createElement('div', { className: 'bt-range-row' },
    React.createElement('span', { className: 'bt-range-label' }, label),
    React.createElement('input', { className: 'bt-input bt-input-sm', type: 'number', placeholder: 'Min',
      value: form[prefix + 'Min'], onChange: e => upd(prefix + 'Min', parseFloat(e.target.value) || 0) }),
    React.createElement('span', { className: 'bt-range-sep' }, '→'),
    React.createElement('input', { className: 'bt-input bt-input-sm', type: 'number', placeholder: 'Max',
      value: form[prefix + 'Max'], onChange: e => upd(prefix + 'Max', parseFloat(e.target.value) || 0) }),
    React.createElement('span', { className: 'bt-range-sep' }, 'step'),
    React.createElement('input', { className: 'bt-input bt-input-sm', type: 'number', placeholder: 'Step',
      value: form[prefix + 'Step'], onChange: e => upd(prefix + 'Step', parseFloat(e.target.value) || 1) }),
  );
}

function BtStatCard(label, value, icon, variant) {
  const cls = 'bt-stat' + (variant ? ' bt-stat-' + variant : '');
  return React.createElement('div', { className: cls },
    React.createElement('div', { className: 'bt-stat-icon' }, icon),
    React.createElement('div', null,
      React.createElement('div', { className: 'bt-stat-value' }, value),
      React.createElement('div', { className: 'bt-stat-label' }, label)
    )
  );
}

function StatusBadge(status) {
  const map = { PENDING: 'bt-badge-gray', RUNNING: 'bt-badge-blue', COMPLETED: 'bt-badge-green', FAILED: 'bt-badge-red' };
  const icons = { PENDING: '⏳', RUNNING: '⚡', COMPLETED: '✅', FAILED: '❌' };
  return React.createElement('span', { className: 'bt-badge ' + (map[status] || '') }, icons[status] || '', ' ', status);
}

function StrategyBadge(s) {
  const map = { Phantom: 'bt-badge-purple', OnnxWithPhantomGate: 'bt-badge-blue', OnnxRaw: 'bt-badge-teal' };
  const short = { Phantom: 'Phantom', OnnxWithPhantomGate: 'ONNX+Gate', OnnxRaw: 'ONNX Raw' };
  return React.createElement('span', { className: 'bt-badge ' + (map[s] || '') }, short[s] || s);
}

function parseGridLabel(label) {
  if (!label) return { sl: '—', tp: '—', trail: '—', conf: '—', max: '—' };
  const m = label.match(/SL=([^,]+),TP=([^,]+),Trail=([^,]+),Conf=([^,]+),Max=(\d+)/);
  if (!m) return { sl: '—', tp: '—', trail: '—', conf: '—', max: '—' };
  return { sl: m[1].replace('%',''), tp: m[2].replace('%',''), trail: m[3].replace('%',''), conf: m[4].replace('%',''), max: m[5] };
}

function getHeatColor(pnl, allResults) {
  if (allResults.length === 0) return 'transparent';
  const pnls = allResults.map(r => r.totalPnlPoints);
  const max = Math.max(...pnls);
  const min = Math.min(...pnls);
  if (max === min) return 'transparent';
  const norm = (pnl - min) / (max - min); // 0 = worst, 1 = best
  if (pnl >= 0) return 'rgba(22,163,74,' + (0.04 + norm * 0.12) + ')';
  return 'rgba(220,38,38,' + (0.04 + (1 - norm) * 0.12) + ')';
}
