// Rumbo — Reports · v3 · Insights de texto + gráfico ahorro con degradado

const { useRef: useRfR, useEffect: useEffR, useState: useStR } = React;

/* ── Gráfico Ingresos vs Gastos (barras, clickeables → navegan a mes) ── */
const BarChart = ({ transactions, theme, onMonthClick }) => {
  const ref = useRfR(null); const ch = useRfR(null);
  const monthsRef = useRfR([]);
  useEffR(() => {
    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 months = [];
      for (let i = 11; i >= 0; i--) {
        const d = new Date(); d.setDate(1); d.setMonth(d.getMonth()-i);
        months.push(`${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}`);
      }
      monthsRef.current = months;
      const labels  = months.map(m => { const [,mo]=m.split('-'); return new Date(2000,parseInt(mo)-1,1).toLocaleDateString('es-AR',{month:'short'}); });
      const incData = months.map(m => transactions.filter(t=>t.type==='income'&&t.date.startsWith(m)).reduce((s,t)=>s+t.amount,0));
      const expData = months.map(m => transactions.filter(t=>t.type==='expense'&&t.date.startsWith(m)).reduce((s,t)=>s+t.amount,0));

      const dark = theme==='dark';
      ch.current = new window.Chart(ref.current, {
        type: 'bar',
        data: {
          labels,
          datasets: [
            { label:'Ingresos', data:incData, backgroundColor:dark?'rgba(52,211,153,0.22)':'rgba(5,150,105,0.15)',  borderColor:dark?'#34D399':'#059669', borderWidth:2, borderRadius:6 },
            { label:'Gastos',   data:expData, backgroundColor:dark?'rgba(248,113,113,0.22)':'rgba(220,38,38,0.12)',   borderColor:dark?'#F87171':'#DC2626', borderWidth:2, borderRadius:6 },
          ]
        },
        options: {
          responsive:true, maintainAspectRatio:false,
          plugins: {
            legend: { labels:{ color:dark?'#94A3B8':'#64748B', font:{size:11,family:"'Outfit'"}, boxWidth:10, padding:14 } },
            tooltip: { backgroundColor:dark?'#1E2030':'#334155', titleColor:dark?'#94A3B8':'#CBD5E1', bodyColor:'#F1F5F9', cornerRadius:10, padding:10, callbacks:{ label:ctx=>` ${fmtFull(ctx.raw)}` } }
          },
          scales: {
            x: { grid:{color:dark?'rgba(255,255,255,0.06)':'rgba(100,116,139,0.10)'}, ticks:{color:dark?'#64748B':'#94A3B8',font:{size:11,family:"'Outfit'"}} },
            y: { grid:{color:dark?'rgba(255,255,255,0.06)':'rgba(100,116,139,0.10)'}, ticks:{color:dark?'#64748B':'#94A3B8',font:{size:11,family:"'Outfit'"},callback:v=>`$${(v/1000).toFixed(0)}K`} }
          },
          interaction:{mode:'index',intersect:false},
          onClick: (evt, elems) => {
            if (!elems.length || !onMonthClick) return;
            const idx = elems[0].index;
            const m = monthsRef.current[idx];
            if (m) onMonthClick(m);
          },
          onHover: (evt, elems) => {
            if (!evt.native?.target) return;
            evt.native.target.style.cursor = elems.length ? 'pointer' : 'default';
          },
        }
      });
    };
    init();
    return () => { if (ch.current) { ch.current.destroy(); ch.current=null; } };
  }, [transactions, theme, onMonthClick]);
  return <canvas ref={ref} style={{ width:'100%', height:'100%' }} />;
};

/* ── Gráfico ahorro acumulado con degradado vibrante ── */
const SavingsChart = ({ transactions, theme }) => {
  const ref = useRfR(null); const ch = useRfR(null);
  useEffR(() => {
    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 months = [];
      for (let i = 11; i >= 0; i--) {
        const d = new Date(); d.setDate(1); d.setMonth(d.getMonth()-i);
        months.push(`${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}`);
      }
      const labels = months.map(m => { const [,mo]=m.split('-'); return new Date(2000,parseInt(mo)-1,1).toLocaleDateString('es-AR',{month:'short'}); });

      let cumSaving = 0;
      const savData = months.map(m => {
        const inc = transactions.filter(t=>t.type==='income'&&t.date.startsWith(m)).reduce((s,t)=>s+t.amount,0);
        const exp = transactions.filter(t=>t.type==='expense'&&t.date.startsWith(m)).reduce((s,t)=>s+t.amount,0);
        cumSaving += (inc - exp);
        return Math.max(0, cumSaving);
      });
      const maxSav = Math.max(...savData, 1);
      const goalLine = savData.map(() => maxSav * 0.8); // meta al 80% del máximo alcanzado

      const dark = theme==='dark';
      const canvas = ref.current;
      const ctx    = canvas.getContext('2d');
      const grad   = ctx.createLinearGradient(0, 0, 0, 220);
      grad.addColorStop(0,  dark ? 'rgba(59,130,246,0.45)' : 'rgba(37,99,235,0.30)');
      grad.addColorStop(1,  dark ? 'rgba(59,130,246,0.02)' : 'rgba(37,99,235,0.02)');

      ch.current = new window.Chart(canvas, {
        type: 'line',
        data: {
          labels,
          datasets: [
            {
              label: 'Ahorro acumulado', data: savData,
              borderColor: dark ? '#60A5FA' : '#2563EB',
              backgroundColor: grad,
              tension: 0.45, fill: true, borderWidth: 2.5,
              pointRadius: 4, pointBackgroundColor: dark?'#60A5FA':'#2563EB',
              pointBorderColor: dark?'#11121C':'#fff', pointBorderWidth: 2,
              pointHoverRadius: 6,
            },
            {
              label: 'Meta', data: goalLine,
              borderColor: dark?'rgba(251,191,36,0.7)':'rgba(217,119,6,0.6)',
              borderWidth: 1.5, borderDash: [5,4],
              pointRadius: 0, fill: false, tension: 0,
            }
          ]
        },
        options: {
          responsive:true, maintainAspectRatio:false,
          plugins: {
            legend: { labels:{ color:dark?'#94A3B8':'#64748B', font:{size:11,family:"'Outfit'"}, boxWidth:10, padding:14, usePointStyle:true } },
            tooltip: { backgroundColor:dark?'#1E2030':'#334155', titleColor:dark?'#94A3B8':'#CBD5E1', bodyColor:'#F1F5F9', cornerRadius:10, padding:10, callbacks:{ label:ctx=>` ${fmtFull(ctx.raw)}` } }
          },
          scales: {
            x: { grid:{color:dark?'rgba(255,255,255,0.06)':'rgba(100,116,139,0.10)'}, ticks:{color:dark?'#64748B':'#94A3B8',font:{size:11,family:"'Outfit'"}} },
            y: { grid:{color:dark?'rgba(255,255,255,0.06)':'rgba(100,116,139,0.10)'}, ticks:{color:dark?'#64748B':'#94A3B8',font:{size:11,family:"'Outfit'"},callback:v=>`$${(v/1000).toFixed(0)}K`} }
          },
          interaction:{mode:'index',intersect:false}
        }
      });
    };
    init();
    return () => { if (ch.current) { ch.current.destroy(); ch.current=null; } };
  }, [transactions, theme]);
  return <canvas ref={ref} style={{ width:'100%', height:'100%' }} />;
};

/* ── Matriz categoría × mes — la tabla que la gente arma a mano en Excel, hecha sola ── */
const CatMonthMatrix = ({ transactions }) => {
  const months = [];
  for (let i = 5; i >= 0; i--) {
    const d = new Date(); d.setDate(1); d.setMonth(d.getMonth() - i);
    months.push(`${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`);
  }
  const byCat = {};
  transactions
    .filter(t => t.type === 'expense' && months.some(m => (t.date || '').startsWith(m)))
    .forEach(t => {
      const m = t.date.slice(0, 7);
      if (!byCat[t.category]) byCat[t.category] = { total: 0 };
      byCat[t.category][m] = (byCat[t.category][m] || 0) + t.amount;
      byCat[t.category].total += t.amount;
    });
  const cats = Object.entries(byCat).sort((a, b) => b[1].total - a[1].total).slice(0, 8);
  if (cats.length < 2) return null;

  const maxCell = Math.max(...cats.flatMap(([, row]) => months.map(m => row[m] || 0)), 1);
  const monthLbl = (m) => { const [, mo] = m.split('-'); return new Date(2000, parseInt(mo) - 1, 1).toLocaleDateString('es-AR', { month: 'short' }); };
  const totals = months.map(m => cats.reduce((s, [, row]) => s + (row[m] || 0), 0));

  // Tendencia: último mes completo vs promedio de los meses anteriores con datos
  const trendFor = (row) => {
    const lastFull = months[months.length - 2];
    const prior = months.slice(0, months.length - 2).map(m => row[m] || 0).filter(v => v > 0);
    if (!prior.length || !(row[lastFull] > 0)) return null;
    const avg = prior.reduce((s, v) => s + v, 0) / prior.length;
    return Math.round(((row[lastFull] - avg) / avg) * 100);
  };

  const th = { padding: '8px 10px', fontSize: 10, fontWeight: 700, color: 'var(--t5)', textTransform: 'uppercase', letterSpacing: '0.4px', textAlign: 'right', whiteSpace: 'nowrap', borderBottom: '1px solid var(--border)' };
  const td = { padding: '8px 10px', fontSize: 12, textAlign: 'right', fontVariantNumeric: 'tabular-nums', whiteSpace: 'nowrap' };

  return (
    <div style={{ background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--r-xl)', padding: '18px 20px', marginTop: 14, boxShadow: 'var(--sh-sm)' }}>
      <div style={{ marginBottom: 6 }}>
        <div style={{ fontSize: 14, fontWeight: 700, color: 'var(--t1)' }}>Categoría por mes</div>
        <div style={{ fontSize: 11, color: 'var(--t4)', marginTop: 2 }}>Los últimos 6 meses, celda por celda — la planilla que ya no tenés que armar</div>
      </div>
      <div style={{ overflowX: 'auto' }}>
        <table style={{ borderCollapse: 'collapse', width: '100%', minWidth: 540 }}>
          <thead>
            <tr>
              <th style={{ ...th, textAlign: 'left' }}>Categoría</th>
              {months.map(m => <th key={m} style={{ ...th, textTransform: 'capitalize' }}>{monthLbl(m)}</th>)}
              <th style={th}>Tend.</th>
            </tr>
          </thead>
          <tbody>
            {cats.map(([cat, row]) => {
              const tr = trendFor(row);
              return (
                <tr key={cat}>
                  <td style={{ ...td, textAlign: 'left', fontWeight: 700, color: 'var(--t2)' }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                      <span style={{ width: 8, height: 8, borderRadius: '50%', background: getCategoryColor(cat), flexShrink: 0 }} />
                      {cat}
                    </div>
                  </td>
                  {months.map(m => {
                    const v = row[m] || 0;
                    const heat = v > 0 ? Math.round(5 + (v / maxCell) * 20) : 0;
                    return (
                      <td key={m} style={{ ...td, color: v > 0 ? 'var(--t2)' : 'var(--t5)', background: v > 0 ? `color-mix(in srgb, var(--danger) ${heat}%, transparent)` : 'transparent' }}>
                        {v > 0 ? fmt(v) : '—'}
                      </td>
                    );
                  })}
                  <td style={td}>
                    {tr === null ? <span style={{ color: 'var(--t5)' }}>—</span> : (
                      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 3, fontWeight: 800, color: tr > 10 ? 'var(--danger)' : tr < -10 ? 'var(--success)' : 'var(--t4)' }}>
                        <Icon name={tr > 10 ? 'trending' : tr < -10 ? 'trendingDown' : 'moreH'} size={12} color={tr > 10 ? 'var(--danger)' : tr < -10 ? 'var(--success)' : 'var(--t4)'} strokeWidth={2} />
                        {tr > 0 ? '+' : ''}{tr}%
                      </span>
                    )}
                  </td>
                </tr>
              );
            })}
            <tr>
              <td style={{ ...td, textAlign: 'left', fontWeight: 900, color: 'var(--t1)', borderTop: '1px solid var(--border)' }}>Total</td>
              {totals.map((v, i) => (
                <td key={i} style={{ ...td, fontWeight: 900, color: 'var(--t1)', borderTop: '1px solid var(--border)' }}>{v > 0 ? fmt(v) : '—'}</td>
              ))}
              <td style={{ ...td, borderTop: '1px solid var(--border)' }} />
            </tr>
          </tbody>
        </table>
      </div>
    </div>
  );
};

/* ── Pantalla Reportes ── */
const Reports = ({ data, theme, toggleTheme, selectedMonth, setSelectedMonth, setScreen, openNewTx }) => {
  const { transactions, accounts, debts } = data;
  const [chartKey, setChartKey] = useStR(0);
  useEffR(() => setChartKey(k=>k+1), [theme]);

  const curMonth  = selectedMonth || CURRENT_MONTH;
  const prevMonth = (typeof getPrevMonth === 'function') ? getPrevMonth(curMonth) : PREV_MONTH;

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

  // Mes seleccionado vs anterior
  const curTx  = transactions.filter(t=>t.date.startsWith(curMonth));
  const prevTx = transactions.filter(t=>t.date.startsWith(prevMonth));

  const curInc  = curTx.filter(t=>t.type==='income').reduce((s,t)=>s+t.amount,0);
  const curExp  = curTx.filter(t=>t.type==='expense').reduce((s,t)=>s+t.amount,0);
  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 curSaving  = curInc  - curExp;
  const prevSaving = prevInc - prevExp;
  const curRate    = curInc  > 0 ? Math.round((curSaving/curInc)*100)  : 0;
  const prevRate   = prevInc > 0 ? Math.round((prevSaving/prevInc)*100): 0;

  const trendExp  = prevExp > 0  ? Math.round(((curExp-prevExp)/prevExp)*100)   : null;
  const trendSav  = prevSaving > 0 ? Math.round(((curSaving-prevSaving)/prevSaving)*100) : null;

  // KPIs anuales
  const allInc  = transactions.filter(t=>t.type==='income').reduce((s,t)=>s+t.amount,0);
  const allExp  = transactions.filter(t=>t.type==='expense').reduce((s,t)=>s+t.amount,0);
  const annualSaving = allInc - allExp;
  const avgMonthly   = Math.round(allInc/Math.max(1,12));
  const annualRate   = allInc>0 ? Math.round((annualSaving/allInc)*100) : 0;

  // Insight de gasto actual vs promedio
  const avgExp6 = (() => {
    let total = 0, cnt = 0;
    for (let i = 1; i <= 6; i++) {
      const d = new Date(); d.setDate(1); d.setMonth(d.getMonth()-i);
      const key = `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}`;
      const mExp = transactions.filter(t=>t.type==='expense'&&t.date.startsWith(key)).reduce((s,t)=>s+t.amount,0);
      if (mExp > 0) { total+=mExp; cnt++; }
    }
    return cnt>0 ? total/cnt : 0;
  })();

  const expDiff = avgExp6>0 ? Math.round(((curExp-avgExp6)/avgExp6)*100) : null;

  const spendInsight = expDiff === null ? null
    : expDiff <= -10 ? { type:'good', icon:'sparkles', title:'¡Vas muy bien!', msg:`Gastaste ${Math.abs(expDiff)}% menos que tu promedio de los últimos 6 meses.` }
    : expDiff <=  5  ? { type:'info', icon:'info',      title:'Ritmo normal', msg:`Tus gastos están en línea con tu promedio histórico.` }
    : expDiff <= 20  ? { type:'warn', icon:'alertTriangle', title:'Atención al gasto', msg:`Gastaste ${expDiff}% más que tu promedio. Podría afectar tu ahorro.` }
    : { type:'bad', icon:'alertCircle', title:'Gasto elevado', msg:`Estás gastando ${expDiff}% por encima de tu promedio. Revisá tus categorías.` };

  const savInsight = trendSav === null ? null
    : trendSav >= 15 ? { type:'good', icon:'trending',  title:'Ahorro en alza',    msg:`Ahorraste ${trendSav}% más que el mes pasado. ¡Seguí así!` }
    : trendSav >= 0  ? { type:'info', icon:'info',      title:'Ahorro estable', msg:`Tu ahorro se mantiene respecto al mes anterior.` }
    : { type:'warn', icon:'trendingDown', title:'Ahorro a la baja', msg:`Ahorraste ${Math.abs(trendSav)}% menos que el mes pasado. Identificá qué categoría subió.` };

  // ── "Rumbo te cuenta" — lo que ningún Excel te dice solo ──
  const tales = [];
  const curExpTx = curTx.filter(t => t.type === 'expense');
  if (curExpTx.length > 0) {
    const bycatCur = {};
    curExpTx.forEach(t => { bycatCur[t.category] = (bycatCur[t.category] || 0) + t.amount; });
    const top = Object.entries(bycatCur).sort((a, b) => b[1] - a[1])[0];
    tales.push({ icon: 'pieChart', text: <>Tu mayor gasto del mes: <b>{top[0]}</b> — {fmtFull(top[1])}, el {Math.round((top[1] / curExp) * 100)}% de todo lo que gastaste.</> });

    const bycatPrev = {};
    prevTx.filter(t => t.type === 'expense').forEach(t => { bycatPrev[t.category] = (bycatPrev[t.category] || 0) + t.amount; });
    let worst = null;
    Object.entries(bycatCur).forEach(([c, v]) => {
      const p = bycatPrev[c] || 0;
      if (p > 0) { const d = (v - p) / p; if (!worst || d > worst.d) worst = { c, d, v, p }; }
    });
    if (worst && worst.d >= 0.15) {
      tales.push({ icon: 'trending', text: <><b>{worst.c}</b> subió {Math.round(worst.d * 100)}% contra el mes pasado: {fmtFull(worst.p)} → {fmtFull(worst.v)}.</> });
    }

    const byday = {};
    curExpTx.forEach(t => { byday[t.date] = (byday[t.date] || 0) + t.amount; });
    if (Object.keys(byday).length >= 3) {
      const [maxDay, maxAmt] = Object.entries(byday).sort((a, b) => b[1] - a[1])[0];
      tales.push({ icon: 'calendar', text: <>Tu día más caro fue el <b>{new Date(maxDay + 'T00:00:00').toLocaleDateString('es-AR', { day: 'numeric', month: 'long' })}</b>: {fmtFull(maxAmt)} en un solo día.</> });
    }

    const incomeRef = Number(data.settings?.monthlyIncome) || 0;
    const antThreshold = incomeRef > 0 ? Math.round(incomeRef * 0.02) : 15000;
    const ants = curExpTx.filter(t => t.amount <= antThreshold);
    if (ants.length >= 4) {
      tales.push({ icon: 'receipt', text: <>{ants.length} gastos chicos (hasta {fmt(antThreshold)}) sumaron <b>{fmtFull(ants.reduce((s, t) => s + t.amount, 0))}</b>. Los gastos hormiga también hacen agujero.</> });
    }

    if (curMonth === CURRENT_MONTH) {
      const dayN = new Date().getDate();
      if (dayN >= 3) {
        const lastDayN = new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0).getDate();
        const rate = curExp / dayN;
        tales.push({ icon: 'gauge', text: <>Venís gastando <b>{fmt(rate)}/día</b>. A este ritmo, el mes cierra con {fmt(rate * lastDayN)} de gasto.</> });
      }
    }
  }

  // Top categorías
  const bycat = {};
  transactions.filter(t=>t.type==='expense').forEach(t=>{ bycat[t.category]=(bycat[t.category]||0)+t.amount; });
  const topCats = Object.entries(bycat).sort((a,b)=>b[1]-a[1]).slice(0,6);
  const totalExp2 = topCats.reduce((s,[,v])=>s+v,0);

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

      {/* Header */}
      <div className="screen-header">
        <div>
          <h1 className="screen-title">Reportes</h1>
          <p className="screen-sub">Análisis de tus finanzas · últimos 12 meses</p>
        </div>
        <div style={{ display:'flex', gap:8, flexWrap:'wrap', justifyContent:'flex-end' }}>
          {setSelectedMonth && (
            <MonthSwitcher value={curMonth} onChange={setSelectedMonth} transactions={transactions} compact />
          )}
          <button className="theme-toggle" onClick={toggleTheme}>
            <Icon name={theme==='dark'?'sun':'moon'} size={15} color="var(--t3)" />
          </button>
        </div>
      </div>

      <div style={{ padding:'14px 20px 0' }}>

        {/* ── Insights de texto ── */}
        {spendInsight && (
          <div className={`insight ${spendInsight.type}`}>
            <div className="insight-icon" style={{
              background: spendInsight.type==='good'?'var(--success-bg)':spendInsight.type==='warn'?'var(--warning-bg)':spendInsight.type==='bad'?'var(--danger-bg)':'var(--accent-muted)'
            }}>
              <Icon name={spendInsight.icon} size={18}
                color={spendInsight.type==='good'?'var(--success)':spendInsight.type==='warn'?'var(--warning)':spendInsight.type==='bad'?'var(--danger)':'var(--accent)'}
              />
            </div>
            <div>
              <div style={{ fontSize:13, fontWeight:700, color:spendInsight.type==='good'?'var(--success-text)':spendInsight.type==='warn'?'var(--warning-text)':spendInsight.type==='bad'?'var(--danger-text)':'var(--accent-text)' }}>
                {spendInsight.title}
              </div>
              <div style={{ fontSize:12, color:'var(--t3)', marginTop:3, lineHeight:1.5 }}>{spendInsight.msg}</div>
            </div>
          </div>
        )}
        {savInsight && (
          <div className={`insight ${savInsight.type}`}>
            <div className="insight-icon" style={{
              background: savInsight.type==='good'?'var(--success-bg)':savInsight.type==='warn'?'var(--warning-bg)':'var(--accent-muted)'
            }}>
              <Icon name={savInsight.icon} size={18}
                color={savInsight.type==='good'?'var(--success)':savInsight.type==='warn'?'var(--warning)':'var(--accent)'}
              />
            </div>
            <div>
              <div style={{ fontSize:13, fontWeight:700, color:savInsight.type==='good'?'var(--success-text)':savInsight.type==='warn'?'var(--warning-text)':'var(--accent-text)' }}>
                {savInsight.title}
              </div>
              <div style={{ fontSize:12, color:'var(--t3)', marginTop:3, lineHeight:1.5 }}>{savInsight.msg}</div>
            </div>
          </div>
        )}

        {/* ── Rumbo te cuenta — insights automáticos en criollo ── */}
        {tales.length > 0 && (
          <div style={{ background:'var(--surface)', border:'1px solid var(--border)', borderRadius:'var(--r-xl)', padding:'18px 20px', marginBottom:14, boxShadow:'var(--sh-sm)' }}>
            <div style={{ display:'flex', alignItems:'center', gap:8, marginBottom:14 }}>
              <div style={{ width:28, height:28, borderRadius:'var(--r-md)', background:'var(--accent-muted)', display:'flex', alignItems:'center', justifyContent:'center' }}>
                <Icon name="compass" size={15} color="var(--accent)" strokeWidth={1.8} />
              </div>
              <div>
                <div style={{ fontSize:14, fontWeight:700, color:'var(--t1)' }}>Rumbo te cuenta</div>
                <div style={{ fontSize:11, color:'var(--t5)' }}>Lo que tus números dicen este mes, sin que tengas que buscarlo</div>
              </div>
            </div>
            <div style={{ display:'flex', flexDirection:'column', gap:10 }}>
              {tales.slice(0, 4).map((t, i) => (
                <div key={i} style={{ display:'flex', gap:10, alignItems:'flex-start' }}>
                  <div style={{ width:26, height:26, borderRadius:'var(--r-md)', background:'var(--surface-2)', border:'1px solid var(--border)', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>
                    <Icon name={t.icon} size={13} color="var(--t3)" strokeWidth={1.8} />
                  </div>
                  <div style={{ fontSize:12.5, color:'var(--t2)', lineHeight:1.55, paddingTop:3 }}>{t.text}</div>
                </div>
              ))}
            </div>
          </div>
        )}

        {/* ── KPIs anuales ── */}
        <div style={{ display:'grid', gridTemplateColumns:'repeat(4,1fr)', gap:10, marginBottom:14 }} className="stats-grid-4">
          {[
            { l:'Ingreso prom./mes', v:fmt(avgMonthly),      c:'var(--success)' },
            { l:'Gasto anual',       v:fmt(allExp),           c:'var(--danger)'  },
            { l:'Ahorro anual',      v:fmt(annualSaving),     c:'var(--accent)'  },
            { l:'Tasa de ahorro',    v:`${annualRate}%`,      c:annualRate>=20?'var(--success)':annualRate>=10?'var(--warning)':'var(--danger)' },
          ].map(({l,v,c}) => (
            <div key={l} style={{ background:'var(--surface)', border:'1px solid var(--border)', borderRadius:'var(--r-lg)', padding:'14px 15px', boxShadow:'var(--sh-xs)' }}>
              <div style={{ fontSize:10, fontWeight:700, color:'var(--t5)', textTransform:'uppercase', letterSpacing:'0.4px', marginBottom:6 }}>{l}</div>
              <div style={{ fontSize:20, fontWeight:900, color:c, fontVariantNumeric:'tabular-nums', letterSpacing:'-0.4px' }}>{v}</div>
            </div>
          ))}
        </div>

        {/* ── Gráfico barras ── */}
        <div style={{ background:'var(--surface)', border:'1px solid var(--border)', borderRadius:'var(--r-xl)', padding:'18px 20px', marginBottom:14, boxShadow:'var(--sh-sm)' }}>
          <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:14 }}>
            <div style={{ fontSize:14, fontWeight:700, color:'var(--t1)' }}>Ingresos vs Gastos</div>
            <span style={{ fontSize:11, color:'var(--t5)' }}>Tap en una barra para ver ese mes</span>
          </div>
          <div style={{ height:200 }} key={`bar-${chartKey}`}>
            <BarChart transactions={transactions} theme={theme}
              onMonthClick={(m) => {
                if (setSelectedMonth) setSelectedMonth(m);
                if (setScreen) setScreen('transactions');
              }} />
          </div>
        </div>

        {/* ── Gráfico ahorro con degradado ── */}
        <div style={{ background:'var(--surface)', border:'1px solid var(--border)', borderRadius:'var(--r-xl)', padding:'18px 20px', marginBottom:14, boxShadow:'var(--sh-sm)' }}>
          <div style={{ display:'flex', justifyContent:'space-between', alignItems:'flex-start', marginBottom:14 }}>
            <div>
              <div style={{ fontSize:14, fontWeight:700, color:'var(--t1)' }}>Ahorro acumulado</div>
              <div style={{ fontSize:11, color:'var(--t4)', marginTop:2 }}>
                Línea discontinua = meta (80% del mejor mes)
              </div>
            </div>
            {trendSav !== null && (
              <span className={`badge badge-${trendSav>=0?'green':'red'}`}>
                <Icon name={trendSav>=0?'arrowUp':'arrowDown'} size={10} strokeWidth={2.5}
                  color={trendSav>=0?'var(--success-text)':'var(--danger-text)'} />
                {Math.abs(trendSav)}% vs mes ant.
              </span>
            )}
          </div>
          <div style={{ height:200 }} key={`sav-${chartKey}`}><SavingsChart transactions={transactions} theme={theme} /></div>
        </div>

        {/* ── Top categorías ── */}
        <div style={{ background:'var(--surface)', border:'1px solid var(--border)', borderRadius:'var(--r-xl)', padding:'18px 20px', boxShadow:'var(--sh-sm)' }}>
          <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:14 }}>
            <div style={{ fontSize:14, fontWeight:700, color:'var(--t1)' }}>Top categorías de gasto</div>
            <span style={{ fontSize:11, color:'var(--t5)' }}>Todo el historial</span>
          </div>
          <div style={{ display:'flex', flexDirection:'column', gap:12 }}>
            {topCats.map(([cat, amt]) => {
              const pct  = Math.round((amt/totalExp2)*100);
              const meta = getCategoryMeta(cat);
              return (
                <div key={cat}>
                  <div style={{ display:'flex', alignItems:'center', gap:10, marginBottom:7 }}>
                    <CategoryIcon category={cat} size="sm" />
                    <div style={{ flex:1 }}>
                      <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center' }}>
                        <span style={{ fontSize:13, fontWeight:600, color:'var(--t1)' }}>{cat}</span>
                        <div style={{ display:'flex', alignItems:'center', gap:8 }}>
                          <span style={{ fontSize:13, fontWeight:800, color:'var(--t2)', fontVariantNumeric:'tabular-nums' }}>{fmtFull(amt)}</span>
                          <span style={{ fontSize:11, color:'var(--t5)', minWidth:30, textAlign:'right' }}>{pct}%</span>
                        </div>
                      </div>
                    </div>
                  </div>
                  <div className="progress-track">
                    <div className="progress-fill" style={{ width:`${pct}%`, background:meta.color }} />
                  </div>
                </div>
              );
            })}
          </div>
        </div>

        {/* ── Matriz categoría × mes ── */}
        <CatMonthMatrix transactions={transactions} />
      </div>

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

Object.assign(window, { Reports });
