// ============ Seed data ============
const TICKERS = ['NVDA','AAPL','TSLA','MSFT','AMD','META','SPY','QQQ','COIN','BTCUSD','ETHUSD','GOOGL','NFLX','AMZN','CRWD','PLTR','ARM','SMCI','MSTR','SHOP'];
const STRATS = ['ORB Breakout','VWAP Reclaim','Gap & Go','Trend Pullback','Mean Reversion','Earnings Fade','News Catalyst'];
const MISTAKES = ['No stop','Oversized','Chased','Exit early','FOMO entry','Held loser','Ignored plan'];
const EMOTIONS = ['fearful','neutral','confident','fomo'];

// Deterministic PRNG so data is stable across reloads
function mulberry32(seed){let t=seed>>>0;return function(){t+=0x6D2B79F5;let r=Math.imul(t^(t>>>15),1|t);r^=r+Math.imul(r^(r>>>7),61|r);return((r^(r>>>14))>>>0)/4294967296}}
const rng = mulberry32(7);
const pick = (arr) => arr[Math.floor(rng()*arr.length)];
const rnd = (a,b) => a + rng()*(b-a);
const rint = (a,b) => Math.floor(rnd(a,b+1));

// Generate trades over ~3 months
const TRADES = (() => {
  const out = [];
  const start = new Date(2026, 0, 15); // Jan 15 2026
  const today = new Date(2026, 3, 21);  // Apr 21 2026
  let equity = 25000;
  let id = 1;
  for (let d = new Date(start); d <= today; d.setDate(d.getDate()+1)) {
    if (d.getDay() === 0 || d.getDay() === 6) continue; // weekdays only
    const tradesToday = rng() < 0.2 ? 0 : rint(1,4);
    for (let i=0;i<tradesToday;i++){
      const ticker = pick(TICKERS);
      const dir = rng() < 0.62 ? 'long' : 'short';
      const entry = +(rnd(50,520)).toFixed(2);
      const move = rnd(-0.04, 0.05);
      const exit = +(entry * (1 + move * (dir==='long'?1:-1))).toFixed(2);
      const size = rint(50, 800);
      const commission = +(rng()*6 + 1).toFixed(2);
      const pnl = +(((dir==='long' ? exit-entry : entry-exit) * size) - commission).toFixed(2);
      const risk = Math.max(30, Math.abs(entry*0.012*size));
      const r = +(pnl/risk).toFixed(2);
      const hour = rint(9,15);
      const minute = rint(0,59);
      const dt = new Date(d); dt.setHours(hour,minute,0,0);
      equity += pnl;
      out.push({
        id: id++,
        ticker,
        dir,
        size,
        entry,
        exit,
        pnl,
        r,
        risk: +risk.toFixed(2),
        commission,
        strategy: pick(STRATS),
        tags: [pick(STRATS)].concat(rng()<0.4?[pick(['A+ setup','B setup','High vol','Low vol','Morning','Afternoon'])]:[]),
        status: 'closed',
        outcome: pnl > 5 ? 'win' : pnl < -5 ? 'loss' : 'be',
        emotion: pick(EMOTIONS),
        grade: pick(['A','A','B','B','B','C','C','D']),
        mistake: rng()<0.3 ? pick(MISTAKES) : null,
        date: new Date(dt),
        equityAfter: +equity.toFixed(2),
      });
    }
  }
  // a couple open trades
  for (let i=0;i<3;i++){
    out.push({
      id: id++, ticker: pick(TICKERS), dir: rng()<0.5?'long':'short', size: rint(100,500),
      entry:+(rnd(80,400)).toFixed(2), exit:null, pnl:0, r:0, risk:0, commission:0,
      strategy: pick(STRATS), tags:[pick(STRATS)], status:'open', outcome:'open',
      emotion: pick(EMOTIONS), grade:null, mistake:null, date: new Date(today.getTime() - rint(0,3)*86400000),
      equityAfter: equity,
    });
  }
  return out.sort((a,b)=>b.date-a.date);
})();

// KPIs
const STATS = (() => {
  const closed = TRADES.filter(t=>t.status==='closed');
  const wins = closed.filter(t=>t.pnl>0);
  const losses = closed.filter(t=>t.pnl<0);
  const netPnl = closed.reduce((s,t)=>s+t.pnl,0);
  const grossWin = wins.reduce((s,t)=>s+t.pnl,0);
  const grossLoss = Math.abs(losses.reduce((s,t)=>s+t.pnl,0));
  return {
    netPnl: +netPnl.toFixed(2),
    winRate: closed.length ? wins.length/closed.length : 0,
    profitFactor: grossLoss ? +(grossWin/grossLoss).toFixed(2) : 0,
    avgR: closed.length ? +(closed.reduce((s,t)=>s+t.r,0)/closed.length).toFixed(2) : 0,
    trades: closed.length,
    wins: wins.length,
    losses: losses.length,
    bestDay: Math.max(...closed.map(t=>t.pnl)),
    worstDay: Math.min(...closed.map(t=>t.pnl)),
  };
})();

// Equity curve (daily aggregate)
const EQUITY = (() => {
  const byDay = new Map();
  TRADES.filter(t=>t.status==='closed').sort((a,b)=>a.date-b.date).forEach(t=>{
    const k = t.date.toISOString().slice(0,10);
    byDay.set(k, (byDay.get(k)||0) + t.pnl);
  });
  const arr = []; let eq = 25000;
  for (const [k,v] of [...byDay].sort()) { eq += v; arr.push({ date: k, equity: +eq.toFixed(2), pnl: +v.toFixed(2) }); }
  return arr;
})();

// Strategies playbook
const PLAYBOOK = STRATS.map(name => {
  const ts = TRADES.filter(t=>t.status==='closed' && t.strategy===name);
  const wins = ts.filter(t=>t.pnl>0).length;
  const avgR = ts.length ? +(ts.reduce((s,t)=>s+t.r,0)/ts.length).toFixed(2) : 0;
  const net = +ts.reduce((s,t)=>s+t.pnl,0).toFixed(2);
  return {
    name, trades: ts.length, wins, winRate: ts.length ? wins/ts.length : 0,
    avgR, net, lastUsed: ts[0] ? ts[0].date : null,
    description: {
      'ORB Breakout': 'Open range breakout on first 15m candle, volume > 1.5× avg, trend align.',
      'VWAP Reclaim': 'Long after price loses VWAP, consolidates, and reclaims on volume.',
      'Gap & Go': 'High-relative-volume gap-ups continuing premarket range.',
      'Trend Pullback': 'Pullback to 9EMA in established trend, bounce with volume confirm.',
      'Mean Reversion': 'Overextended moves, RSI extremes, fade into prior structure.',
      'Earnings Fade': 'Fade exaggerated gap reaction post-earnings during first 30m.',
      'News Catalyst': 'Breaking news momentum, entry after first consolidation.',
    }[name],
  };
});

// Calendar aggregation
const CAL = (() => {
  const m = new Map();
  TRADES.filter(t=>t.status==='closed').forEach(t=>{
    const k = t.date.toISOString().slice(0,10);
    const cur = m.get(k) || { pnl: 0, count: 0 };
    cur.pnl += t.pnl; cur.count += 1; m.set(k, cur);
  });
  return m;
})();

// helpers
const fmtMoney = (n, signed=true) => {
  const abs = Math.abs(n);
  const s = abs.toLocaleString('en-US',{minimumFractionDigits:2,maximumFractionDigits:2});
  const sign = n > 0 ? '+' : n < 0 ? '−' : '';
  return (signed ? sign : '') + '$' + s;
};
const fmtShort = (n) => {
  const s = n < 0 ? '−' : n > 0 ? '+' : '';
  const a = Math.abs(n);
  if (a >= 1000) return s + '$' + (a/1000).toFixed(1) + 'k';
  return s + '$' + a.toFixed(0);
};
const fmtPct = (n) => (n*100).toFixed(1) + '%';
const fmtDate = (d) => d.toLocaleDateString('en-US',{month:'short',day:'numeric'});
const fmtTime = (d) => d.toLocaleTimeString('en-US',{hour:'numeric',minute:'2-digit'});

Object.assign(window, { TRADES, STATS, EQUITY, PLAYBOOK, CAL, STRATS, MISTAKES, EMOTIONS, TICKERS, fmtMoney, fmtShort, fmtPct, fmtDate, fmtTime });
