// Tempo — pages: Dashboard, Daily, Calendar, Journal modal

// ─── Shared bits ──────────────────────────────────────────────────
function FilterBar({ tabs, activeTab, setActiveTab, right }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap', gap: 12 }}>
      <div style={{ display: 'flex', gap: 8 }}>
        {tabs.map((t) =>
        <button key={t.id} onClick={() => setActiveTab(t.id)} className="tap" style={{
          padding: '7px 14px', borderRadius: 8,
          border: '1.5px solid ' + (activeTab === t.id ? 'var(--blue)' : 'var(--line)'),
          background: activeTab === t.id ? 'var(--blue-soft)' : 'var(--bg-card)',
          color: activeTab === t.id ? 'var(--blue-600)' : 'var(--fg-2)',
          fontSize: 12.5, fontWeight: activeTab === t.id ? 600 : 500, letterSpacing: '-.005em',
          cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 6
        }}>
            {t.ico} {t.label}
          </button>
        )}
      </div>
      {right && <div style={{ display: 'flex', gap: 8 }}>{right}</div>}
    </div>);

}

function PickerButton({ label, icon, blue, free }) {
  return (
    <button className="tap" style={{
      display: 'inline-flex', alignItems: 'center', gap: 8,
      padding: '8px 12px', borderRadius: 8,
      border: '1px solid ' + (blue ? 'var(--blue)' : 'var(--line)'),
      background: blue ? 'var(--blue)' : 'var(--bg-card)',
      color: blue ? '#fff' : 'var(--fg-2)',
      fontSize: 12.5, fontWeight: 500, cursor: 'pointer', letterSpacing: '-.005em'
    }}>
      {icon}
      <span>{label}</span>
      {free && <span style={{ padding: '1px 7px', borderRadius: 999, background: 'var(--green-soft)', color: 'var(--green-text)', fontSize: 10, fontWeight: 600, marginLeft: 2 }}>Free</span>}
    </button>);

}

// ─── Dashboard ────────────────────────────────────────────────────
function Dashboard({ nav, navStats, openImport, openJournal, state }) {
  // Clic sur une carte KPI → section Statistiques (vue trading). Inerte si navStats absent.
  const goStats = navStats ? () => navStats('trading') : undefined;
  const [tab, setTab] = React.useState('all');
  const { trades, stats, tradesLoading, tradesByDay } = state || { trades: [], stats: computeStats([]), tradesLoading: true, tradesByDay: {} };
  const empty = !tradesLoading && trades.length === 0;
  const pf = Number.isFinite(stats.profitFactor) ? stats.profitFactor : 0;
  // Build cumulative P&L from trades (sort by date asc)
  const cumulative = React.useMemo(() => {
    const sorted = [...trades].sort((a, b) => new Date(a.executed_at) - new Date(b.executed_at));
    let running = 0;
    return sorted.map(t => { running += Number(t.pnl) || 0; return running; });
  }, [trades]);

  return (
    <div style={{ width: '100%', height: '100%', overflow: 'auto', display: 'flex', flexDirection: 'column' }} className="scroll">
      <PageHeader title="Journaling Dashboard" />
      <div style={{ padding: '20px 24px 32px', flex: 1 }}>
        <div style={{ marginBottom: 16 }}>
          <FilterBar
            activeTab={tab} setActiveTab={setTab}
            tabs={[
            { id: 'all', label: 'Tous', ico: null }]
            }
            right={[
            <button key="imp" onClick={openImport} className="btn tap">{Ico.upload} Importer CSV</button>,
            <button key="new" onClick={openImport} className="btn btn-blue tap">{Ico.plus} Nouveau trade</button>]
            } />

        </div>

        {tradesLoading ? (
          <div className="card" style={{ padding: '40px 24px', textAlign: 'center', color: 'var(--fg-3)', fontSize: 13 }}>Chargement des données…</div>
        ) : empty ? (
          <div className="card" style={{ padding: '64px 24px', textAlign: 'center' }}>
            <div style={{ fontSize: 16, fontWeight: 600, color: 'var(--fg)', marginBottom: 6 }}>Aucune donnée pour l'instant</div>
            <div style={{ fontSize: 13, color: 'var(--fg-3)', marginBottom: 20, maxWidth: 420, margin: '0 auto 20px' }}>
              Importe ton premier CSV ou ajoute un trade manuellement pour démarrer ton journal. Tes statistiques apparaîtront dès qu'il y aura des trades à analyser.
            </div>
            <div style={{ display: 'flex', gap: 10, justifyContent: 'center' }}>
              <button onClick={openImport} className="btn btn-blue tap">{Ico.plus} Ajouter un trade</button>
              <button onClick={openImport} className="btn tap">{Ico.upload} Importer un CSV</button>
            </div>
          </div>
        ) : (
          <React.Fragment>
            {/* KPI top row — 4 essentials */}
            <div className="stagger" style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 14, marginBottom: 14 }}>
              <KpiCard onClick={goStats} label="Net P&L" main={<span style={{ color: stats.netPnl >= 0 ? 'var(--green)' : 'var(--red)' }}><AnimatedMoney value={stats.netPnl} size={28} weight={700} color={stats.netPnl >= 0 ? 'var(--green)' : 'var(--red)'} /></span>} sub={`${stats.count} trade${stats.count > 1 ? 's' : ''}`} />
              <KpiCard onClick={goStats} label="Profit Factor" main={stats.count === 0 ? <span>—</span> : !Number.isFinite(stats.profitFactor) ? <span>∞</span> : <span><AnimatedNumber value={stats.profitFactor} decimals={2} /></span>} sub={stats.count > 0 ? `${stats.wins}W · ${stats.losses}L` : '—'} />
              <KpiCard onClick={goStats} label="Win Rate" main={<span><AnimatedNumber value={stats.winRate || 0} decimals={1} suffix="%" /></span>} sub={`${stats.wins}W · ${stats.losses}L`} winLossBar={stats.winRate} />
              <KpiCard onClick={goStats} label="Avg Win / Loss" main={<span><span style={{ color: 'var(--green)' }}>{fmtMoney(stats.avgWin)}</span><span style={{ color: 'var(--fg-3)', margin: '0 6px', fontSize: 18 }}>/</span><span style={{ color: 'var(--red)' }}>{fmtMoney(stats.avgLoss)}</span></span>} sub={stats.avgLoss > 0 ? `Ratio ${(stats.avgWin / stats.avgLoss).toFixed(2).replace('.', ',')}` : '—'} />
            </div>

            {/* P&L cumulé */}
            {cumulative.length > 1 && (
              <div className="stagger" style={{ display: 'grid', gridTemplateColumns: '1fr', gap: 14, marginBottom: 14 }}>
                <ChartCard title="P&L cumulé" subtitle={`${stats.count} trade${stats.count > 1 ? 's' : ''}`}>
                  <CumulativeChartReal points={cumulative}/>
                </ChartCard>
              </div>
            )}
          </React.Fragment>
        )}

        {/* Calendar — always show, with real data */}
        <CalendarBlock nav={nav} onDayClick={openJournal} openImport={openImport} tradesByDay={tradesByDay}/>
      </div>
    </div>);

}

// Lightweight cumulative chart from real points
function CumulativeChartReal({ points }) {
  if (!points || points.length < 2) return null;
  const max = Math.max(...points);
  const min = Math.min(...points);
  const labelMax = (max >= 0 ? '+$' : '−$') + Math.abs(max).toLocaleString('fr-FR');
  const labelMin = (min >= 0 ? '+$' : '−$') + Math.abs(min).toLocaleString('fr-FR');
  const tone = points[points.length - 1] >= 0 ? 'var(--green)' : 'var(--red)';
  return <LineArea data={points} W={720} H={200} stroke={tone} fill={tone === 'var(--green)' ? 'rgba(21,128,61,0.12)' : 'rgba(239,68,68,0.10)'} labelMax={labelMax} labelMin={labelMin} hover/>;
}

function KpiCard({ label, main, sub, hint, winLossBar, onClick }) {
  return (
    <div
      className={'card lift' + (onClick ? ' tap' : '')}
      onClick={onClick}
      style={{ padding: '20px 22px', position: 'relative', cursor: onClick ? 'pointer' : 'default' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 16 }}>
        <span style={{ fontSize: 13, fontWeight: 500, color: 'var(--fg-2)', letterSpacing: '-.005em' }}>{label}</span>
        {hint && <span style={{ fontSize: 11, color: 'var(--fg-3)' }}>{hint}</span>}
      </div>
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 12 }}>
        <div>
          <div style={{ fontSize: 30, fontWeight: 700, letterSpacing: '-.022em', color: 'var(--fg)', lineHeight: 1 }}>{main}</div>
          {sub && <div style={{ fontSize: 12, color: 'var(--fg-3)', marginTop: 10 }}>{sub}</div>}
        </div>
        {winLossBar != null &&
        <div style={{ width: 90, display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 6 }}>
            <div style={{ width: '100%', height: 4, borderRadius: 4, background: 'var(--red)', position: 'relative', overflow: 'hidden' }}>
              <div style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: `${winLossBar}%`, background: 'var(--green)' }}></div>
            </div>
            <div style={{ display: 'flex', justifyContent: 'space-between', width: '100%', fontSize: 10, color: 'var(--fg-3)', fontWeight: 500 }}>
              <span style={{ color: 'var(--green)' }}>{winLossBar.toFixed(0)}% W</span>
              <span style={{ color: 'var(--red)' }}>{(100 - winLossBar).toFixed(0)}% L</span>
            </div>
          </div>
        }
      </div>
    </div>);

}

function ChartCard({ title, subtitle, children, tone }) {
  return (
    <div className="card lift" style={{ padding: '18px 20px' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 6 }}>
        <span style={{ fontSize: 13, fontWeight: 600, letterSpacing: '-.01em' }}>{title}</span>
        {subtitle && <span style={{ fontSize: 11, color: tone === 'red' ? 'var(--red)' : 'var(--fg-3)' }}>{subtitle}</span>}
      </div>
      <div style={{ marginTop: 12 }}>{children}</div>
    </div>);

}

// ─── Score radar (real values, real points) ───────────────────────
function ScoreCard() {
  const axes = [
  { l: 'Win %', v: 0.62 },
  { l: 'Profit', v: 0.74 },
  { l: 'Discipline', v: 0.81 },
  { l: 'Constance', v: 0.66 },
  { l: 'Recovery', v: 0.58 },
  { l: 'R-multiple', v: 0.70 }];

  const score = 73;
  return (
    <div className="card lift" style={{ padding: '18px 20px', display: 'flex', flexDirection: 'column' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
        <span style={{ fontSize: 13, fontWeight: 600, letterSpacing: '-.01em' }}>Tempo Score</span>
        <span style={{ fontSize: 11, color: 'var(--green-text)', fontWeight: 500, background: 'var(--green-soft)', padding: '2px 8px', borderRadius: 999 }}>+3,2 vs S-1</span>
      </div>
      <div style={{ display: 'flex', justifyContent: 'center', padding: '10px 0 0' }}>
        <Radar axes={axes} size={206} />
      </div>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginTop: 6 }}>
        <span style={{ fontSize: 38, fontWeight: 700, letterSpacing: '-.022em', color: 'var(--fg)', lineHeight: 1 }}>{score}</span>
        <span style={{ fontSize: 13, color: 'var(--fg-3)' }}>/ 100</span>
      </div>
      <div style={{ height: 5, background: 'var(--bg-elev)', borderRadius: 4, marginTop: 10, overflow: 'hidden' }}>
        <div style={{ width: `${score}%`, height: '100%', background: 'linear-gradient(90deg, var(--blue), #60a5fa)', borderRadius: 4 }}></div>
      </div>
    </div>);

}

function Radar({ axes, size = 200 }) {
  const n = axes.length,cx = size / 2,cy = size / 2,R = size / 2 - 30;
  const ang = (i) => -Math.PI / 2 + i * 2 * Math.PI / n;
  const pt = (i, r) => [cx + r * Math.cos(ang(i)), cy + r * Math.sin(ang(i))];
  const ringPts = (k) => axes.map((_, i) => pt(i, R * k).join(',')).join(' ');
  const valuePts = axes.map((a, i) => pt(i, R * a.v).join(',')).join(' ');
  return (
    <svg width={size} height={size}>
      {[0.25, 0.5, 0.75, 1].map((k) => <polygon key={k} points={ringPts(k)} fill="none" stroke="var(--line)" strokeWidth="1" />)}
      {axes.map((_, i) => {
        const [x, y] = pt(i, R);
        return <line key={i} x1={cx} y1={cy} x2={x} y2={y} stroke="var(--line)" strokeWidth="1" />;
      })}
      <polygon points={valuePts} fill="rgba(59,130,246,0.16)" stroke="var(--blue)" strokeWidth="1.6" />
      {axes.map((a, i) => {
        const [x, y] = pt(i, R * a.v);
        return <circle key={i} cx={x} cy={y} r="3" fill="#fff" stroke="var(--blue)" strokeWidth="1.6" />;
      })}
      {axes.map((a, i) => {
        const [x, y] = pt(i, R + 16);
        const ta = Math.abs(Math.cos(ang(i))) < 0.3 ? 'middle' : Math.cos(ang(i)) > 0 ? 'start' : 'end';
        return (
          <text key={a.l} x={x} y={y} textAnchor={ta} dominantBaseline="middle"
          style={{ fontSize: 10, fontWeight: 500, fill: 'var(--fg-2)', letterSpacing: '-.005em' }}>
            {a.l}
          </text>);

      })}
    </svg>);

}

// ─── Cumulative chart ─────────────────────────────────────────────
function CumulativeChart() {
  const pts = [0, -180, 280, 400, 310, 590, 590, 590, 1130, 1550, 1330, 1510, 2230, 2230, 2230, 2170, 2510, 2510, 2790, 2650, 2650, 2650, 3270, 3190, 3450, 3860, 3860, 3860, 4180, 4280];
  return <LineArea data={pts} W={360} H={160} stroke="var(--green)" fill="rgba(21,128,61,0.12)" labelMax="+$4 280" labelMin="−$180" hover />;
}

function DrawdownChart() {
  const eq = [0, -180, 280, 400, 310, 590, 590, 590, 1130, 1550, 1330, 1510, 2230, 2230, 2230, 2170, 2510, 2510, 2790, 2650, 2650, 2650, 3270, 3190, 3450, 3860, 3860, 3860, 4180, 4280];
  let runMax = -Infinity;
  const dd = eq.map((v) => {runMax = Math.max(runMax, v);return v - runMax;});
  return <LineArea data={dd} W={360} H={160} stroke="var(--red)" fill="rgba(239,68,68,0.10)" labelMax="$0" labelMin="−$680" tone="red" />;
}

function PNLLineChart() {
  const series = [
  { name: 'P&L', data: [120, -80, 460, 540, 280, 720, 340, -60, 280, 410], color: 'var(--blue)' },
  { name: 'Cible', data: [200, 200, 200, 200, 200, 200, 200, 200, 200, 200], color: 'var(--fg-4)', dashed: true }];

  return <MultiBar series={series} W={360} H={160} />;
}

function LongShortBars() {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 14, padding: '6px 0' }}>
      {[
      { l: 'Long', c: 62, w: 41, ls: 21, pnl: 3180 },
      { l: 'Short', c: 28, w: 16, ls: 12, pnl: 1100 }].
      map((r) => {
        const wr = r.w / r.c * 100;
        return (
          <div key={r.l}>
            <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
              <span style={{ fontSize: 12.5, fontWeight: 500 }}>{r.l}</span>
              <span style={{ fontSize: 12, color: 'var(--fg-3)' }}>{r.c} trades · {Math.round(wr)}% win</span>
              <span style={{ fontSize: 14, fontWeight: 600, color: 'var(--green)' }}>+${r.pnl.toLocaleString('fr-FR')}</span>
            </div>
            <div style={{ display: 'flex', height: 18, borderRadius: 6, overflow: 'hidden', background: 'var(--bg-elev)', border: '1px solid var(--line)' }}>
              <div style={{ flex: r.w, background: 'var(--green)', display: 'flex', alignItems: 'center', justifyContent: 'flex-end', padding: '0 7px', color: '#fff', fontSize: 11, fontWeight: 600 }}>{r.w}W</div>
              <div style={{ flex: r.ls, background: 'var(--red)', display: 'flex', alignItems: 'center', justifyContent: 'flex-end', padding: '0 7px', color: '#fff', fontSize: 11, fontWeight: 600 }}>{r.ls}L</div>
            </div>
          </div>);

      })}
      <div style={{ marginTop: 4, paddingTop: 12, borderTop: '1px solid var(--line)', display: 'flex', justifyContent: 'space-between' }}>
        <span style={{ fontSize: 11.5, color: 'var(--fg-3)' }}>Biais 30j</span>
        <span style={{ fontSize: 12, fontWeight: 600, color: 'var(--green)' }}>Long +68 % du volume</span>
      </div>
    </div>);

}

function LineArea({ data, W, H, stroke, fill, labelMax, labelMin, tone, hover }) {
  const padL = 6,padR = 56,padT = 14,padB = 22;
  const w = W - padL - padR,h = H - padT - padB;
  const max = Math.max(...data),min = Math.min(...data);
  const sx = w / (data.length - 1);
  const y = (v) => padT + h - (v - min) / (max - min || 1) * h;
  function smooth(pts) {
    if (!pts.length) return '';
    let d = `M ${pts[0][0]} ${pts[0][1]}`;
    for (let i = 0; i < pts.length - 1; i++) {
      const [x0, y0] = pts[i],[x1, y1] = pts[i + 1];
      const cx = (x0 + x1) / 2;
      d += ` C ${cx} ${y0}, ${cx} ${y1}, ${x1} ${y1}`;
    }
    return d;
  }
  const pts = data.map((v, i) => [padL + i * sx, y(v)]);
  const path = smooth(pts);
  const lastY = y(data[data.length - 1]);
  const lastX = padL + (data.length - 1) * sx;
  const yZero = y(0);
  const area = path + ` L ${lastX} ${y(min)} L ${padL} ${y(min)} Z`;

  const [hoverIdx, setHoverIdx] = React.useState(null);
  const svgRef = React.useRef(null);

  return (
    <svg ref={svgRef} width="100%" height={H} viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="xMidYMid meet"
    style={{ display: 'block', cursor: hover ? 'crosshair' : 'default' }}
    onMouseMove={hover ? (e) => {
      const r = svgRef.current.getBoundingClientRect();
      const x = (e.clientX - r.left) / r.width * W;
      setHoverIdx(Math.max(0, Math.min(data.length - 1, Math.round((x - padL) / sx))));
    } : undefined}
    onMouseLeave={() => setHoverIdx(null)}>
      {[0, 0.5, 1].map((p, i) => {
        const v = min + (max - min) * p;
        const yy = padT + h - p * h;
        return (
          <g key={i}>
            <line x1={padL} y1={yy} x2={padL + w} y2={yy} stroke="var(--line)" strokeDasharray={p === 0 || p === 1 ? '' : '2 4'} />
            <text x={padL + w + 6} y={yy + 3.5} style={{ fontSize: 10, fill: 'var(--fg-3)', fontFamily: 'JetBrains Mono, monospace' }}>
              {p === 0 ? labelMin : p === 1 ? labelMax : ''}
            </text>
          </g>);

      })}
      {/* zero line if 0 falls in range */}
      {0 >= min && 0 <= max && <line x1={padL} y1={yZero} x2={padL + w} y2={yZero} stroke="var(--line-2)" strokeDasharray="2 3" />}

      <path d={area} fill={fill} style={{ opacity: 0, animation: 'fade-in .8s var(--ease) .6s forwards' }} />
      <path d={path} fill="none" stroke={stroke} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
      style={{ strokeDasharray: 3000, strokeDashoffset: 3000, animation: 'draw 1.4s var(--ease) .2s forwards' }} />

      <circle cx={lastX} cy={lastY} r="3.5" fill="#fff" stroke={stroke} strokeWidth="2"
      style={{ opacity: 0, animation: 'fade-in .4s var(--ease) 1.4s forwards' }} />

      {/* x ticks */}
      {[0, Math.floor(data.length / 2), data.length - 1].map((idx, k) =>
      <text key={k} x={padL + idx * sx} y={H - 6} textAnchor={k === 0 ? 'start' : k === 2 ? 'end' : 'middle'}
      style={{ fontSize: 10, fill: 'var(--fg-3)', fontFamily: 'JetBrains Mono, monospace' }}>
          {['25 avr', '10 mai', '25 mai'][k]}
        </text>
      )}

      {hover && hoverIdx != null &&
      <g>
          <line x1={padL + hoverIdx * sx} y1={padT} x2={padL + hoverIdx * sx} y2={padT + h} stroke="var(--fg)" strokeWidth="1" strokeDasharray="3 3" opacity=".35" />
          <circle cx={padL + hoverIdx * sx} cy={y(data[hoverIdx])} r="4" fill="#fff" stroke={stroke} strokeWidth="2" />
          <g transform={`translate(${Math.min(padL + hoverIdx * sx + 8, W - 78)}, ${Math.max(y(data[hoverIdx]) - 30, padT)})`}>
            <rect x="0" y="0" width="74" height="30" rx="6" fill="#0f172a" />
            <text x="6" y="12" style={{ fontSize: 9, fill: 'rgba(255,255,255,.55)', fontFamily: 'JetBrains Mono, monospace' }}>JOUR {hoverIdx + 1}</text>
            <text x="6" y="24" style={{ fontSize: 11, fill: '#fff', fontFamily: 'JetBrains Mono, monospace', fontWeight: 600 }}>
              {data[hoverIdx] >= 0 ? '+' : '−'}${Math.abs(data[hoverIdx]).toLocaleString('fr-FR')}
            </text>
          </g>
        </g>
      }
    </svg>);

}

function MultiBar({ series, W, H }) {
  const padL = 6,padR = 56,padT = 14,padB = 22;
  const w = W - padL - padR,h = H - padT - padB;
  const allData = series[0].data;
  const max = Math.max(...allData.map(Math.abs));
  const sy = h / 2 / max;
  const cy = padT + h / 2;
  const bw = w / allData.length * 0.6;
  const target = series[1].data[0];
  const targetY = cy - target * sy;
  return (
    <svg width="100%" height={H} viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="xMidYMid meet" style={{ display: 'block' }}>
      {[1, 0.5, 0, -0.5, -1].map((p, i) => {
        const v = max * p;
        const yy = cy - p * h / 2;
        return (
          <g key={i}>
            <line x1={padL} y1={yy} x2={padL + w} y2={yy} stroke="var(--line)" strokeDasharray={p === 0 ? '' : '2 4'} opacity={p === 0 ? 1 : .7} />
            {(p === 1 || p === -1 || p === 0) &&
            <text x={padL + w + 6} y={yy + 3.5} style={{ fontSize: 10, fill: 'var(--fg-3)', fontFamily: 'JetBrains Mono, monospace' }}>
                {p === 0 ? '$0' : (p > 0 ? '+$' : '−$') + Math.abs(v).toLocaleString('fr-FR')}
              </text>
            }
          </g>);

      })}
      {/* target line */}
      <line x1={padL} y1={targetY} x2={padL + w} y2={targetY} stroke={series[1].color} strokeDasharray="4 4" opacity=".6" />
      <text x={padL + w + 6} y={targetY + 3.5} style={{ fontSize: 9.5, fill: 'var(--fg-3)', fontFamily: 'JetBrains Mono, monospace' }}>Cible</text>
      {allData.map((v, i) => {
        if (v === 0) return null;
        const cx = padL + (i + 0.5) * (w / allData.length);
        const barH = Math.abs(v) * sy;
        const y = v > 0 ? cy - barH : cy;
        return (
          <rect key={i} x={cx - bw / 2} y={y} width={bw} height={barH} rx="2"
          fill={v > 0 ? 'var(--green)' : 'var(--red)'} opacity=".88"
          style={{ animation: `bar-grow .55s var(--ease) ${.2 + i * .04}s backwards`, transformOrigin: `center ${cy}px` }} />);


      })}
      {[0, Math.floor(allData.length / 2), allData.length - 1].map((idx, k) =>
      <text key={k} x={padL + (idx + 0.5) * (w / allData.length)} y={H - 6}
      textAnchor={k === 0 ? 'start' : k === 2 ? 'end' : 'middle'}
      style={{ fontSize: 10, fill: 'var(--fg-3)', fontFamily: 'JetBrains Mono, monospace' }}>
          {['S20', 'S22', 'S24'][k]}
        </text>
      )}
    </svg>);

}

// ─── Calendar block (used on Dashboard + Calendar page) ───────────
function CalendarBlock({ nav, onDayClick, openImport, full = false, tradesByDay = {} }) {
  // Single source of truth for the displayed month — a Date pinned to the 1st of that month.
  // Using a Date (vs. separate year/monthIdx state vars) keeps prev/next updates atomic and
  // avoids React batching surprises when crossing year boundaries.
  const [viewMonth, setViewMonth] = React.useState(() => {
    const n = new Date();
    return new Date(n.getFullYear(), n.getMonth(), 1);
  });
  const year = viewMonth.getFullYear();
  const monthIdx = viewMonth.getMonth();
  const monthNames = ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'];
  const monthLabel = `${monthNames[monthIdx]} ${year}`;

  // Build cells for the given month
  const firstOfMonth = new Date(year, monthIdx, 1);
  const lastDay = new Date(year, monthIdx + 1, 0).getDate();
  // Monday-first offset
  const jsDow = firstOfMonth.getDay(); // 0=Sun..6=Sat
  const offset = (jsDow + 6) % 7;
  const cells = [];
  for (let i = 0; i < offset; i++) cells.push(null);
  for (let d = 1; d <= lastDay; d++) cells.push(d);
  while (cells.length % 7) cells.push(null);
  const weeks = [];
  for (let i = 0; i < cells.length; i += 7) weeks.push(cells.slice(i, i + 7));
  const days = ['Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim'];

  const todayISODate = todayISO();

  const fmt = (v) => {
    if (v == null) return '';
    const a = Math.abs(v);
    if (a === 0) return '$0,00';
    if (a >= 1000) return (v >= 0 ? '+$' : '−$') + (a / 1000).toFixed(2).replace('.', ',') + 'k';
    return (v >= 0 ? '+$' : '−$') + a;
  };

  const toISO = (day) => `${year}-${String(monthIdx + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
  const dataFor = (day) => day ? tradesByDay[toISO(day)] : null;

  const weekTotals = weeks.map((wk) => {
    let net = 0, n = 0;
    wk.forEach((d) => { const data = dataFor(d); if (data) { net += data.pnl; n += data.trades.length; } });
    return { net, n };
  });

  // Amplitude du mois → intensité de couleur d'un jour (vert/rouge plus ou moins fort).
  // color-mix avec --bg-card pour rester lisible en clair ET en sombre.
  let maxAbsDay = 1;
  weeks.forEach((wk) => wk.forEach((d) => { const data = dataFor(d); if (data) maxAbsDay = Math.max(maxAbsDay, Math.abs(data.pnl)); }));
  const dayBg = (data) => {
    if (!data || !data.pnl) return 'var(--bg-card)';
    const intensity = Math.min(1, Math.abs(data.pnl) / maxAbsDay);
    const a = Math.round(10 + intensity * 28); // 10 % → 38 %
    return data.pnl > 0
      ? `color-mix(in srgb, var(--green) ${a}%, var(--bg-card))`
      : `color-mix(in srgb, var(--red) ${a}%, var(--bg-card))`;
  };

  const prevMonth = () => setViewMonth(m => new Date(m.getFullYear(), m.getMonth() - 1, 1));
  const nextMonth = () => setViewMonth(m => new Date(m.getFullYear(), m.getMonth() + 1, 1));

  return (
    <div className="card" style={{ padding: '20px 22px' }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 18 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{ width: 28, height: 28, borderRadius: 8, background: 'var(--blue)', display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative' }}>
            <div style={{ width: 1.5, height: 12, background: '#fff' }}></div>
            <div style={{ position: 'absolute', width: 9, height: 1.5, background: '#fff', top: 7.5 }}></div>
          </div>
          <span style={{ fontSize: 15, fontWeight: 600, letterSpacing: '-.01em' }}>Calendrier Tempo</span>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <button onClick={prevMonth} className="tap" style={{ width: 30, height: 30, borderRadius: 8, border: '1px solid var(--line)', background: 'var(--bg-card)', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', color: 'var(--fg-2)' }}>{Ico.arrL}</button>
          <span style={{ fontSize: 14, fontWeight: 600, padding: '0 8px', minWidth: 130, textAlign: 'center' }}>{monthLabel}</span>
          <button onClick={nextMonth} className="tap" style={{ width: 30, height: 30, borderRadius: 8, border: '1px solid var(--line)', background: 'var(--bg-card)', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', color: 'var(--fg-2)' }}>{Ico.arrR}</button>
          <button onClick={() => openImport && openImport(todayISODate)} className="tap btn btn-blue" style={{ marginLeft: 6 }}>{Ico.plus} Ajouter un trade</button>
        </div>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr) 110px', gap: 8, marginBottom: 8 }}>
        {days.map((d) => <span key={d} style={{ fontSize: 12, fontWeight: 600, color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '.04em', padding: '0 4px' }}>{d}</span>)}
        <span style={{ fontSize: 12, fontWeight: 600, color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '.04em', padding: '0 4px' }}>Weekly</span>
      </div>

      {weeks.map((wk, wi) =>
      <div key={wi} style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr) 110px', gap: 8, marginBottom: 8 }}>
          {wk.map((d, di) => {
          const iso = d ? toISO(d) : null;
          const data = dataFor(d);
          const isToday = iso === todayISODate;
          const tone = data ? (data.pnl > 0 ? 'pos' : (data.pnl < 0 ? 'neg' : 'flat')) : null;
          return (
            <button key={di}
            onClick={() => d && onDayClick && onDayClick(iso)}
            disabled={!d}
            style={{
              border: '1px solid ' + (isToday ? 'var(--blue)' : 'var(--line)'),
              borderRadius: 10,
              background: !d ? 'transparent' : dayBg(data),

              minHeight: full ? 104 : 88,
              padding: '10px 12px',
              cursor: d ? 'pointer' : 'default',
              display: 'flex', flexDirection: 'column', justifyContent: 'space-between',
              textAlign: 'left',
              position: 'relative',
              boxShadow: isToday ? '0 0 0 2px rgba(59,130,246,0.16)' : 'none',
              transition: 'all .15s var(--ease)',
              fontFamily: 'inherit',
              opacity: d ? 1 : .4
            }}
            className="tap">
                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                  <span style={{ fontSize: 13, fontWeight: isToday ? 700 : 500, color: 'var(--fg)', letterSpacing: '-.01em' }}>{d || ''}</span>
                  {isToday && <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--blue)' }}></span>}
                </div>
                {data && (
                  <div>
                    <div className="num" style={{
                      fontSize: 18, fontWeight: 700,
                      color: data.pnl > 0 ? 'var(--green)' : data.pnl < 0 ? 'var(--red)' : 'var(--fg-3)',
                      letterSpacing: '-.018em', lineHeight: 1
                    }}>{fmt(data.pnl)}</div>
                    {data.trades.length === 0 ? (
                      <div style={{ fontSize: 10.5, color: 'var(--fg-3)', marginTop: 5 }}>Journal</div>
                    ) : (
                      <div style={{ display: 'flex', gap: 3, flexWrap: 'wrap', marginTop: 6 }}>
                        {data.trades.slice(0, 5).map((t, ti) => {
                          const v = Number(t.pnl) || 0;
                          const win = v > 0, loss = v < 0;
                          return (
                            <span key={ti} title={win ? 'Gagnant' : loss ? 'Perdant' : 'Neutre'} style={{
                              minWidth: 16, height: 16, padding: '0 3px', borderRadius: 4,
                              fontSize: 10, fontWeight: 700, lineHeight: 1,
                              display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                              background: win ? 'var(--green-soft)' : loss ? 'var(--red-soft)' : 'var(--bg-elev)',
                              color: win ? 'var(--green-text)' : loss ? 'var(--red-text)' : 'var(--fg-3)',
                            }}>{win ? 'W' : loss ? 'L' : '·'}</span>
                          );
                        })}
                        {data.trades.length > 5 && (
                          <span style={{ fontSize: 10.5, color: 'var(--fg-3)', alignSelf: 'center' }}>+{data.trades.length - 5}</span>
                        )}
                      </div>
                    )}
                  </div>
                )}
              </button>);

        })}
          <div style={{
          border: '1px solid var(--line)', borderRadius: 10,
          background: 'var(--bg-soft)', padding: '10px 12px',
          display: 'flex', flexDirection: 'column', justifyContent: 'space-between', minHeight: full ? 96 : 80
        }}>
            <span style={{ fontSize: 11, color: 'var(--fg-3)', fontWeight: 500, textTransform: 'uppercase', letterSpacing: '.04em' }}>S{wi + 1}</span>
            <div>
              <div className="num" style={{
              fontSize: 15, fontWeight: 600,
              color: weekTotals[wi].net > 0 ? 'var(--green)' : weekTotals[wi].net < 0 ? 'var(--red)' : 'var(--fg-3)',
              letterSpacing: '-.018em', lineHeight: 1
            }}>{weekTotals[wi].net === 0 ? '$0,00' : fmt(weekTotals[wi].net)}</div>
              <div style={{ fontSize: 10.5, color: 'var(--fg-3)', marginTop: 3 }}>{weekTotals[wi].n} trade{weekTotals[wi].n !== 1 ? 's' : ''}</div>
            </div>
          </div>
        </div>
      )}
    </div>);

}

// ─── Calendar page (full month, used by route 'calendar' if any) ─
function CalendarPage({ nav, onDayClick }) {
  return (
    <div style={{ width: '100%', height: '100%', overflow: 'auto' }} className="scroll">
      <PageHeader title="Calendrier" />
      <div style={{ padding: '20px 24px 32px' }}>
        <CalendarBlock nav={nav} onDayClick={onDayClick} full />
      </div>
    </div>);

}

Object.assign(window, {
  Dashboard, CalendarPage, FilterBar, PickerButton, CalendarBlock,
  Radar, ScoreCard, LineArea, MultiBar, CumulativeChart, DrawdownChart, PNLLineChart, LongShortBars,
  KpiCard, ChartCard
});