// Rumbo — Dashboard · v3 · Mobile-First · Design System

const { useRef: useRfDS, useEffect: useEffDS, useState: useStDS } = React;

/* ── Donut compacto gastos por categoría ── */
const CategoryDonutDS = ({ transactions, redraw }) => {
  const ref = useRfDS(null);
  const ch  = useRfDS(null);

  useEffDS(() => {
    let t = 0;
    const init = () => {
      if (!ref.current || !window.Chart) { if (t++ < 20) { setTimeout(init, 150); return; } return; }
      if (ch.current) { ch.current.destroy(); ch.current = null; }

      const bycat = {};
      transactions.filter(x => x.type === 'expense')
        .forEach(x => { bycat[x.category] = (bycat[x.category] || 0) + x.amount; });
      const entries = Object.entries(bycat).sort((a,b) => b[1]-a[1]).slice(0,6);
      if (!entries.length) return;

      const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
      ch.current = new window.Chart(ref.current, {
        type: 'doughnut',
        data: {
          labels: entries.map(([k]) => k),
          datasets: [{
            data:            entries.map(([,v]) => v),
            backgroundColor: entries.map(([k]) => getCategoryColor(k)),
            borderColor:     isDark ? '#11121C' : '#fff',
            borderWidth: 3,
            hoverOffset: 6,
          }]
        },
        options: {
          responsive: true,
          maintainAspectRatio: false,
          cutout: '72%',
          plugins: {
            legend: { display: false },
            tooltip: {
              backgroundColor: isDark ? '#1E2030' : '#334155',
              titleColor: isDark ? '#94A3B8' : '#CBD5E1',
              bodyColor: '#F1F5F9',
              cornerRadius: 10, padding: 10,
              callbacks: { label: ctx => ` ${ctx.label}: ${fmtFull(ctx.raw)}` }
            }
          }
        }
      });
    };
    init();
    return () => { if (ch.current) { ch.current.destroy(); ch.current = null; } };
  }, [transactions, redraw]);

  return <canvas ref={ref} style={{ width: '100%', height: '100%' }} />;
};

/* ── Stat pill ── */
const Pill = ({ label, value, color, trend, trendLabel = 'vs mes ant.', goodWhen = 'up' }) => {
  // goodWhen='up' → subir es bueno (ingresos, ahorro). 'down' → subir es malo (gastos).
  const isGood = goodWhen === 'up' ? trend >= 0 : trend < 0;
  return (
    <div style={{
      background: 'var(--surface)', borderRadius: 'var(--r-lg)',
      border: '1px solid var(--border)', boxShadow: 'var(--sh-sm)',
      padding: '14px 16px',
    }}>
      <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--t4)', textTransform: 'uppercase', letterSpacing: '0.4px', marginBottom: 6 }}>
        {label}
      </div>
      <div style={{ fontSize: 20, fontWeight: 800, color, letterSpacing: '-0.4px', fontVariantNumeric: 'tabular-nums', lineHeight: 1.2 }}>
        {value}
      </div>
      {trend !== undefined && trend !== null && (
        <div style={{ marginTop: 5, display: 'flex', alignItems: 'center', gap: 4 }}>
          <span className={`badge badge-${isGood ? 'green' : 'red'}`}>
            <Icon name={trend >= 0 ? 'arrowUp' : 'arrowDown'} size={10} color={isGood ? 'var(--success-text)' : 'var(--danger-text)'} strokeWidth={2.5} />
            {Math.abs(trend)}%
          </span>
          <span style={{ fontSize: 11, color: 'var(--t5)' }}>{trendLabel}</span>
        </div>
      )}
    </div>
  );
};

/* ── Dashboard principal ── */
const Dashboard = ({ data, setData, setScreen, norteScore = 60, norteInfo = null, theme, toggleTheme, selectedMonth, setSelectedMonth, openNewTx }) => {
  const { accounts, debts, transactions, settings } = data;
  const [chartKey, setChartKey] = useStDS(0);

  // Re-render charts when theme changes
  useEffDS(() => { setChartKey(k => k + 1); }, [theme]);

  const totalAssets = accounts.reduce((s, a) => s + a.balance, 0);
  const totalDebt   = debts.reduce((s, d) => s + d.balance, 0);
  const netWorth    = totalAssets - totalDebt;

  // Mes seleccionado y el anterior — todo el dashboard se ancla a ese mes
  const curMonth  = selectedMonth || CURRENT_MONTH;
  const prevMonth = (typeof getPrevMonth === 'function') ? getPrevMonth(curMonth) : PREV_MONTH;
  const todayKey  = `${new Date().getFullYear()}-${String(new Date().getMonth()+1).padStart(2,'0')}`;
  const isFutureMonth = curMonth > todayKey;

  const curTx  = transactions.filter(t => t.date.startsWith(curMonth));
  const prevTx = transactions.filter(t => t.date.startsWith(prevMonth));

  // Proyección del mes — la pieza final del rumbo
  const projection = (typeof getMonthProjection === 'function')
    ? getMonthProjection(data, curMonth)
    : null;

  const income   = curTx.filter(t => t.type === 'income').reduce((s,t)=>s+t.amount, 0);
  const expenses = curTx.filter(t => t.type === 'expense').reduce((s,t)=>s+t.amount, 0);
  const saving   = income - expenses;
  const savingPct = income > 0 ? Math.round((saving/income)*100) : 0;

  // Promedio de gasto por día — solo cuenta los días transcurridos del mes
  const dailyAvg = (() => {
    const [y, m] = curMonth.split('-').map(Number);
    const today = new Date();
    const isThisMonth = today.getFullYear() === y && today.getMonth() + 1 === m;
    const isPast = curMonth < todayKey;
    const daysElapsed = isThisMonth ? today.getDate()
                       : isPast      ? new Date(y, m, 0).getDate()  // último día del mes pasado
                       : 1;                                          // mes futuro
    return daysElapsed > 0 ? expenses / daysElapsed : 0;
  })();

  // Gasto de hoy (solo aplica si estamos viendo el mes actual)
  const isCurrentMonth = curMonth === todayKey;
  const todayISO = (() => {
    const d = new Date();
    return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
  })();
  const yesterdayISO = (() => {
    const d = new Date(); d.setDate(d.getDate() - 1);
    return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
  })();
  const todayExpense = !isCurrentMonth ? 0
    : curTx.filter(t => t.type === 'expense' && (t.date || '').startsWith(todayISO)).reduce((s,t)=>s+t.amount, 0);
  const yesterdayExpense = !isCurrentMonth ? 0
    : curTx.filter(t => t.type === 'expense' && (t.date || '').startsWith(yesterdayISO)).reduce((s,t)=>s+t.amount, 0);
  const trendDay = (isCurrentMonth && yesterdayExpense > 0)
    ? Math.round(((todayExpense - yesterdayExpense) / yesterdayExpense) * 100)
    : null;

  const prevInc = prevTx.filter(t=>t.type==='income').reduce((s,t)=>s+t.amount,0);
  const prevExp = prevTx.filter(t=>t.type==='expense').reduce((s,t)=>s+t.amount,0);
  const prevSaving = prevInc - prevExp;
  const trendInc = prevInc > 0 ? Math.round(((income-prevInc)/prevInc)*100) : null;
  const trendExp = prevExp > 0 ? Math.round(((expenses-prevExp)/prevExp)*100) : null;
  const trendSaving = prevSaving > 0 ? Math.round(((saving - prevSaving)/prevSaving)*100) : null;

  const toneColors = { success: 'var(--success)', warning: 'var(--warning)', danger: 'var(--danger)', neutral: 'var(--accent)' };
  const toneBgs    = { success: 'var(--success-bg)', warning: 'var(--warning-bg)', danger: 'var(--danger-bg)', neutral: 'var(--accent-muted)' };
  const toneTexts  = { success: 'var(--success-text)', warning: 'var(--warning-text)', danger: 'var(--danger-text)', neutral: 'var(--accent-text)' };
  const tone = norteInfo?.tone || (norteScore >= 70 ? 'success' : norteScore >= 40 ? 'warning' : 'danger');
  const scoreColor = toneColors[tone];
  const scoreLabel = norteInfo?.label || (norteScore >= 70 ? 'Rumbo firme' : norteScore >= 40 ? 'En camino' : 'Zona de riesgo');

  // Gastos por categoría (mes)
  const bycat = {};
  curTx.filter(t=>t.type==='expense').forEach(t=>{ bycat[t.category]=(bycat[t.category]||0)+t.amount; });
  const catEntries = Object.entries(bycat).sort((a,b)=>b[1]-a[1]).slice(0,5);

  // Recientes — ancladas al mes seleccionado (no globales). Si no hay, fallback a últimas 8 globales.
  const recentInMonth = [...curTx].sort((a,b)=>b.date.localeCompare(a.date)).slice(0,8);
  const recent = recentInMonth.length > 0
    ? recentInMonth
    : [...transactions].sort((a,b)=>b.date.localeCompare(a.date)).slice(0,8);

  const needleAngle = -90 + (norteScore/100)*180;

  return (
    <div style={{ background: 'var(--bg)', minHeight: '100%', paddingBottom: 24 }}>

      {/* ── Header ── */}
      <div className="screen-header">
        <div>
          <h1 className="screen-title">{settings.name ? `¡Hola, ${settings.name}!` : '¡Hola!'}</h1>
          <p className="screen-sub">Aquí tienes tu resumen financiero</p>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 2 }}>
          {setSelectedMonth ? (
            <MonthSwitcher value={curMonth} onChange={setSelectedMonth} transactions={transactions} compact />
          ) : (
            <div style={{
              background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--r-md)',
              padding: '6px 11px', fontSize: 12, fontWeight: 600, color: 'var(--t3)',
              boxShadow: 'var(--sh-xs)', display: 'flex', alignItems: 'center', gap: 5,
            }}>
              <Icon name="calendar" size={13} color="var(--t4)" />
              <span style={{ textTransform: 'capitalize' }}>{getMonthLabel(curMonth)}</span>
            </div>
          )}
          <button className="theme-toggle" onClick={toggleTheme} title="Cambiar tema">
            <Icon name={theme === 'dark' ? 'sun' : 'moon'} size={15} color="var(--t3)" />
          </button>
        </div>
      </div>

      {/* Banner informativo — modo "futuro" o "pasado" */}
      {curMonth !== todayKey && (
        <div style={{ padding: '10px 20px 0' }}>
          <div style={{
            display:'flex', alignItems:'center', gap:10, padding:'8px 14px',
            background: isFutureMonth ? 'var(--warning-bg)' : 'var(--accent-muted)',
            border: `1px solid ${isFutureMonth ? 'var(--warning)' : 'var(--accent)'}`,
            borderRadius:'var(--r-md)', fontSize:12,
          }}>
            <Icon name={isFutureMonth ? 'arrowUp' : 'arrowDown'} size={13}
              color={isFutureMonth ? 'var(--warning)' : 'var(--accent)'} strokeWidth={2.5} />
            <span style={{ flex:1, color: isFutureMonth ? 'var(--warning-text)' : 'var(--accent-text)', fontWeight:600 }}>
              {(() => {
                const lbl = getMonthLabel(curMonth);
                const cap = lbl.charAt(0).toUpperCase() + lbl.slice(1);
                return isFutureMonth
                  ? `Estás viendo ${cap} — mes futuro, solo proyecciones de fijos.`
                  : `Estás viendo ${cap} — mes pasado, datos cerrados.`;
              })()}
            </span>
            <button onClick={() => setSelectedMonth && setSelectedMonth(todayKey)}
              style={{ background:'none', border:'none', cursor:'pointer', color:'var(--accent)', fontSize:12, fontWeight:700 }}>
              Volver a hoy
            </button>
          </div>
        </div>
      )}

      {/* ── Tarjeta Salud Financiera ── */}
      <div style={{ padding: '16px 20px 0' }}>
        <div style={{
          background: 'var(--surface)', border: '1px solid var(--border)',
          borderRadius: 'var(--r-xl)', boxShadow: 'var(--sh-md)', padding: '16px 18px',
        }}>
          {/* Eyebrow uppercase — centrado */}
          <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--t5)', textTransform: 'uppercase', letterSpacing: '1.2px', marginBottom: 14, textAlign: 'center' }}>
            Cómo estás parado hoy
          </div>

          {/* Fila 1: Score + Brújula — grupo centrado, no en los extremos */}
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 24 }}>
            <div style={{ textAlign: 'center' }}>
              <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--t3)', marginBottom: 4 }}>Tu Norte</div>
              <div style={{ display: 'inline-flex', alignItems: 'baseline', gap: 4, marginBottom: 10 }}>
                <span style={{ fontSize: 42, fontWeight: 900, color: 'var(--accent)', letterSpacing: '-1.5px', fontVariantNumeric: 'tabular-nums', lineHeight: 1 }}>{norteInfo?.empty ? '—' : norteScore}</span>
                <span style={{ fontSize: 16, fontWeight: 700, color: 'var(--t5)', fontVariantNumeric: 'tabular-nums' }}>/100</span>
              </div>
              <div>
                <span className="badge" style={{
                  background: toneBgs[tone],
                  color: toneTexts[tone],
                  display: 'inline-block',
                }}>
                  {scoreLabel}
                </span>
              </div>
            </div>
            <div className="norte-compass-anim" style={{ flexShrink: 0, position: 'relative' }}>
              <svg width="92" height="92" viewBox="0 0 72 72">
                <circle cx="36" cy="36" r="30" fill="none" stroke="var(--track)" strokeWidth="6"/>
                <circle cx="36" cy="36" r="30" fill="none"
                  stroke="var(--accent)" strokeWidth="6"
                  strokeDasharray={`${(norteScore/100)*188.5} 188.5`}
                  strokeLinecap="round"
                  transform="rotate(-90 36 36)"
                  style={{ transition: 'stroke-dasharray 1s ease' }}
                />
                <g transform={`rotate(${needleAngle},36,36)`} style={{ transition: 'transform 1s ease' }}>
                  <polygon points="36,36 34.4,42 36,18 37.6,42" fill="var(--accent)"/>
                  <polygon points="36,36 37.6,30 36,52 34.4,30" fill="var(--accent)" opacity="0.18"/>
                </g>
                <circle cx="36" cy="36" r="3" fill="var(--accent)"/>
                <circle cx="36" cy="36" r="1.2" fill="var(--surface)"/>
              </svg>
            </div>
          </div>

          {/* Divider con titulito centrado */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 12, margin: '16px 0' }}>
            <div style={{ flex: 1, height: 1, background: 'var(--border)' }} />
            <span style={{ fontSize: 10, fontWeight: 700, color: 'var(--t5)', textTransform: 'uppercase', letterSpacing: '1px' }}>Balance final</span>
            <div style={{ flex: 1, height: 1, background: 'var(--border)' }} />
          </div>

          {/* Fila 2: Monto centrado grande */}
          <div style={{ textAlign: 'center' }}>
            <div style={{ fontSize: 12, color: 'var(--t4)', marginBottom: 6 }}>Si pagás todas tus deudas hoy, te quedan:</div>
            <div style={{ fontSize: 32, fontWeight: 900, color: netWorth >= 0 ? 'var(--accent)' : 'var(--danger)', letterSpacing: '-1px', fontVariantNumeric: 'tabular-nums', lineHeight: 1 }}>
              {fmtFull(netWorth)}
            </div>
          </div>

          {/* La brújula habla: por qué estás en esta banda + UNA acción concreta */}
          {norteInfo?.msg && (
            <div style={{
              marginTop: 16, padding: '12px 14px',
              background: 'var(--surface-2)', border: '1px solid var(--border)',
              borderRadius: 'var(--r-lg)', display: 'flex', gap: 10, alignItems: 'flex-start',
            }}>
              <div style={{ width: 28, height: 28, borderRadius: 'var(--r-md)', background: toneBgs[tone], display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                <Icon name="compass" size={15} color={scoreColor} strokeWidth={1.8} />
              </div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 12, color: 'var(--t2)', lineHeight: 1.55 }}>{norteInfo.msg}</div>
                {norteInfo.action && setScreen && (
                  <button onClick={() => setScreen(norteInfo.action.screen)}
                    style={{
                      marginTop: 8, display: 'inline-flex', alignItems: 'center', gap: 4,
                      background: 'none', border: 'none', padding: 0, cursor: 'pointer',
                      color: 'var(--accent)', fontSize: 12, fontWeight: 800, fontFamily: 'var(--font)',
                    }}>
                    {norteInfo.action.label}
                    <Icon name="arrowRight" size={13} color="var(--accent)" strokeWidth={2.2} />
                  </button>
                )}
              </div>
            </div>
          )}
        </div>
      </div>

      {/* ── Cards Tenés / Debés — únicas con color, monto protagonista ── */}
      <div style={{ padding: '12px 20px 0', display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
        <button
          onClick={() => setScreen('accounts')}
          style={{ background: 'var(--success-bg)', border: '1px solid color-mix(in srgb, var(--success) 25%, transparent)', borderRadius: 'var(--r-lg)', padding: '14px 14px 12px', textAlign: 'left', cursor: 'pointer', fontFamily: 'var(--font)', display: 'flex', flexDirection: 'column', gap: 6 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
            <Icon name="arrowUp" size={12} color="var(--success)" strokeWidth={2.5} />
            <span style={{ fontSize: 10, fontWeight: 800, color: 'var(--success-text)', textTransform: 'uppercase', letterSpacing: '0.5px' }}>Tenés</span>
          </div>
          <div style={{ fontSize: 24, fontWeight: 900, color: 'var(--success)', fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.8px', lineHeight: 1 }}>{fmtFull(totalAssets)}</div>
          <div style={{ fontSize: 10, color: 'var(--success-text)', opacity: 0.7 }}>plata disponible hoy</div>
        </button>
        <button
          onClick={() => setScreen('debts')}
          style={{ background: 'var(--danger-bg)', border: '1px solid color-mix(in srgb, var(--danger) 25%, transparent)', borderRadius: 'var(--r-lg)', padding: '14px 14px 12px', textAlign: 'left', cursor: 'pointer', fontFamily: 'var(--font)', display: 'flex', flexDirection: 'column', gap: 6 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
            <Icon name="arrowDown" size={12} color="var(--danger)" strokeWidth={2.5} />
            <span style={{ fontSize: 10, fontWeight: 800, color: 'var(--danger-text)', textTransform: 'uppercase', letterSpacing: '0.5px' }}>Debés</span>
          </div>
          <div style={{ fontSize: 24, fontWeight: 900, color: 'var(--danger)', fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.8px', lineHeight: 1 }}>{fmtFull(totalDebt)}</div>
          <div style={{ fontSize: 10, color: 'var(--danger-text)', opacity: 0.7 }}>total pendiente</div>
        </button>
      </div>

      {/* ── 4 Stats ── */}
      <div style={{ padding: '18px 20px 6px', display: 'flex', alignItems: 'center', gap: 8 }}>
        <span style={{ fontSize: 10, fontWeight: 700, color: 'var(--t5)', textTransform: 'uppercase', letterSpacing: '1px' }}>Este mes</span>
        <div style={{ flex: 1, height: 1, background: 'var(--border)' }} />
      </div>
      <div style={{ padding: '0 20px', display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 10 }} className="stats-grid-4">
        <Pill label={isFutureMonth?'Esperado':'Ingresos'}  value={fmtFull(isFutureMonth ? (projection?.expected.income||0) : income)}   color="var(--success)"  trend={isFutureMonth?null:trendInc}  goodWhen="up"   />
        <Pill label={isFutureMonth?'Esperado':'Gastos'}    value={fmtFull(isFutureMonth ? (projection?.expected.expense||0) : expenses)}  color="var(--danger)"   trend={isFutureMonth?null:trendExp}  goodWhen="down" />
        <Pill label={isFutureMonth?'Sobrará':'Te sobró'}  value={fmtFull(isFutureMonth ? (projection?.expected.net||0) : saving)}    color="var(--success)"  trend={isFutureMonth?null:trendSaving} goodWhen="up" />
        {isCurrentMonth
          ? <Pill label="Hoy gastaste"      value={fmtFull(todayExpense)} color={todayExpense > 0 ? 'var(--danger)' : 'var(--t5)'} trend={trendDay} trendLabel="vs ayer" goodWhen="down" />
          : <Pill label="Promedio por día"  value={fmtFull(dailyAvg)}     color="var(--t2)"     trend={null} />}
      </div>

      {/* ── Proyección del mes — la pieza del rumbo ── */}
      {projection && (projection.isFuture || (projection.isCurrent && (projection.projected.income > 0 || projection.projected.expense > 0))) && (
        <div style={{ padding:'12px 20px 0' }}>
          <div style={{
            background:'var(--surface)', border:'1.5px solid var(--border)',
            borderRadius:'var(--r-xl)', padding:'18px 20px', boxShadow:'var(--sh-sm)',
          }}>
            <div style={{ display:'flex', justifyContent:'space-between', alignItems:'flex-start', marginBottom:14 }}>
              <div>
                <div style={{ fontSize:11, fontWeight:700, color:'var(--t5)', textTransform:'uppercase', letterSpacing:'0.5px', marginBottom:3 }}>
                  {projection.isFuture ? 'Lo que viene en' : 'Lo que falta del mes'}
                </div>
                <div style={{ fontSize:15, fontWeight:800, color:'var(--t1)' }}>
                  {projection.isFuture
                    ? (() => { const lbl = getMonthLabel(curMonth); return lbl.charAt(0).toUpperCase()+lbl.slice(1); })()
                    : 'según fijos + cuotas + sueldo'}
                </div>
              </div>
              <div style={{ textAlign:'right' }}>
                <div style={{ fontSize:10, fontWeight:700, color:'var(--t5)', textTransform:'uppercase', letterSpacing:'0.4px' }}>
                  {projection.isFuture ? 'Saldo estimado' : 'Cierre estimado'}
                </div>
                <div style={{ fontSize:22, fontWeight:900, color: projection.expected.net >= 0 ? 'var(--success)' : 'var(--danger)', fontVariantNumeric:'tabular-nums', letterSpacing:'-0.5px' }}>
                  {projection.expected.net >= 0 ? '+' : '−'}{fmt(Math.abs(projection.expected.net))}
                </div>
              </div>
            </div>

            <div style={{ display:'grid', gridTemplateColumns:'repeat(3,1fr)', gap:10 }}>
              <div style={{ background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:'var(--r-md)', padding:'10px 12px' }}>
                <div style={{ fontSize:10, color:'var(--t5)', fontWeight:700, textTransform:'uppercase', letterSpacing:'0.4px', marginBottom:4 }}>Ingresos esperados</div>
                <div style={{ fontSize:15, fontWeight:800, color:'var(--success)', fontVariantNumeric:'tabular-nums' }}>+{fmt(projection.expected.income)}</div>
                {projection.real.income > 0 && (
                  <div style={{ fontSize:10, color:'var(--t5)', marginTop:2 }}>{fmt(projection.real.income)} ya · +{fmt(projection.projected.income)} por venir</div>
                )}
              </div>
              <div style={{ background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:'var(--r-md)', padding:'10px 12px' }}>
                <div style={{ fontSize:10, color:'var(--t5)', fontWeight:700, textTransform:'uppercase', letterSpacing:'0.4px', marginBottom:4 }}>Gastos esperados</div>
                <div style={{ fontSize:15, fontWeight:800, color:'var(--danger)', fontVariantNumeric:'tabular-nums' }}>−{fmt(projection.expected.expense)}</div>
                {projection.real.expense > 0 && (
                  <div style={{ fontSize:10, color:'var(--t5)', marginTop:2 }}>{fmt(projection.real.expense)} ya · −{fmt(projection.projected.expense)} por venir</div>
                )}
              </div>
              <div style={{ background:'var(--accent-muted)', border:'1px solid var(--accent)', borderRadius:'var(--r-md)', padding:'10px 12px' }}>
                <div style={{ fontSize:10, color:'var(--accent)', fontWeight:700, textTransform:'uppercase', letterSpacing:'0.4px', marginBottom:4 }}>Por venir</div>
                <div style={{ fontSize:13, fontWeight:700, color:'var(--accent-text)' }}>
                  {projection.projected.items.incomes.length} ingresos<br/>
                  {projection.projected.items.expenses.length} gastos
                </div>
              </div>
            </div>
          </div>
        </div>
      )}

      {/* ── Metas de ahorro — resumen compacto ── */}
      {(data.goals || []).length > 0 && (
        <div style={{ padding: '12px 20px 0' }}>
          <div style={{
            background: 'var(--surface)', border: '1px solid var(--border)',
            borderRadius: 'var(--r-xl)', boxShadow: 'var(--sh-sm)', padding: '18px 20px',
          }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 14 }}>
              <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--t1)' }}>Metas de ahorro</div>
              <button onClick={() => setScreen('savings')}
                style={{ background: 'none', border: 'none', color: 'var(--accent)', fontSize: 12, fontWeight: 700, display: 'flex', alignItems: 'center', gap: 3, cursor: 'pointer', fontFamily: 'var(--font)' }}>
                Ver todas <Icon name="chevronRight" size={13} color="var(--accent)" />
              </button>
            </div>

            {/* Recordatorio del plan: si un período no está cubierto, avisar acá (primera pantalla) */}
            {(() => {
              if (typeof goalPlanStatus !== 'function') return null;
              const due = (data.goals || []).map(g => ({ g, st: goalPlanStatus(g) })).filter(x => x.st && !x.st.done && !x.st.covered);
              if (!due.length) return null;
              const f = due[0];
              return (
                <button onClick={() => setScreen('savings')}
                  style={{
                    width: '100%', display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12,
                    background: 'var(--warning-bg)', border: '1px solid var(--warning)',
                    borderRadius: 'var(--r-md)', padding: '9px 12px', cursor: 'pointer',
                    fontFamily: 'var(--font)', textAlign: 'left',
                  }}>
                  <Icon name="bell" size={14} color="var(--warning)" strokeWidth={2} />
                  <span style={{ flex: 1, fontSize: 12, color: 'var(--warning-text)', fontWeight: 600, lineHeight: 1.4 }}>
                    {f.st.period} te toca guardar <b style={{ fontVariantNumeric: 'tabular-nums' }}>{fmtFull(f.st.amount)}</b> para {f.g.name}{due.length > 1 ? ` (+${due.length - 1} más)` : ''}
                  </span>
                  <Icon name="chevronRight" size={14} color="var(--warning)" />
                </button>
              );
            })()}

            <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
              {(data.goals || []).slice(0, 2).map(g => {
                const saved = (typeof goalSaved === 'function') ? goalSaved(g) : 0;
                const pct = g.target > 0 ? Math.min(100, Math.round((saved / g.target) * 100)) : 0;
                const done = saved >= g.target;
                return (
                  <div key={g.id} style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
                    <div style={{ width: 34, height: 34, borderRadius: 'var(--r-md)', background: done ? 'var(--success-bg)' : 'var(--accent-muted)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                      <Icon name={g.iconName || 'piggyBank'} size={16} color={done ? 'var(--success)' : 'var(--accent)'} strokeWidth={1.8} />
                    </div>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, marginBottom: 5 }}>
                        <span style={{ fontSize: 12, fontWeight: 700, color: 'var(--t2)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{g.name}</span>
                        <span style={{ fontSize: 12, fontWeight: 800, color: done ? 'var(--success)' : 'var(--accent)', fontVariantNumeric: 'tabular-nums', flexShrink: 0 }}>{pct}%</span>
                      </div>
                      <div style={{ height: 6, background: 'var(--track, var(--surface-2))', borderRadius: 99, overflow: 'hidden' }}>
                        <div style={{ width: `${pct}%`, height: '100%', background: done ? 'var(--success)' : 'var(--accent)', borderRadius: 99 }} />
                      </div>
                    </div>
                  </div>
                );
              })}
            </div>
          </div>
        </div>
      )}

      {/* ── Gráfico compacto: gastos por categoría ── */}
      {catEntries.length > 0 && (
        <div style={{ padding: '12px 20px 0' }}>
          <div style={{
            background: 'var(--surface)', border: '1px solid var(--border)',
            borderRadius: 'var(--r-xl)', boxShadow: 'var(--sh-sm)', padding: '18px 20px',
          }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 14 }}>
              <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--t1)' }}>Gastos por categoría</div>
              <button onClick={() => setScreen('budget')}
                style={{ background: 'none', border: 'none', color: 'var(--accent)', fontSize: 12, fontWeight: 700, display: 'flex', alignItems: 'center', gap: 3 }}>
                Ver todo <Icon name="chevronRight" size={13} color="var(--accent)" />
              </button>
            </div>

            <div style={{ display: 'flex', alignItems: 'center', gap: 18 }}>
              {/* Donut compacto */}
              <div style={{ position: 'relative', width: 110, height: 110, flexShrink: 0 }}>
                <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', zIndex: 1, pointerEvents: 'none' }}>
                  <div style={{ fontSize: 15, fontWeight: 800, color: 'var(--t1)', letterSpacing: '-0.3px', fontVariantNumeric: 'tabular-nums' }}>{fmt(expenses)}</div>
                  <div style={{ fontSize: 10, color: 'var(--t5)', fontWeight: 600 }}>total</div>
                </div>
                <CategoryDonutDS transactions={curTx} redraw={chartKey} />
              </div>

              {/* Leyenda */}
              <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 7 }}>
                {catEntries.map(([cat, amt]) => {
                  const pct = expenses > 0 ? Math.round((amt/expenses)*100) : 0;
                  const meta = getCategoryMeta(cat);
                  return (
                    <div key={cat} style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                      <div style={{ width: 8, height: 8, borderRadius: '50%', background: meta.color, flexShrink: 0 }} />
                      <span style={{ fontSize: 12, color: 'var(--t3)', flex: 1, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{cat}</span>
                      <span style={{ fontSize: 12, fontWeight: 700, color: 'var(--t2)', fontVariantNumeric: 'tabular-nums' }}>{fmt(amt)}</span>
                      <span style={{ fontSize: 11, color: 'var(--t5)', minWidth: 30, textAlign: 'right' }}>{pct}%</span>
                    </div>
                  );
                })}
              </div>
            </div>
          </div>
        </div>
      )}

      {/* ── Movimientos recientes (prioritario) ── */}
      <div style={{ padding: '12px 20px 0' }}>
        <div style={{
          background: 'var(--surface)', border: '1px solid var(--border)',
          borderRadius: 'var(--r-xl)', boxShadow: 'var(--sh-sm)', overflow: 'hidden',
        }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '16px 18px 12px' }}>
            <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--t1)' }}>Movimientos recientes</div>
            <button onClick={() => setScreen('transactions')}
              style={{ background: 'none', border: 'none', color: 'var(--accent)', fontSize: 12, fontWeight: 700, display: 'flex', alignItems: 'center', gap: 3 }}>
              Ver todos <Icon name="chevronRight" size={13} color="var(--accent)" />
            </button>
          </div>

          {recent.length === 0 ? (
            <div style={{ padding: '40px 20px', textAlign: 'center', color: 'var(--t5)', fontSize: 13 }}>
              <Icon name="receipt" size={32} color="var(--t6)" />
              <div style={{ marginTop: 8 }}>Sin movimientos aún</div>
            </div>
          ) : recent.map((t, i) => {
            const meta = getCategoryMeta(t.category);
            return (
              <div key={t.id}
                style={{
                  display: 'flex', alignItems: 'center', gap: 12,
                  padding: '11px 18px',
                  borderTop: '1px solid var(--border)',
                  transition: 'background 0.15s', cursor: 'default',
                }}
                onMouseEnter={e => e.currentTarget.style.background='var(--surface-2)'}
                onMouseLeave={e => e.currentTarget.style.background=''}>

                {/* Icono categoría */}
                <CategoryIcon category={t.category} size="sm" />

                {/* Info */}
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--t1)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                    {t.description}
                  </div>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginTop: 2 }}>
                    <span style={{ fontSize: 11, color: 'var(--t5)' }}>
                      {new Date(t.date+'T00:00:00').toLocaleDateString('es-AR',{day:'numeric',month:'short'})}
                    </span>
                    <span style={{ fontSize: 11, color: meta.color, background: meta.bg, borderRadius: 'var(--r-full)', padding: '1px 7px', fontWeight: 700 }}>
                      {t.category}
                    </span>
                  </div>
                </div>

                {/* Monto */}
                <div style={{
                  fontSize: 14, fontWeight: 800,
                  color: t.type === 'income' ? 'var(--success)' : 'var(--t1)',
                  fontVariantNumeric: 'tabular-nums', flexShrink: 0,
                }}>
                  {t.type === 'income' ? '+' : '–'}{fmt(t.amount)}
                </div>
              </div>
            );
          })}

        </div>
      </div>

      {/* ── FAB — abre TxDrawer global sin cambiar de pantalla ── */}
      <button className="fab fab-fixed" onClick={openNewTx || (() => setScreen('transactions'))} aria-label="Nueva transacción">
        <Icon name="plus" size={24} color="#fff" strokeWidth={2.5} />
      </button>
    </div>
  );
};

Object.assign(window, { Dashboard });
