// ============ Shared components (nav, KPIs, charts, tables) ============
const { useState, useMemo, useEffect, useRef } = React;

const NAV_LINKS = [
  { id: 'dashboard', key: 'nav_dashboard' },
  { id: 'trades', key: 'nav_trades' },
  { id: 'analytics', key: 'nav_analytics' },
  { id: 'calendar', key: 'nav_calendar' },
  { id: 'journal', key: 'nav_journal' },
  { id: 'playbook', key: 'nav_playbook' },
];

// ----- Profile Dropdown -----
const ProfileDropdown = ({ setRoute, lang, setLang }) => {
  const { t } = useI18n();
  const { user, signOut } = useAuth();
  const [open, setOpen] = useState(false);
  const wrapRef = useRef(null);

  const initials = useMemo(() => {
    const name = (user?.name || 'User').trim();
    const parts = name.split(/\s+/);
    if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase();
    return name.slice(0,2).toUpperCase();
  }, [user?.name]);

  useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false); };
    const onKey = (e) => { if (e.key==='Escape') setOpen(false); };
    document.addEventListener('click', onDoc);
    document.addEventListener('keydown', onKey);
    return () => { document.removeEventListener('click', onDoc); document.removeEventListener('keydown', onKey); };
  }, [open]);

  const go = (route, subtab) => {
    if (subtab) { try { localStorage.setItem('edgebook:settings_tab', subtab); } catch {} }
    setRoute(route); setOpen(false);
  };

  return (
    <div className="pf-wrap" ref={wrapRef}>
      <div className="avatar" onClick={(e)=>{e.stopPropagation();setOpen(o=>!o);}} style={{cursor:'pointer'}}>{initials}</div>
      {open && (
        <div className="pf-menu" onClick={e=>e.stopPropagation()}>
          <div className="pf-head">
            <div className="avatar" style={{width:36,height:36,fontSize:13}}>{initials}</div>
            <div style={{minWidth:0,flex:1}}>
              <div style={{fontWeight:500,fontSize:13.5,whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}}>{user?.name}</div>
              <div className="muted tiny" style={{whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}}>{user?.email}</div>
            </div>
          </div>
          <div style={{padding:'6px 0'}}>
            <div className="pf-item" onClick={()=>go('settings')}><Icon name="settings" size={14}/> {t('nav_settings')}</div>
            <div className="pf-item" onClick={()=>go('settings','accounts')}><Icon name="book" size={14}/> {t('st_accounts')}</div>
            <div className="pf-item" onClick={()=>go('settings','risk')}><Icon name="target" size={14}/> {t('st_risk')}</div>
            <div className="pf-item" onClick={()=>go('settings','goals')}><Icon name="star" size={14}/> {t('st_goals')}</div>
          </div>
          <div className="pf-sep"/>
          <div className="pf-item" style={{justifyContent:'space-between'}} onClick={e=>e.stopPropagation()}>
            <span style={{display:'flex',alignItems:'center',gap:10}}><Icon name="layers" size={14}/> {t('language')}</span>
            <div className="lang-pill">
              <button className={lang==='en'?'on':''} onClick={(e)=>{e.stopPropagation();setLang('en');}}>EN</button>
              <button className={lang==='mn'?'on':''} onClick={(e)=>{e.stopPropagation();setLang('mn');}}>MN</button>
            </div>
          </div>
          <div className="pf-sep"/>
          <div className="pf-item danger" onClick={()=>{setOpen(false);signOut();}}><Icon name="log-out" size={14}/> {t('sign_out')}</div>
        </div>
      )}
    </div>
  );
};

// ----- Top Nav -----
const TopNav = ({ route, setRoute, menuOpen, setMenuOpen, lang, setLang }) => {
  const { t } = useI18n();
  const [notifOpen, setNotifOpen] = useState(false);
  const notifWrapRef = useRef(null);
  const [readIds] = useState(() => {
    try { return new Set(JSON.parse(localStorage.getItem('edgebook:notif_read') || '["n4","n5","n6","n7","n8","n9","n10","n11"]')); }
    catch { return new Set(); }
  });
  // Recompute from storage on each render so badge updates after marking
  const [,force] = useState(0);
  useEffect(() => {
    if (!notifOpen) return;
    const onDoc = (e) => { if (notifWrapRef.current && !notifWrapRef.current.contains(e.target)) setNotifOpen(false); };
    const onKey = (e) => { if (e.key==='Escape') setNotifOpen(false); };
    document.addEventListener('click', onDoc);
    document.addEventListener('keydown', onKey);
    return () => { document.removeEventListener('click', onDoc); document.removeEventListener('keydown', onKey); };
  }, [notifOpen]);
  // Pick up read-state changes made inside the panel
  const unreadCount = (() => {
    try {
      const s = new Set(JSON.parse(localStorage.getItem('edgebook:notif_read') || '[]'));
      return (window.NOTIFS_SEED || []).filter(n => !s.has(n.id)).length;
    } catch { return 0; }
  })();

  return (
    <div className="nav">
      <button className="nav-burger" onClick={()=>setMenuOpen(!menuOpen)} aria-label="menu">
        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
      </button>
      <a className="nav-logo" onClick={()=>setRoute('dashboard')} style={{cursor:'pointer'}}>
        <span className="nav-logo-mark">E</span>
        <span>Edgebook</span>
      </a>
      <AccountSwitcher />
      <div className="nav-links">
        {NAV_LINKS.map(l => (
          <a key={l.id} className={'nav-link' + (route===l.id?' active':'')} onClick={()=>setRoute(l.id)} style={{cursor:'pointer'}}>{t(l.key)}</a>
        ))}
      </div>
      <div className="nav-right">
        <button className="log-btn" onClick={()=>setRoute('logtrade')}>
          <Icon name="plus" size={14} /> <span className="log-label">{t('nav_log_trade')}</span>
        </button>
        <div className="notif-wrap" ref={notifWrapRef}>
          <button className="icon-btn" title="Notifications" onClick={(e)=>{ e.stopPropagation(); setNotifOpen(o=>!o); force(x=>x+1); }}>
            <Icon name="bell" size={16} />
            {unreadCount > 0 && <span className="notif-badge">{unreadCount > 9 ? '9+' : unreadCount}</span>}
          </button>
          {notifOpen && <NotificationPanel onClose={()=>{ setNotifOpen(false); force(x=>x+1); }} setRoute={setRoute} />}
        </div>
        <ProfileDropdown setRoute={setRoute} lang={lang} setLang={setLang} />
      </div>
    </div>
  );
};

const MobileMenu = ({ route, setRoute }) => {
  const { t } = useI18n();
  return (
    <div className="mobile-menu open">
      {NAV_LINKS.map(l => (
        <a key={l.id} className={'nav-link' + (route===l.id?' active':'')} onClick={()=>setRoute(l.id)} style={{cursor:'pointer'}}>{t(l.key)}</a>
      ))}
      <a className={'nav-link' + (route==='settings'?' active':'')} onClick={()=>setRoute('settings')} style={{cursor:'pointer'}}>{t('nav_settings')}</a>
    </div>
  );
};

// ----- Page header -----
const PageHead = ({ title, sub, actions }) => (
  <div className="page-head">
    <div>
      <h1 className="page-title">{title}</h1>
      {sub && <div className="page-sub">{sub}</div>}
    </div>
    {actions && <div className="page-actions">{actions}</div>}
  </div>
);

// ----- Sparkline -----
const Sparkline = ({ data, color = '#10b981', width = 90, height = 40 }) => {
  if (!data || data.length < 2) return null;
  const min = Math.min(...data), max = Math.max(...data);
  const span = max - min || 1;
  const step = width / (data.length - 1);
  const pts = data.map((v,i)=>`${(i*step).toFixed(1)},${(height - ((v-min)/span)*height).toFixed(1)}`).join(' ');
  const areaPts = `0,${height} ${pts} ${width},${height}`;
  return (
    <svg width={width} height={height} className="kpi-spark">
      <polygon points={areaPts} fill={color} opacity="0.12" />
      <polyline points={pts} fill="none" stroke={color} strokeWidth="1.5" />
    </svg>
  );
};

const KPICard = ({ label, value, delta, deltaDir, spark, sparkColor, tooltip }) => (
  <div className="kpi">
    <div className="kpi-label" style={{display:'flex',alignItems:'center',gap:6}}>
      {label}
      {tooltip && (
        <span title={tooltip} style={{
          width:14,height:14,borderRadius:'50%',border:'1px solid #3a3a3a',
          display:'inline-grid',placeItems:'center',fontSize:9,fontWeight:600,
          color:'#6b6b6b',cursor:'help',lineHeight:1,
        }}>?</span>
      )}
    </div>
    <div className={'kpi-value ' + (deltaDir==='up'?'up':deltaDir==='down'?'dn':'')}>{value}</div>
    {delta && <div className={'kpi-delta ' + (deltaDir==='up'?'up':'dn')}>
      <Icon name={deltaDir==='up'?'arrow-up':'arrow-down'} size={11} />{delta}
    </div>}
    {spark && <Sparkline data={spark} color={sparkColor || (deltaDir==='up'?'#10b981':'#ef4444')} />}
  </div>
);

const KPIRow = () => {
  const { t, fmtCur } = useI18n();
  const { active, statsFor } = useAccounts();
  const stats = statsFor(active);
  const curve = active==='all' ? EQUITY : equityCurveFor(active);
  const eq = curve.map(e=>e.equity);
  const closedPool = active==='all' ? TRADES : TRADES.filter(x=>x.accountId===active);
  const closedSorted = closedPool.filter(x=>x.status==='closed').sort((a,b)=>a.date-b.date);

  const wr = []; {
    const step = Math.max(1,Math.floor(closedSorted.length/20));
    for (let i=10;i<=closedSorted.length;i+=step){
      const slice = closedSorted.slice(Math.max(0,i-20),i);
      wr.push(slice.filter(x=>x.pnl>0).length / Math.max(1,slice.length));
    }
  }
  const pf = eq.map((v,i)=> 1 + Math.sin(i/6)*0.2 + i*0.02);
  const r = []; {
    let running = 0;
    for (let i=0;i<closedSorted.length;i++){ running += closedSorted[i].r; r.push(running/(i+1)); }
  }

  // Expectancy per trade = (wr*avgWin) − (lr*avgLoss)
  const wins = closedSorted.filter(x=>x.pnl>0);
  const losses = closedSorted.filter(x=>x.pnl<0);
  const n = closedSorted.length || 1;
  const wrt = wins.length / n;
  const lrt = losses.length / n;
  const avgWin = wins.length ? wins.reduce((s,x)=>s+x.pnl,0)/wins.length : 0;
  const avgLoss = losses.length ? Math.abs(losses.reduce((s,x)=>s+x.pnl,0)/losses.length) : 0;
  const exp$ = +((wrt*avgWin) - (lrt*avgLoss)).toFixed(2);
  // Sparkline: running expectancy over last 20 trades window
  const expSpark = [];
  for (let i=5;i<=closedSorted.length;i++){
    const slice = closedSorted.slice(Math.max(0,i-20),i);
    const w = slice.filter(x=>x.pnl>0);
    const l = slice.filter(x=>x.pnl<0);
    const wrs = w.length/slice.length;
    const lrs = l.length/slice.length;
    const aw = w.length ? w.reduce((s,x)=>s+x.pnl,0)/w.length : 0;
    const al = l.length ? Math.abs(l.reduce((s,x)=>s+x.pnl,0)/l.length) : 0;
    expSpark.push((wrs*aw)-(lrs*al));
  }
  const expSign = exp$>=0?'+':'−';
  const expStr = expSign + '$' + Math.abs(exp$).toLocaleString('en-US',{minimumFractionDigits:2,maximumFractionDigits:2});

  return (
    <div className="kpi-grid">
      <KPICard label={t('kpi_net_pnl')} value={fmtCur(stats.netPnl)} delta="+12.4% MoM" deltaDir={stats.netPnl>=0?'up':'down'} spark={eq} />
      <KPICard label={t('kpi_win_rate')} value={fmtPct(stats.winRate)} delta="+2.1%" deltaDir="up" spark={wr} sparkColor="#3b82f6" />
      <KPICard label={t('kpi_profit_factor')} value={stats.profitFactor.toFixed(2)} delta="+0.18" deltaDir="up" spark={pf} sparkColor="#8b5cf6" />
      <KPICard label={t('kpi_avg_r')} value={(stats.avgR>=0?'+':'') + stats.avgR.toFixed(2) + 'R'} delta="+0.04R" deltaDir={stats.avgR>=0?'up':'down'} spark={r} sparkColor="#f59e0b" />
      <KPICard label={t('kpi_expectancy')} tooltip={t('kpi_expectancy_tip')} value={expStr} delta={(exp$>=0?'+':'−') + '$4.80 vs last 30d'} deltaDir={exp$>=0?'up':'down'} spark={expSpark} sparkColor="#ec4899" />
    </div>
  );
};

// ----- Equity Curve -----
const EquityCurve = ({ height = 280 }) => {
  const { active } = useAccounts();
  const wrapRef = useRef(null);
  const [w, setW] = useState(900);
  const [hover, setHover] = useState(null);

  useEffect(() => {
    const el = wrapRef.current; if (!el) return;
    const ro = new ResizeObserver(() => setW(el.clientWidth));
    ro.observe(el); setW(el.clientWidth);
    return () => ro.disconnect();
  }, []);

  const padL = 54, padR = 18, padT = 18, padB = 28;
  const data = active==='all' ? EQUITY : equityCurveFor(active);
  if (!data.length) return <div style={{padding:40,textAlign:'center'}} className="muted tiny">No trades in this account yet.</div>;
  const eqs = data.map(d=>d.equity);
  const min = Math.min(...eqs), max = Math.max(...eqs);
  const pad = (max-min)*0.05 || 100;
  const y0 = min - pad, y1 = max + pad;
  const innerW = Math.max(100, w - padL - padR);
  const innerH = height - padT - padB;
  const x = (i) => padL + (i/(data.length-1 || 1)) * innerW;
  const y = (v) => padT + (1 - (v-y0)/(y1-y0)) * innerH;

  const linePts = data.map((d,i)=>`${x(i).toFixed(1)},${y(d.equity).toFixed(1)}`).join(' ');
  const areaPts = `${padL},${padT+innerH} ${linePts} ${padL+innerW},${padT+innerH}`;

  const ticks = [];
  const tickCount = 5;
  const labelFor = (v) => '$' + (v/1000).toFixed(1) + 'k';
  for (let i=0;i<=tickCount;i++){
    const v = y0 + (y1-y0)*(i/tickCount);
    ticks.push({ v, y: y(v) });
  }
  const trend = data[data.length-1].equity - data[0].equity;

  const onMove = (e) => {
    const rect = e.currentTarget.getBoundingClientRect();
    const mx = e.clientX - rect.left;
    const idx = Math.round(((mx - padL)/innerW) * (data.length-1));
    if (idx>=0 && idx<data.length) setHover({ idx, mx });
  };

  const fmtHover = (v) => '$' + v.toLocaleString('en-US',{minimumFractionDigits:2,maximumFractionDigits:2});
  const fmtDay = (v) => {
    const abs = Math.abs(v);
    const s = abs.toLocaleString('en-US',{minimumFractionDigits:2,maximumFractionDigits:2});
    return (v>0?'+':v<0?'−':'') + '$' + s;
  };

  return (
    <div ref={wrapRef} style={{width:'100%', position:'relative'}}>
      <svg width={w} height={height} onMouseMove={onMove} onMouseLeave={()=>setHover(null)} style={{display:'block',cursor:'crosshair'}}>
        <defs>
          <linearGradient id="eqGrad" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor={trend>=0?'#10b981':'#ef4444'} stopOpacity="0.35" />
            <stop offset="100%" stopColor={trend>=0?'#10b981':'#ef4444'} stopOpacity="0" />
          </linearGradient>
        </defs>
        {ticks.map((tk,i)=>(
          <g key={i}>
            <line x1={padL} x2={padL+innerW} y1={tk.y} y2={tk.y} stroke="#1e1e1e" strokeWidth="1" />
            <text x={padL-8} y={tk.y+4} fill="#6b6b6b" fontSize="10" textAnchor="end" fontFamily="JetBrains Mono">{labelFor(tk.v)}</text>
          </g>
        ))}
        {[0, Math.floor(data.length/3), Math.floor(2*data.length/3), data.length-1].map(i=>(
          <text key={i} x={x(i)} y={height-8} fill="#6b6b6b" fontSize="10" textAnchor="middle" fontFamily="JetBrains Mono">
            {new Date(data[i].date).toLocaleDateString('en-US',{month:'short',day:'numeric'})}
          </text>
        ))}
        <polygon points={areaPts} fill="url(#eqGrad)" />
        <polyline points={linePts} fill="none" stroke={trend>=0?'#10b981':'#ef4444'} strokeWidth="1.8" />
        {hover && (
          <g>
            <line x1={x(hover.idx)} x2={x(hover.idx)} y1={padT} y2={padT+innerH} stroke="#333" strokeDasharray="3 3" />
            <circle cx={x(hover.idx)} cy={y(data[hover.idx].equity)} r="3.5" fill={trend>=0?'#10b981':'#ef4444'} stroke="#0a0a0a" strokeWidth="2" />
          </g>
        )}
      </svg>
      {hover && (
        <div style={{position:'absolute', left: Math.min(w-180, Math.max(0, x(hover.idx)+12)), top: 12, background:'#0a0a0a', border:'1px solid #2a2a2a', borderRadius:8, padding:'8px 10px', fontSize:12, pointerEvents:'none', minWidth: 160}}>
          <div className="muted tiny">{new Date(data[hover.idx].date).toLocaleDateString('en-US',{weekday:'short',month:'short',day:'numeric'})}</div>
          <div className="mono" style={{fontSize:14, fontWeight:600, marginTop:2}}>{fmtHover(data[hover.idx].equity)}</div>
          <div className={'mono tiny ' + (data[hover.idx].pnl>=0?'up':'dn')}>{fmtDay(data[hover.idx].pnl)} day</div>
        </div>
      )}
    </div>
  );
};

// ----- Trade row helpers -----
const DirBadge = ({ dir }) => (
  <span className={'badge ' + (dir==='long'?'badge-long':'badge-short')}>{dir==='long'?'LONG':'SHORT'}</span>
);
const OutcomeBadge = ({ out }) => {
  if (out==='win') return <span className="badge badge-win">WIN</span>;
  if (out==='loss') return <span className="badge badge-loss">LOSS</span>;
  if (out==='open') return <span className="badge badge-open">OPEN</span>;
  return <span className="badge badge-be">BE</span>;
};

const TradeRow = ({ t: trade, showTags=false, showSize=false }) => {
  const { fmtCur } = useI18n();
  const fmtPx = (v) => '$' + v.toLocaleString('en-US',{minimumFractionDigits:2,maximumFractionDigits:2});
  return (
    <tr>
      <td><span className="ticker">{trade.ticker}</span></td>
      <td><DirBadge dir={trade.dir} /></td>
      {showSize && <td className="mono muted">{trade.size}</td>}
      <td className="mono">{fmtPx(trade.entry)}</td>
      <td className="mono">{trade.exit ? fmtPx(trade.exit) : <span className="muted">—</span>}</td>
      <td className={'mono ' + (trade.pnl>0?'up':trade.pnl<0?'dn':'neu')} style={{fontWeight:600}}>{trade.status==='open' ? <span className="muted">—</span> : fmtCur(trade.pnl)}</td>
      <td className={'mono ' + (trade.r>0?'up':trade.r<0?'dn':'neu')}>{trade.status==='open' ? <span className="muted">—</span> : (trade.r>=0?'+':'') + trade.r.toFixed(2) + 'R'}</td>
      {showTags && <td>{trade.tags.map((tag,i)=><span key={i} className="tag">{tag}</span>)}</td>}
      <td className="muted mono tiny">{fmtDate(trade.date)} · {fmtTime(trade.date)}</td>
    </tr>
  );
};

// ----- Trade card (mobile) -----
const TradeCard = ({ t: trade }) => {
  const { fmtCur } = useI18n();
  const fmtPx = (v) => '$' + v.toLocaleString('en-US',{minimumFractionDigits:2,maximumFractionDigits:2});
  return (
    <div className="trade-card">
      <div className="trade-card-head">
        <div style={{display:'flex',alignItems:'center',gap:8}}>
          <span className="ticker" style={{fontSize:15}}>{trade.ticker}</span>
          <DirBadge dir={trade.dir}/>
        </div>
        <div className={'mono ' + (trade.pnl>0?'up':trade.pnl<0?'dn':'neu')} style={{fontWeight:700,fontSize:15}}>
          {trade.status==='open' ? '—' : fmtCur(trade.pnl)}
        </div>
      </div>
      <div className="trade-card-grid">
        <div><div>Entry</div><div className="mono">{fmtPx(trade.entry)}</div></div>
        <div><div>Exit</div><div className="mono">{trade.exit ? fmtPx(trade.exit) : '—'}</div></div>
        <div><div>Size</div><div className="mono">{trade.size}</div></div>
        <div><div>R</div><div className={'mono ' + (trade.r>0?'up':trade.r<0?'dn':'neu')}>{trade.status==='open'?'—':(trade.r>=0?'+':'')+trade.r.toFixed(2)+'R'}</div></div>
        <div style={{gridColumn:'1 / -1'}}><div>Date</div><div className="mono tiny muted">{fmtDate(trade.date)} · {fmtTime(trade.date)}</div></div>
      </div>
    </div>
  );
};

Object.assign(window, { TopNav, ProfileDropdown, MobileMenu, PageHead, Sparkline, KPICard, KPIRow, EquityCurve, DirBadge, OutcomeBadge, TradeRow, TradeCard, NAV_LINKS });
