/home/devscfvi/AblePro/js/analytics_ablePro.js
// ============================================================
// ANALYTICS — AblePro Bootstrap 5 UI override
// Keeps all chart init logic from analytics.js
// Adds TraderVue-style detailed stats, win/loss day comparison,
// ApexCharts equity curve, day-of-week heatmap, and more.
// ============================================================

// ── Helper: resolve P&L for any trade ────────────────────────
function _pnl(t) {
  if (t.actual_pnl != null && t.actual_pnl !== '') return parseFloat(t.actual_pnl);
  return t.status === 'win' ? parseFloat(t.profit_amount || 0) : -parseFloat(t.loss_amount || 0);
}

// ── Helper: format currency ───────────────────────────────────
function _fc(v) {
  const abs = Math.abs(parseFloat(v) || 0);
  const sign = parseFloat(v) >= 0 ? '+' : '-';
  return sign + '$' + abs.toFixed(2);
}

// ── Helper: colour class ──────────────────────────────────────
function _cc(v) { return parseFloat(v) >= 0 ? 'text-success' : 'text-danger'; }

// ── Main render override ──────────────────────────────────────
window.renderAnalytics = function() {
  if (!state.analytics) {
    return `<div class="d-flex align-items-center justify-content-center py-5">
      <div class="spinner-border text-primary"></div>
      <span class="ms-3 text-muted">Loading analytics…</span>
    </div>`;
  }

  const hasData = state.trades && state.trades.length > 0;
  if (!hasData) {
    return `<div class="card"><div class="card-body text-center py-5">
      <i class="ti ti-chart-bar f-48 d-block mb-3 text-muted opacity-25"></i>
      <h5 class="text-muted">No trades yet</h5>
      <p class="text-muted mb-4">Import or log trades to unlock analytics</p>
      <button class="btn btn-primary" onclick="navigateTo('calculator')">
        <i class="ti ti-plus me-2"></i>Add First Trade
      </button>
    </div></div>`;
  }

  const tabs = [
    { id:'overview',   icon:'ti-layout-dashboard', label:'Overview'   },
    { id:'reports',    icon:'ti-report-analytics',  label:'Reports'    },
    { id:'days-times', icon:'ti-clock',              label:'Days/Times' },
    { id:'strategy',   icon:'ti-target',             label:'Strategy'   },
    { id:'psychology', icon:'ti-brain',              label:'Psychology' },
  ];

  return `
  <!-- Tab nav -->
  <div class="card mb-4">
    <div class="card-body py-2 px-3">
      <ul class="nav nav-tabs border-0 gap-1" id="analytics-tabs">
        ${tabs.map((t, i) => `
        <li class="nav-item">
          <button class="nav-link ${i===0?'active':''} d-flex align-items-center gap-2 px-3 py-2 f-13 fw-semibold"
            onclick="switchAnalyticsTabAP('${t.id}', this)">
            <i class="ti ${t.icon} f-15"></i>
            <span class="d-none d-md-inline">${t.label}</span>
          </button>
        </li>`).join('')}
      </ul>
    </div>
  </div>

  <!-- Tab content -->
  <div id="analytics-content"></div>`;
};

// ── Tab switcher ──────────────────────────────────────────────
window.switchAnalyticsTabAP = function(tab, btnEl) {
  document.querySelectorAll('#analytics-tabs .nav-link').forEach(b => b.classList.remove('active'));
  if (btnEl) btnEl.classList.add('active');

  const container = document.getElementById('analytics-content');
  if (!container) return;

  switch(tab) {
    case 'overview':   container.innerHTML = renderOverviewTabAP();   setTimeout(initOverviewChartsAP, 120);   break;
    case 'reports':    container.innerHTML = renderReportsTabAP();    setTimeout(initReportsChartsAP, 120);    break;
    case 'days-times': container.innerHTML = renderDaysTimesTabAP();  setTimeout(initDaysTimesChartsAP, 120);  break;
    case 'strategy':   container.innerHTML = renderCategoryTab();     setTimeout(initCategoryCharts, 120);     break;
    case 'psychology': container.innerHTML = renderPsychologyTab();   setTimeout(initPsychologyCharts, 120);   break;
    default:           container.innerHTML = renderOverviewTabAP();   setTimeout(initOverviewChartsAP, 120);   break;
  }
};

// ── initAnalyticsCharts override ──────────────────────────────
window.initAnalyticsCharts = function() {
  // Boot on the Overview tab
  const firstBtn = document.querySelector('#analytics-tabs .nav-link');
  switchAnalyticsTabAP('overview', firstBtn);
};

// ─────────────────────────────────────────────────────────────
// OVERVIEW TAB
// ─────────────────────────────────────────────────────────────
function renderOverviewTabAP() {
  const stats    = state.stats    || {};
  const analytics = state.analytics || {};
  const trades   = state.trades   || [];
  const closed   = trades.filter(t => t.status==='win'||t.status==='loss');
  const withPnl  = closed.map(t => ({...t, _pnl: _pnl(t)}));

  const totalPnl    = withPnl.reduce((s,t)=>s+t._pnl,0);
  const wins        = withPnl.filter(t=>t._pnl>0);
  const losses      = withPnl.filter(t=>t._pnl<0);
  const profitFactor= losses.length>0 ? (wins.reduce((s,t)=>s+t._pnl,0)/Math.abs(losses.reduce((s,t)=>s+t._pnl,0))).toFixed(2) : wins.length>0?'∞':'0.00';
  const expectancy  = withPnl.length>0 ? totalPnl/withPnl.length : 0;
  const winRate     = withPnl.length>0 ? Math.round(wins.length/withPnl.length*100) : 0;
  const streaks     = analytics.streaks || {};

  const kpis = [
    { label:'Net P&L',       val:_fc(totalPnl),      cls:_cc(totalPnl), icon:'ti-currency-dollar', bg:'bg-light-'+(totalPnl>=0?'success':'danger') },
    { label:'Win Rate',      val:winRate+'%',         cls:_cc(winRate-50), icon:'ti-chart-pie', bg:'bg-light-'+(winRate>=50?'success':'danger') },
    { label:'Profit Factor', val:profitFactor,        cls:_cc(parseFloat(profitFactor)-1), icon:'ti-trending-up', bg:'bg-light-primary' },
    { label:'Expectancy',    val:_fc(expectancy),     cls:_cc(expectancy), icon:'ti-target', bg:'bg-light-'+(expectancy>=0?'success':'danger') },
    { label:'Total Trades',  val:withPnl.length,      cls:'', icon:'ti-list-details', bg:'bg-light-primary' },
    { label:'Avg R:R',       val:(()=>{ const rrs=withPnl.filter(t=>parseFloat(t.reward_risk_ratio||0)>0).map(t=>parseFloat(t.reward_risk_ratio)); return rrs.length>0?'1:'+(rrs.reduce((a,b)=>a+b,0)/rrs.length).toFixed(2):'—'; })(), cls:'text-primary', icon:'ti-scale', bg:'bg-light-primary' },
  ];

  return `
  <!-- KPI row -->
  <div class="row g-3 mb-4">
    ${kpis.map(k=>`
    <div class="col-6 col-md-4 col-lg-2">
      <div class="card mb-0 h-100">
        <div class="card-body py-3 px-3">
          <div class="d-flex align-items-center gap-2 mb-2">
            <span class="avtar avtar-xs ${k.bg} rounded"><i class="ti ${k.icon} f-15"></i></span>
            <span class="text-muted f-11">${k.label}</span>
          </div>
          <div class="fw-bold f-20 ${k.cls}">${k.val}</div>
        </div>
      </div>
    </div>`).join('')}
  </div>

  <div class="row g-4 mb-4">
    <!-- Equity curve -->
    <div class="col-lg-8">
      <div class="card h-100">
        <div class="card-header d-flex align-items-center justify-content-between py-3">
          <h6 class="mb-0 fw-semibold">Equity Curve</h6>
          <span class="badge ${totalPnl>=0?'bg-light-success text-success':'bg-light-danger text-danger'}">${_fc(totalPnl)}</span>
        </div>
        <div class="card-body p-2">
          <div id="apex-equity" style="height:220px"></div>
        </div>
      </div>
    </div>
    <!-- Streaks -->
    <div class="col-lg-4">
      <div class="card h-100">
        <div class="card-header py-3"><h6 class="mb-0 fw-semibold">Streaks</h6></div>
        <div class="card-body">
          <div class="row g-3">
            <div class="col-6">
              <div class="p-3 rounded-3 text-center bg-light-success">
                <div class="f-28 fw-black text-success">${streaks.current_win_streak||0}</div>
                <div class="f-11 text-muted">Current Win</div>
                <div class="f-11 text-success mt-1">Best: ${streaks.max_win_streak||0}</div>
              </div>
            </div>
            <div class="col-6">
              <div class="p-3 rounded-3 text-center bg-light-danger">
                <div class="f-28 fw-black text-danger">${streaks.current_loss_streak||0}</div>
                <div class="f-11 text-muted">Current Loss</div>
                <div class="f-11 text-danger mt-1">Worst: ${streaks.max_loss_streak||0}</div>
              </div>
            </div>
            <div class="col-12">
              <div class="p-3 rounded-3" style="background:#f8fafc">
                <div class="d-flex justify-content-between mb-2">
                  <span class="f-12 text-muted">Win / Loss / Open</span>
                  <span class="f-12 fw-semibold">${wins.length} / ${losses.length} / ${trades.filter(t=>!t.status||t.status==='pending').length}</span>
                </div>
                <div style="height:8px;background:#e2e8f0;border-radius:4px;overflow:hidden">
                  <div style="height:100%;width:${winRate}%;background:linear-gradient(90deg,#10b981,#34d399);border-radius:4px"></div>
                </div>
                <div class="d-flex justify-content-between mt-1">
                  <span class="f-10 text-success">${winRate}% wins</span>
                  <span class="f-10 text-danger">${100-winRate}% losses</span>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <!-- Performance by coin -->
  <div class="card">
    <div class="card-header py-3"><h6 class="mb-0 fw-semibold">Performance by Symbol</h6></div>
    <div class="card-body p-0">
      <div class="table-responsive">
        <table class="table table-hover mb-0 f-13">
          <thead class="table-light">
            <tr><th>Symbol</th><th class="text-end">Trades</th><th class="text-end">Win Rate</th><th class="text-end">Net P&L</th><th class="text-end">Avg R:R</th></tr>
          </thead>
          <tbody>
            ${(analytics.byCoin||[]).slice(0,10).map(c=>`
            <tr>
              <td class="fw-semibold">${c.coin}</td>
              <td class="text-end">${c.total||c.total_trades||0}</td>
              <td class="text-end ${parseFloat(c.win_rate||0)>=50?'text-success':'text-danger'}">${parseFloat(c.win_rate||0).toFixed(1)}%</td>
              <td class="text-end fw-semibold ${_cc(c.net_pnl)}">${_fc(c.net_pnl)}</td>
              <td class="text-end text-primary">—</td>
            </tr>`).join('')||'<tr><td colspan="5" class="text-center text-muted py-3">No data</td></tr>'}
          </tbody>
        </table>
      </div>
    </div>
  </div>`;
}

function initOverviewChartsAP() {
  const trades  = state.trades || [];
  const closed  = trades.filter(t=>t.status==='win'||t.status==='loss');
  const withPnl = closed.map(t=>({...t,_pnl:_pnl(t)}));

  // Build cumulative by trade date
  const sorted = [...withPnl].sort((a,b)=>{
    const da = (a.trade_date||a.created_at||'').substring(0,10);
    const db = (b.trade_date||b.created_at||'').substring(0,10);
    return da.localeCompare(db);
  });

  let cum=0;
  const series = sorted.map(t=>{ cum+=t._pnl; return parseFloat(cum.toFixed(2)); });
  const labels = sorted.map(t=>(t.trade_date||t.created_at||'').substring(0,10));
  const finalVal = series[series.length-1]||0;
  const lineColor = finalVal>=0?'#10b981':'#ef4444';

  if (window.ApexCharts && document.getElementById('apex-equity')) {
    if (window._apexEquity) { try{window._apexEquity.destroy();}catch(e){} }
    window._apexEquity = new ApexCharts(document.getElementById('apex-equity'), {
      chart:{ type:'area', height:220, toolbar:{show:false}, sparkline:{enabled:false}, animations:{enabled:true,speed:600} },
      series:[{ name:'Equity', data:series }],
      xaxis:{ categories:labels, labels:{show:labels.length<40, style:{colors:'#94a3b8',fontSize:'10px'}}, axisBorder:{show:false}, axisTicks:{show:false} },
      yaxis:{ labels:{ style:{colors:'#94a3b8',fontSize:'11px'}, formatter:v=>'$'+v.toFixed(0) } },
      stroke:{ curve:'smooth', width:2.5, colors:[lineColor] },
      fill:{ type:'gradient', gradient:{ shadeIntensity:1, opacityFrom:.35, opacityTo:0, stops:[0,100], colorStops:[{offset:0,color:lineColor,opacity:.35},{offset:100,color:lineColor,opacity:0}] } },
      tooltip:{ theme:'light', y:{formatter:v=>(v>=0?'+':'')+`$${v.toFixed(2)}`} },
      grid:{ borderColor:'#f1f5f9', strokeDashArray:3 },
      colors:[lineColor],
    });
    window._apexEquity.render();
  }
}

// ─────────────────────────────────────────────────────────────
// REPORTS TAB — TraderVue-style full stats table
// ─────────────────────────────────────────────────────────────
function renderReportsTabAP() {
  const trades  = state.trades || [];
  const closed  = trades.filter(t=>t.status==='win'||t.status==='loss');
  if (closed.length===0) return `<div class="card"><div class="card-body text-center py-5 text-muted">Close some trades to see reports.</div></div>`;

  const withPnl = closed.map(t=>({...t,_pnl:_pnl(t)}));

  // Core stats
  const netPnl      = withPnl.reduce((s,t)=>s+t._pnl,0);
  const wins        = withPnl.filter(t=>t._pnl>0);
  const losses      = withPnl.filter(t=>t._pnl<=0);
  const totalWinAmt = wins.reduce((s,t)=>s+t._pnl,0);
  const totalLossAmt= Math.abs(losses.reduce((s,t)=>s+t._pnl,0));
  const profitFactor= totalLossAmt>0?(totalWinAmt/totalLossAmt).toFixed(2):totalWinAmt>0?'∞':'0.00';
  const winRate     = withPnl.length>0?Math.round(wins.length/withPnl.length*100):0;
  const avgWin      = wins.length>0?totalWinAmt/wins.length:0;
  const avgLoss     = losses.length>0?totalLossAmt/losses.length:0;
  const expectancy  = withPnl.length>0?netPnl/withPnl.length:0;
  const largestGain = wins.length>0?Math.max(...wins.map(t=>t._pnl)):0;
  const largestLoss = losses.length>0?Math.max(...losses.map(t=>Math.abs(t._pnl))):0;

  // Standard deviation
  const mean = expectancy;
  const variance = withPnl.length>1?withPnl.reduce((s,t)=>s+Math.pow(t._pnl-mean,2),0)/(withPnl.length-1):0;
  const stdDev = Math.sqrt(variance);

  // Daily breakdown — win days vs loss days
  const dailyMap = {};
  withPnl.forEach(t=>{
    const day = (t.trade_date||t.created_at||'').substring(0,10);
    if(!day||day==='') return;
    if(!dailyMap[day]) dailyMap[day]={pnl:0,trades:0,wins:0};
    dailyMap[day].pnl+=t._pnl; dailyMap[day].trades++; if(t._pnl>0) dailyMap[day].wins++;
  });
  const dailyArr = Object.values(dailyMap);
  const winDays  = dailyArr.filter(d=>d.pnl>0);
  const lossDays = dailyArr.filter(d=>d.pnl<=0);
  const avgDailyPnl = dailyArr.length>0?netPnl/dailyArr.length:0;

  // Kelly %
  const p = winRate/100;
  const b = avgLoss>0?avgWin/avgLoss:0;
  const kelly = b>0?Math.max(0,((p*b-(1-p))/b)*100).toFixed(1):'—';

  // Max consecutive
  let maxWinStreak=0, maxLossStreak=0, curW=0, curL=0;
  withPnl.forEach(t=>{ if(t._pnl>0){curW++;curL=0;maxWinStreak=Math.max(maxWinStreak,curW);}else{curL++;curW=0;maxLossStreak=Math.max(maxLossStreak,curL);} });

  // Cumulative for drawdown
  let cum=0, peak=0, maxDD=0;
  withPnl.forEach(t=>{ cum+=t._pnl; if(cum>peak)peak=cum; const dd=peak-cum; if(dd>maxDD)maxDD=dd; });

  const statRow = (label, val, cls='') => `
    <tr>
      <td class="f-13 text-muted py-2">${label}</td>
      <td class="f-13 fw-semibold py-2 text-end ${cls}">${val}</td>
    </tr>`;

  // Best/worst trades
  const sorted  = [...withPnl].sort((a,b)=>b._pnl-a._pnl);
  const best5   = sorted.slice(0,5);
  const worst5  = sorted.slice(-5).reverse();
  const fmtDate = d => d?(new Date((d||'').substring(0,10)+'T00:00:00')).toLocaleDateString('en-US',{month:'short',day:'numeric',year:'2-digit'}):'—';

  return `
  <!-- Charts row -->
  <div class="row g-4 mb-4">
    <div class="col-md-8">
      <div class="card h-100">
        <div class="card-header d-flex align-items-center justify-content-between py-3">
          <h6 class="mb-0 fw-semibold">Daily P&L</h6>
          <div class="d-flex gap-2">
            <span class="badge bg-light-success text-success">${winDays.length} green days</span>
            <span class="badge bg-light-danger text-danger">${lossDays.length} red days</span>
          </div>
        </div>
        <div class="card-body p-2"><div id="apex-daily" style="height:220px"></div></div>
      </div>
    </div>
    <div class="col-md-4">
      <div class="card h-100">
        <div class="card-header py-3"><h6 class="mb-0 fw-semibold">Cumulative P&L</h6></div>
        <div class="card-body p-2"><div id="apex-cum" style="height:220px"></div></div>
      </div>
    </div>
  </div>

  <!-- Full stats table — TraderVue style -->
  <div class="card mb-4">
    <div class="card-header d-flex align-items-center gap-2 py-3">
      <i class="ti ti-report-analytics text-primary f-18"></i>
      <h6 class="mb-0 fw-semibold">Detailed Statistics</h6>
    </div>
    <div class="card-body p-0">
      <div class="row g-0">
        <!-- Column 1 -->
        <div class="col-md-4 border-end">
          <div class="px-3 py-2 border-bottom bg-light">
            <span class="f-11 fw-bold text-muted text-uppercase tracking-wider">P&L Summary</span>
          </div>
          <table class="table table-sm mb-0">
            <tbody>
              ${statRow('Total Gain / Loss', _fc(netPnl), _cc(netPnl))}
              ${statRow('Profit Factor', profitFactor, _cc(parseFloat(profitFactor)-1))}
              ${statRow('Expectancy (per trade)', _fc(expectancy), _cc(expectancy))}
              ${statRow('Largest Gain', '+$'+largestGain.toFixed(2), 'text-success')}
              ${statRow('Largest Loss', '-$'+largestLoss.toFixed(2), 'text-danger')}
              ${statRow('Max Drawdown', '-$'+maxDD.toFixed(2), 'text-danger')}
              ${statRow('Std Deviation', '$'+stdDev.toFixed(2))}
            </tbody>
          </table>
          <div class="px-3 py-2 border-bottom border-top bg-light mt-1">
            <span class="f-11 fw-bold text-muted text-uppercase">Winning Days</span>
          </div>
          <table class="table table-sm mb-0">
            <tbody>
              ${statRow('Total Win Days', winDays.length, 'text-success')}
              ${statRow('Avg Win Day P&L', winDays.length>0?_fc(winDays.reduce((s,d)=>s+d.pnl,0)/winDays.length):'—', 'text-success')}
              ${statRow('Best Day', '+$'+Math.max(0,...winDays.map(d=>d.pnl)).toFixed(2), 'text-success')}
            </tbody>
          </table>
        </div>

        <!-- Column 2 -->
        <div class="col-md-4 border-end">
          <div class="px-3 py-2 border-bottom bg-light">
            <span class="f-11 fw-bold text-muted text-uppercase">Win / Loss Breakdown</span>
          </div>
          <table class="table table-sm mb-0">
            <tbody>
              ${statRow('Win Rate', winRate+'%', _cc(winRate-50))}
              ${statRow('Winning Trades', wins.length+' ('+winRate+'%)', 'text-success')}
              ${statRow('Losing Trades', losses.length+' ('+(100-winRate)+'%)', 'text-danger')}
              ${statRow('Avg Winning Trade', '+$'+avgWin.toFixed(2), 'text-success')}
              ${statRow('Avg Losing Trade', '-$'+avgLoss.toFixed(2), 'text-danger')}
              ${statRow('Avg Trade (all)', _fc(expectancy), _cc(expectancy))}
              ${statRow('Total Trades', withPnl.length)}
            </tbody>
          </table>
          <div class="px-3 py-2 border-bottom border-top bg-light mt-1">
            <span class="f-11 fw-bold text-muted text-uppercase">Losing Days</span>
          </div>
          <table class="table table-sm mb-0">
            <tbody>
              ${statRow('Total Loss Days', lossDays.length, 'text-danger')}
              ${statRow('Avg Loss Day P&L', lossDays.length>0?_fc(lossDays.reduce((s,d)=>s+d.pnl,0)/lossDays.length):'—', 'text-danger')}
              ${statRow('Worst Day', '-$'+Math.abs(Math.min(0,...lossDays.map(d=>d.pnl))).toFixed(2), 'text-danger')}
            </tbody>
          </table>
        </div>

        <!-- Column 3 -->
        <div class="col-md-4">
          <div class="px-3 py-2 border-bottom bg-light">
            <span class="f-11 fw-bold text-muted text-uppercase">Advanced Metrics</span>
          </div>
          <table class="table table-sm mb-0">
            <tbody>
              ${statRow('Avg Daily Gain/Loss', _fc(avgDailyPnl), _cc(avgDailyPnl))}
              ${statRow('Trading Days', dailyArr.length)}
              ${statRow('Max Consec. Wins', maxWinStreak, 'text-success')}
              ${statRow('Max Consec. Losses', maxLossStreak, 'text-danger')}
              ${statRow('Kelly Percentage', kelly!=='—'?kelly+'%':'—')}
              ${statRow('Total Fees', '$'+(withPnl.reduce((s,t)=>s+parseFloat(t.fees||0),0)).toFixed(2), 'text-muted')}
              ${(()=>{ const rrs=(state.trades||[]).filter(t=>t.status==='win'||t.status==='loss').filter(t=>parseFloat(t.reward_risk_ratio||0)>0).map(t=>parseFloat(t.reward_risk_ratio)); const avgRR=rrs.length>0?(rrs.reduce((a,b)=>a+b,0)/rrs.length).toFixed(2):'—'; return statRow('Avg R:R', rrs.length>0?'1:'+avgRR:'—', 'text-primary'); })()}
            </tbody>
          </table>
          <div class="px-3 py-2 border-bottom border-top bg-light mt-1">
            <span class="f-11 fw-bold text-muted text-uppercase">Win / Loss Day Ratio</span>
          </div>
          <div class="px-3 py-3">
            <div class="d-flex align-items-center gap-2 mb-1">
              <span class="f-12 text-muted" style="width:80px">Win Days</span>
              <div class="flex-fill" style="background:#f1f5f9;border-radius:4px;height:10px">
                <div style="background:#10b981;height:10px;border-radius:4px;width:${dailyArr.length>0?Math.round(winDays.length/dailyArr.length*100):0}%"></div>
              </div>
              <span class="f-12 text-success fw-semibold">${dailyArr.length>0?Math.round(winDays.length/dailyArr.length*100):0}%</span>
            </div>
            <div class="d-flex align-items-center gap-2">
              <span class="f-12 text-muted" style="width:80px">Loss Days</span>
              <div class="flex-fill" style="background:#f1f5f9;border-radius:4px;height:10px">
                <div style="background:#ef4444;height:10px;border-radius:4px;width:${dailyArr.length>0?Math.round(lossDays.length/dailyArr.length*100):0}%"></div>
              </div>
              <span class="f-12 text-danger fw-semibold">${dailyArr.length>0?Math.round(lossDays.length/dailyArr.length*100):0}%</span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <!-- Best & Worst Trades -->
  <div class="row g-4">
    <div class="col-md-6">
      <div class="card">
        <div class="card-header py-3 d-flex align-items-center gap-2">
          <i class="ti ti-trophy text-warning"></i>
          <h6 class="mb-0 fw-semibold">Best Trades</h6>
        </div>
        <div class="card-body p-0">
          <table class="table table-hover mb-0 f-13">
            <thead class="table-light"><tr><th>Symbol</th><th>Date</th><th class="text-end">P&L</th></tr></thead>
            <tbody>
              ${best5.map(t=>`<tr style="cursor:pointer" onclick="openTradeDetailModal(window._tradeRegistry[${t.id}])">
                <td class="fw-semibold">${t.coin||'—'}</td>
                <td class="text-muted">${fmtDate(t.trade_date||t.created_at)}</td>
                <td class="text-end fw-bold text-success">${_fc(t._pnl)}</td>
              </tr>`).join('')}
            </tbody>
          </table>
        </div>
      </div>
    </div>
    <div class="col-md-6">
      <div class="card">
        <div class="card-header py-3 d-flex align-items-center gap-2">
          <i class="ti ti-alert-triangle text-danger"></i>
          <h6 class="mb-0 fw-semibold">Worst Trades</h6>
        </div>
        <div class="card-body p-0">
          <table class="table table-hover mb-0 f-13">
            <thead class="table-light"><tr><th>Symbol</th><th>Date</th><th class="text-end">P&L</th></tr></thead>
            <tbody>
              ${worst5.map(t=>`<tr style="cursor:pointer" onclick="openTradeDetailModal(window._tradeRegistry[${t.id}])">
                <td class="fw-semibold">${t.coin||'—'}</td>
                <td class="text-muted">${fmtDate(t.trade_date||t.created_at)}</td>
                <td class="text-end fw-bold text-danger">${_fc(t._pnl)}</td>
              </tr>`).join('')}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  </div>`;
}

function initReportsChartsAP() {
  const trades  = state.trades||[];
  const closed  = trades.filter(t=>t.status==='win'||t.status==='loss');
  if(!closed.length) return;
  const withPnl = closed.map(t=>({...t,_pnl:_pnl(t)}));

  // Daily map using trade_date
  const dailyMap={};
  withPnl.forEach(t=>{
    const day=(t.trade_date||t.created_at||'').substring(0,10);
    if(!day) return;
    dailyMap[day]=(dailyMap[day]||0)+t._pnl;
  });
  const dailyEntries=Object.entries(dailyMap).sort((a,b)=>a[0].localeCompare(b[0]));
  const dailyLabels=dailyEntries.map(([d])=>d);
  const dailyValues=dailyEntries.map(([,v])=>+v.toFixed(2));
  let cum=0;
  const cumValues=dailyValues.map(v=>+(cum+=v).toFixed(2));
  const finalVal=cumValues[cumValues.length-1]||0;

  if(!window.ApexCharts) return;

  // Daily P&L
  if(document.getElementById('apex-daily')) {
    if(window._apexDaily){try{window._apexDaily.destroy();}catch(e){}}
    window._apexDaily=new ApexCharts(document.getElementById('apex-daily'),{
      chart:{type:'bar',height:220,toolbar:{show:false}},
      series:[{name:'Daily P&L',data:dailyValues}],
      xaxis:{categories:dailyLabels,labels:{style:{colors:'#94a3b8',fontSize:'10px'},rotate:-45},axisBorder:{show:false}},
      yaxis:{labels:{style:{colors:'#94a3b8',fontSize:'11px'},formatter:v=>'$'+v.toFixed(0)}},
      colors:[function({value}){return value>=0?'#10b981':'#ef4444';}],
      plotOptions:{bar:{borderRadius:4,columnWidth:'60%'}},
      tooltip:{theme:'light',y:{formatter:v=>(v>=0?'+':'')+`$${v.toFixed(2)}`}},
      grid:{borderColor:'#f1f5f9',strokeDashArray:3},
    });
    window._apexDaily.render();
  }

  // Cumulative
  if(document.getElementById('apex-cum')) {
    if(window._apexCum){try{window._apexCum.destroy();}catch(e){}}
    const lc=finalVal>=0?'#10b981':'#ef4444';
    window._apexCum=new ApexCharts(document.getElementById('apex-cum'),{
      chart:{type:'area',height:220,toolbar:{show:false}},
      series:[{name:'Cumulative',data:cumValues}],
      xaxis:{categories:dailyLabels,labels:{show:false},axisBorder:{show:false}},
      yaxis:{labels:{style:{colors:'#94a3b8',fontSize:'11px'},formatter:v=>'$'+v.toFixed(0)}},
      stroke:{curve:'smooth',width:2,colors:[lc]},
      fill:{type:'gradient',gradient:{shadeIntensity:1,opacityFrom:.3,opacityTo:0,stops:[0,100]}},
      colors:[lc],
      tooltip:{theme:'light',y:{formatter:v=>(v>=0?'+':'')+`$${v.toFixed(2)}`}},
      grid:{borderColor:'#f1f5f9',strokeDashArray:3},
    });
    window._apexCum.render();
  }
}

// ─────────────────────────────────────────────────────────────
// DAYS / TIMES TAB
// ─────────────────────────────────────────────────────────────
function renderDaysTimesTabAP() {
  return `
  <div class="row g-4">
    <div class="col-md-6">
      <div class="card"><div class="card-header py-3"><h6 class="mb-0 fw-semibold">P&L by Day of Week</h6></div>
        <div class="card-body p-2"><div id="apex-dow-pnl" style="height:240px"></div></div></div>
    </div>
    <div class="col-md-6">
      <div class="card"><div class="card-header py-3"><h6 class="mb-0 fw-semibold">Win Rate by Day of Week</h6></div>
        <div class="card-body p-2"><div id="apex-dow-wr" style="height:240px"></div></div></div>
    </div>
    <div class="col-md-6">
      <div class="card"><div class="card-header py-3"><h6 class="mb-0 fw-semibold">P&L by Hour of Day</h6></div>
        <div class="card-body p-2"><div id="apex-hour-pnl" style="height:260px"></div></div></div>
    </div>
    <div class="col-md-6">
      <div class="card"><div class="card-header py-3"><h6 class="mb-0 fw-semibold">Trade Count by Hour</h6></div>
        <div class="card-body p-2"><div id="apex-hour-count" style="height:260px"></div></div></div>
    </div>
  </div>`;
}

function initDaysTimesChartsAP() {
  const trades  = state.trades||[];
  const closed  = trades.filter(t=>t.status==='win'||t.status==='loss');
  if(!closed.length||!window.ApexCharts) return;
  const withPnl = closed.map(t=>({...t,_pnl:_pnl(t)}));

  // Day of week
  const dowNames=['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
  const dowPnl  =Array(7).fill(0), dowCount=Array(7).fill(0), dowWins=Array(7).fill(0);
  withPnl.forEach(t=>{
    const raw=(t.trade_date||t.created_at||'').substring(0,10);
    if(!raw) return;
    const d=new Date(raw+'T00:00:00').getDay();
    dowPnl[d]+=t._pnl; dowCount[d]++; if(t._pnl>0) dowWins[d]++;
  });
  const dowWr=dowCount.map((c,i)=>c>0?Math.round(dowWins[i]/c*100):null);

  // DOW P&L bar
  if(document.getElementById('apex-dow-pnl')){
    if(window._apexDowPnl){try{window._apexDowPnl.destroy();}catch(e){}}
    window._apexDowPnl=new ApexCharts(document.getElementById('apex-dow-pnl'),{
      chart:{type:'bar',height:240,toolbar:{show:false}},
      series:[{name:'P&L',data:dowPnl.map(v=>+v.toFixed(2))}],
      xaxis:{categories:dowNames,labels:{style:{colors:'#94a3b8'}}},
      yaxis:{labels:{style:{colors:'#94a3b8'},formatter:v=>'$'+v.toFixed(0)}},
      colors:[function({value}){return value>=0?'#10b981':'#ef4444';}],
      plotOptions:{bar:{borderRadius:5}},
      tooltip:{theme:'light',y:{formatter:v=>(v>=0?'+':'')+`$${v.toFixed(2)}`}},
      grid:{borderColor:'#f1f5f9',strokeDashArray:3},
    });
    window._apexDowPnl.render();
  }

  // DOW win rate
  if(document.getElementById('apex-dow-wr')){
    if(window._apexDowWr){try{window._apexDowWr.destroy();}catch(e){}}
    window._apexDowWr=new ApexCharts(document.getElementById('apex-dow-wr'),{
      chart:{type:'bar',height:240,toolbar:{show:false}},
      series:[{name:'Win Rate',data:dowWr}],
      xaxis:{categories:dowNames,labels:{style:{colors:'#94a3b8'}}},
      yaxis:{min:0,max:100,labels:{style:{colors:'#94a3b8'},formatter:v=>v+'%'}},
      colors:[function({value}){return value===null?'#cbd5e1':value>=50?'#10b981':'#ef4444';}],
      plotOptions:{bar:{borderRadius:5}},
      tooltip:{theme:'light',y:{formatter:v=>v!==null?v+'% win rate':'No trades'}},
      grid:{borderColor:'#f1f5f9',strokeDashArray:3},
    });
    window._apexDowWr.render();
  }

  // Hour stats
  const hourPnl=Array(24).fill(0), hourCount=Array(24).fill(0);
  withPnl.forEach(t=>{
    const raw=(t.created_at||'');
    const hMatch=raw.match(/T?(\d{2}):/)||raw.match(/\s(\d{2}):/);
    if(!hMatch) return;
    const h=parseInt(hMatch[1]);
    hourPnl[h]+=t._pnl; hourCount[h]++;
  });
  const activeHours=hourPnl.map((v,i)=>({h:i,pnl:v,count:hourCount[i]})).filter(x=>x.count>0);

  if(document.getElementById('apex-hour-pnl')&&activeHours.length>0){
    if(window._apexHourPnl){try{window._apexHourPnl.destroy();}catch(e){}}
    window._apexHourPnl=new ApexCharts(document.getElementById('apex-hour-pnl'),{
      chart:{type:'bar',height:260,toolbar:{show:false}},
      series:[{name:'P&L',data:activeHours.map(x=>+x.pnl.toFixed(2))}],
      xaxis:{categories:activeHours.map(x=>x.h+':00'),labels:{style:{colors:'#94a3b8',fontSize:'10px'}}},
      yaxis:{labels:{style:{colors:'#94a3b8'},formatter:v=>'$'+v.toFixed(0)}},
      colors:[function({value}){return value>=0?'#10b981':'#ef4444';}],
      plotOptions:{bar:{borderRadius:4,horizontal:true}},
      tooltip:{theme:'light',y:{formatter:v=>(v>=0?'+':'')+`$${v.toFixed(2)}`}},
      grid:{borderColor:'#f1f5f9',strokeDashArray:3},
    });
    window._apexHourPnl.render();
  }

  if(document.getElementById('apex-hour-count')&&activeHours.length>0){
    if(window._apexHourCount){try{window._apexHourCount.destroy();}catch(e){}}
    window._apexHourCount=new ApexCharts(document.getElementById('apex-hour-count'),{
      chart:{type:'bar',height:260,toolbar:{show:false}},
      series:[{name:'Trades',data:activeHours.map(x=>x.count)}],
      xaxis:{categories:activeHours.map(x=>x.h+':00'),labels:{style:{colors:'#94a3b8',fontSize:'10px'}}},
      yaxis:{labels:{style:{colors:'#94a3b8'},formatter:v=>Math.round(v)+''}},
      colors:['#4680FF'],
      plotOptions:{bar:{borderRadius:4,horizontal:true}},
      tooltip:{theme:'light'},
      grid:{borderColor:'#f1f5f9',strokeDashArray:3},
    });
    window._apexHourCount.render();
  }
}

// ── switchAnalyticsTab compatibility shim ─────────────────────
// (some buttons in analytics.js still call switchAnalyticsTab)
window.switchAnalyticsTab = function(tab) {
  const map = {overview:'overview',category:'strategy',psychology:'psychology',timing:'days-times',reports:'reports'};
  const apTab = map[tab]||tab;
  const btn = [...document.querySelectorAll('#analytics-tabs .nav-link')]
    .find(b=>b.getAttribute('onclick')&&b.getAttribute('onclick').includes(`'${apTab}'`));
  switchAnalyticsTabAP(apTab, btn||null);
};