// EUTPeru — Admin: Contabilidad, Contactos, Historial, Usuarios
const { useState } = React;
const G = window.C;
const { T, Modal, FInput, FSelect, FTextarea, Row, Btn, Table, Card, Tabs, PageHeader, StatusBadge, DaysBadge, CreditBadge, Tag, DonutChart, BarChart, KPICard, fmtS } = window;

// ─── COMBO CHART (Barras + Línea + Grid + Tooltip) ───────────
function ComboChart({ data, height=150, highlight }) {
  const [tooltip, setTooltip] = React.useState(null);
  const mShort = ['Ene','Feb','Mar','Abr','May','Jun','Jul','Ago','Sep','Oct','Nov','Dic'];
  const chartData = data && data.length > 0 ? data : (() => {
    const now = new Date();
    return Array.from({length:6},(_,i)=>{
      const d = new Date(now.getFullYear(), now.getMonth()-5+i, 1);
      return {m:mShort[d.getMonth()], v:0, c:0};
    });
  })();
  const maxV = Math.max(...chartData.map(d=>Math.max(d.v,d.c||0)),1);
  const niceMax = Math.ceil(maxV / 10000) * 10000 || 10000;
  const gridSteps = [0.25, 0.5, 0.75, 1].map(f => Math.round(niceMax * f));
  const n = chartData.length;
  const W = 600; const pad = 46; const rightPad = 16;
  const slotW = (W - pad - rightPad) / n;
  const barW = slotW * 0.28;
  const yPos = (v) => height - 4 - (v / niceMax) * (height - 4);

  const pts = chartData.map((d,i) => {
    const cx = pad + slotW * i + slotW / 2;
    return { cx: cx + barW * 0.1 + barW / 2, cy: yPos(d.v) };
  });
  const linePath = pts.map((p,i) => `${i===0?'M':'L'}${p.cx},${p.cy}`).join(' ');

  return (
    <div style={{position:'relative',userSelect:'none'}}>
      <svg viewBox={`0 0 ${W} ${height + 24}`} width="100%" preserveAspectRatio="none" style={{overflow:'visible'}}>
        {/* Grid lines */}
        {gridSteps.map(v => {
          const y = yPos(v);
          return (
            <g key={v}>
              <line x1={pad} x2={W-rightPad} y1={y} y2={y} stroke={G.border} strokeWidth={0.8} strokeDasharray="4,4"/>
              <text x={pad-6} y={y+3} textAnchor="end" fill={G.textSec} fontSize={8} fontFamily="Inter">
                {v>=1000?`${(v/1000).toFixed(0)}k`:v}
              </text>
            </g>
          );
        })}
        {/* Baseline */}
        <line x1={pad} x2={W-rightPad} y1={height-4} y2={height-4} stroke={G.border} strokeWidth={1}/>

        {chartData.map((d,i) => {
          const cx = pad + slotW * i + slotW / 2;
          const isHl = !highlight || highlight === d.m;
          return (
            <g key={i}>
              {/* Compras bar */}
              <rect
                x={cx - barW * 1.1} y={yPos(d.c)} width={barW} height={height-4-yPos(d.c)}
                fill={G.border} rx={2} opacity={isHl ? 0.9 : 0.3}
                onMouseEnter={()=>setTooltip({m:d.m,v:d.v,c:d.c,x:cx,y:yPos(d.v)-10})}
                onMouseLeave={()=>setTooltip(null)}/>
              {/* Ventas bar */}
              <rect
                x={cx + barW * 0.1} y={yPos(d.v)} width={barW} height={height-4-yPos(d.v)}
                fill={G.accent} rx={2} opacity={isHl ? 0.85 : 0.25}
                onMouseEnter={()=>setTooltip({m:d.m,v:d.v,c:d.c,x:cx,y:yPos(d.v)-10})}
                onMouseLeave={()=>setTooltip(null)}/>
              {/* Line dot */}
              <circle cx={pts[i].cx} cy={pts[i].cy} r={3} fill={isHl?G.accent:'#333'} stroke={G.bg} strokeWidth={1.5}/>
              <text x={cx} y={height+16} textAnchor="middle" fill={isHl?G.textSec:'#333'} fontSize={9} fontFamily="Inter">{d.m}</text>
            </g>
          );
        })}
        {/* Trend line */}
        <path d={linePath} fill="none" stroke={G.accent} strokeWidth={1.5} opacity={0.6} strokeLinejoin="round"/>

        {/* Tooltip */}
        {tooltip && (
          <g>
            <rect x={tooltip.x - 48} y={tooltip.y - 36} width={96} height={38} rx={4} fill={G.card2} stroke={G.border} strokeWidth={0.8}/>
            <text x={tooltip.x} y={tooltip.y - 22} textAnchor="middle" fill={G.accent} fontSize={9} fontWeight="700" fontFamily="Inter">{tooltip.m}</text>
            <text x={tooltip.x} y={tooltip.y - 12} textAnchor="middle" fill={G.accent} fontSize={8} fontFamily="Inter">Ventas: S/ {Number(tooltip.v).toLocaleString()}</text>
            <text x={tooltip.x} y={tooltip.y - 2} textAnchor="middle" fill={G.textSec} fontSize={8} fontFamily="Inter">Compras: S/ {Number(tooltip.c).toLocaleString()}</text>
          </g>
        )}
      </svg>
    </div>
  );
}

// ─── CONTABILIDAD ─────────────────────────────────────────────
function Contabilidad({ quotes, setQuotes, contacts, monthly, products, users, currentUser, logActivity }) {
  const [tab, setTab] = useState('Ventas');
  const [year, setYear] = useState(String(new Date().getFullYear()));
  const [month, setMonth] = useState('todos');
  const [selClient, setSelClient] = useState('todos');
  const [selVendedor, setSelVendedor] = useState('todos');
  const [excludeCurrentMonth, setExcludeCurrentMonth] = useState(false);

  const monthlyData = (monthly && monthly.length) ? monthly : [];
  const canManagePay = currentUser?.role === 'Administrador' || !!currentUser?.perms?.gestionarPagos || !!currentUser?.perms?.contabilidad;
  const clientes = (contacts||[]).filter(c=>c.type==='cliente');

  // Años disponibles en monthly data
  const availYears = ['todos', ...[...new Set(monthlyData.filter(d=>d.y).map(d=>String(d.y)))].sort((a,b)=>+b-+a)];
  const meses = ['todos','Ene','Feb','Mar','Abr','May','Jun','Jul','Ago','Sep','Oct','Nov','Dic'];
  const mMap = {'01':'Ene','02':'Feb','03':'Mar','04':'Abr','05':'May','06':'Jun','07':'Jul','08':'Ago','09':'Sep','10':'Oct','11':'Nov','12':'Dic'};
  const mNum = {Ene:'01',Feb:'02',Mar:'03',Abr:'04',May:'05',Jun:'06',Jul:'07',Ago:'08',Sep:'09',Oct:'10',Nov:'11',Dic:'12'};
  const now = new Date();
  const currentYear = String(now.getFullYear());
  const currentMonthNum = String(now.getMonth() + 1).padStart(2,'0');
  const currentMonthName = mMap[currentMonthNum];
  const isCurrentPeriod = (m, y) => String(y||'') === currentYear && (m === currentMonthName || m === currentMonthNum);

  const [incluyeGastos, setIncluyeGastos] = useState(false);
  const [gastosLista, setGastosLista] = useState(null);

  const payCobrar = async (f) => {
    console.log('[Cobrar/Admin] Marcando pagada:', f.id);
    const res = await window.api(`/quotes/${f.id}/pay`, {method:'PUT'});
    console.log('[Cobrar/Admin] Respuesta:', res?.status, res?.ok);
    if(res && res.ok) {
      const updated = await res.json();
      if(setQuotes) setQuotes(qs=>qs.map(q=>q.id===updated.id?updated:q));
      if(logActivity) logActivity('Marcó como pagada','Facturación',`Factura ${f.invoice||f.id} — ${fmtS(f.amount)}`);
      if(window.refreshDashboard) window.refreshDashboard();
    } else if (res) {
      const err = await res.json().catch(()=>({}));
      console.error('[Cobrar/Admin] Error:', err);
      alert(err.error || `Error al marcar como pagada (${res.status})`);
    }
  };

  const unpayFn = async (f) => {
    console.log('[Unpay/Admin] Revirtiendo pago:', f.id);
    const res = await window.api(`/quotes/${f.id}/unpay`, {method:'PUT'});
    console.log('[Unpay/Admin] Respuesta:', res?.status, res?.ok);
    if(res && res.ok) {
      const updated = await res.json();
      if(setQuotes) setQuotes(qs=>qs.map(q=>q.id===updated.id?updated:q));
      if(logActivity) logActivity('Revirtió a pendiente','Facturación',`Factura ${f.invoice||f.id} — ${fmtS(f.amount)}`);
      if(window.refreshDashboard) window.refreshDashboard();
    } else if (res) {
      const err = await res.json().catch(()=>({}));
      console.error('[Unpay/Admin] Error:', err);
      alert(err.error || `Error al revertir pago (${res.status})`);
    }
  };

  const toggleGasto = async (id) => {
    const res = await window.api(`/gastos/${id}/toggle`, {method:'PATCH'});
    if(res && res.ok) {
      const updated = await res.json();
      setGastosLista(gs=>gs.map(g=>g.id===id?updated:g));
    }
  };

  const toggleGastos = async () => {
    if (!gastosLista) {
      const res = await window.api('/gastos');
      if (res && res.ok) {
        const data = await res.json();
        setGastosLista(data);
      }
    }
    setIncluyeGastos(v=>!v);
  };

  // Gastos filtrados por año/mes seleccionado (reactivo a los filtros)
  const gastosFiltered = (gastosLista||[]).filter(g => {
    if (g.recurring) return false;
    if (g.category === 'Compras') return false;
    const parts = (g.date||'').split('/');
    const gm = parts[1]||'';
    const gy = parts[2]||'';
    const matchY = year === 'todos' || gy === year;
    const matchM = month === 'todos' || gm === (mNum[month]||'');
    return matchY && matchM && (!excludeCurrentMonth || !isCurrentPeriod(gm, gy));
  });
  const gastosPagados   = gastosFiltered.filter(g=>g.paid).reduce((s,g)=>s+g.amount,0);
  const gastosPrevistos = gastosFiltered.filter(g=>!g.paid).reduce((s,g)=>s+g.amount,0);
  const gastosExtra     = gastosPagados + gastosPrevistos;

  const facturas = (quotes||[]).filter(q=>q.invoice).map(q=>{
    const dateStr = q.deliveryDate||q.date||'';
    const parts = dateStr.split('/');
    const qm = parts[1]||null;
    const qy = parts[2]||null;
    const days = q.daysLeft||0;
    const credit = q.credit||0;
    const paidAt = q.paidAt || null;
    const estado = (paidAt || credit===0) ? 'cobrado' : (days<0 ? 'vencido' : days<=7 ? 'por_vencer' : 'pendiente');
    const dueStr = q.dueDate||'';
    const dueParts = dueStr.split('/');
    const dueM = dueParts[1]||null;
    const dueY = dueParts[2]||null;
    return {
      id:q.id, invoice:q.invoice, client:q.client, clientId:q.clientId,
      date:dateStr, due:q.dueDate||'—', amount:q.total,
      days, credit, createdBy:q.createdBy||'', estado, m:qm, y:qy, paidAt, dueM, dueY,
      paymentLocked: !!q.paymentLocked,
    };
  });

  const clientMatch = f => selClient === 'todos' || String(f.clientId) === selClient;
  const vendMatch   = f => selVendedor === 'todos' || f.createdBy === selVendedor;

  // Para KPIs: unión de emitidas + vencimientos en el período
  const filteredFacturas = facturas.filter(f => {
    const byIssue = (month==='todos'||mMap[f.m]===month) && (year==='todos'||f.y===year);
    const byDue   = f.credit>0 && f.dueM && (month==='todos'||mMap[f.dueM]===month) && (year==='todos'||f.dueY===year);
    const inCurrent = isCurrentPeriod(f.m, f.y) || (f.dueM && isCurrentPeriod(f.dueM, f.dueY));
    return (byIssue||byDue) && clientMatch(f) && vendMatch(f) && (!excludeCurrentMonth || !inCurrent);
  });

  // Tabla "Facturas Emitidas" — filtrada por fecha de emisión
  const facturasEmitidas = facturas.filter(f =>
    (month==='todos'||mMap[f.m]===month) && (year==='todos'||f.y===year) && clientMatch(f) && vendMatch(f) &&
    (!excludeCurrentMonth || !isCurrentPeriod(f.m, f.y))
  );

  // Tabla "Facturas por Cobrar" — filtrada por fecha de vencimiento (crédito, no pagadas)
  const facturasXCobrar = facturas.filter(f =>
    f.credit>0 && f.estado!=='cobrado' && f.dueM &&
    (month==='todos'||mMap[f.dueM]===month) && (year==='todos'||f.dueY===year) &&
    clientMatch(f) && vendMatch(f) && (!excludeCurrentMonth || !isCurrentPeriod(f.dueM, f.dueY))
  );

  // Cobrado por mes calculado desde quotes en tiempo real (reactivo a setQuotes)
  const mShortIdx = ['Ene','Feb','Mar','Abr','May','Jun','Jul','Ago','Sep','Oct','Nov','Dic'];
  const cobradoByMonthLive = {};
  facturas.filter(f=>f.estado==='cobrado').forEach(f=>{
    if(!f.m || !f.y) return;
    const key = `${f.y}-${String(+f.m).padStart(2,'0')}`;
    cobradoByMonthLive[key] = (cobradoByMonthLive[key]||0) + f.amount;
  });

  // monthly con cobrado en tiempo real sobrescrito
  const monthlyLive = monthlyData.map(d => {
    const mn = String(mShortIdx.indexOf(d.m)+1).padStart(2,'0');
    const key = `${d.y}-${mn}`;
    return {...d, co: cobradoByMonthLive[key] !== undefined ? cobradoByMonthLive[key] : (d.co||0)};
  });

  // monthly filtrado por año, mes y cliente/vendedor
  const filteredMonthly = (() => {
    const clientFiltered = selClient !== 'todos' || selVendedor !== 'todos';
    if (!clientFiltered) {
      return monthlyLive.filter(d => {
        const matchY = year === 'todos' || String(d.y||'') === year;
        const matchM = month === 'todos' || d.m === month;
        return matchY && matchM && (!excludeCurrentMonth || !isCurrentPeriod(d.m, d.y));
      });
    }
    // Reconstruir desde facturas (tienen clientId y createdBy)
    const map = {};
    facturas.filter(f => clientMatch(f) && vendMatch(f)).forEach(f => {
      if (!f.m || !f.y) return;
      const mn = mShortIdx[+f.m - 1];
      const key = `${f.y}-${f.m}`;
      if (!map[key]) map[key] = { m: mn, y: f.y, v: 0, c: 0, co: 0 };
      map[key].v += f.amount;
      if (f.estado === 'cobrado') map[key].co += f.amount;
      // Costo (precio de compra) de los productos vendidos en esta cotización
      const q = (quotes||[]).find(q => q.id === f.id);
      if (q?.items) {
        q.items.forEach(item => {
          const prod = (products||[]).find(p => p.id === item.pid);
          map[key].c += (item.qty || 0) * +(prod?.buy || 0);
        });
      }
    });
    return Object.values(map)
      .filter(d => {
        const matchY = year === 'todos' || d.y === year;
        const matchM = month === 'todos' || d.m === month;
        return matchY && matchM && (!excludeCurrentMonth || !isCurrentPeriod(d.m, d.y));
      })
      .sort((a,b) => a.y !== b.y ? +a.y - +b.y : +a.m - +b.m);
  })();

  // KPIs de Ventas — cobrado incluye crédito marcado como pagado (paidAt)
  const totalFact    = filteredFacturas.reduce((s,f)=>s+f.amount, 0);
  const totalCobrado = filteredFacturas.filter(f=>f.estado==='cobrado').reduce((s,f)=>s+f.amount, 0);
  const pendiente    = filteredFacturas.filter(f=>f.estado==='pendiente'||f.estado==='por_vencer').reduce((s,f)=>s+f.amount, 0);
  const vencido      = filteredFacturas.filter(f=>f.estado==='vencido').reduce((s,f)=>s+f.amount, 0);

  const donutData=[
    {label:'Cobrado',value:totalCobrado||0.1,color:G.accent},
    {label:'Pendiente cobro',value:pendiente||0.1,color:G.warning},
    {label:'Vencido',value:vencido||0.1,color:G.error},
  ];

  const selectSt = {background:G.card2,border:`1px solid ${G.border}`,color:G.text,padding:'4px 8px',borderRadius:5,fontSize:12,cursor:'pointer'};
  const hasFilter = selClient!=='todos'||month!=='todos'||year!==currentYear||selVendedor!=='todos'||excludeCurrentMonth;

  const filterBar = (
    <div style={{display:'flex',gap:8,alignItems:'center',flexWrap:'wrap'}}>
      <select value={year} onChange={e=>setYear(e.target.value)} style={selectSt}>
        {availYears.map(y=><option key={y} value={y}>{y==='todos'?'Todos los años':y}</option>)}
      </select>
      <select value={month} onChange={e=>setMonth(e.target.value)} style={selectSt}>
        {meses.map(m=><option key={m} value={m}>{m==='todos'?'Todos los meses':m}</option>)}
      </select>
      <select value={selClient} onChange={e=>setSelClient(e.target.value)} style={selectSt}>
        <option value="todos">Todos los clientes</option>
        {clientes.map(c=><option key={c.id} value={String(c.id)}>{c.name}</option>)}
      </select>
      {tab==='Ventas' && (
        <select value={selVendedor} onChange={e=>setSelVendedor(e.target.value)} style={selectSt}>
          <option value="todos">Todos los vendedores</option>
          {(users||[]).map(u=><option key={u.id} value={u.username}>{u.name}{u.apellidos?` ${u.apellidos}`:''}</option>)}
        </select>
      )}
      <button
        onClick={()=>setExcludeCurrentMonth(v=>!v)}
        style={{background:excludeCurrentMonth?G.warning+'22':'transparent',border:`1px solid ${excludeCurrentMonth?G.warning:G.border}`,color:excludeCurrentMonth?G.warning:G.textSec,padding:'4px 8px',borderRadius:5,fontSize:11,fontWeight:600,cursor:'pointer'}}
      >
        {excludeCurrentMonth?'✓ Sin mes en curso':'No contar mes en curso'}
      </button>
      {hasFilter && (
        <button onClick={()=>{setSelClient('todos');setMonth('todos');setYear(currentYear);setSelVendedor('todos');setExcludeCurrentMonth(false);}} style={{background:G.error+'22',border:`1px solid ${G.error}44`,color:G.error,padding:'4px 8px',borderRadius:5,fontSize:11,cursor:'pointer'}}>
          ✕ Limpiar
        </button>
      )}
    </div>
  );

  const factCols=[
    {key:'invoice',label:'N° SUNAT',w:120,render:r=><span style={{color:'#29B6F6',fontWeight:600,fontSize:12}}>{r.invoice}</span>},
    {key:'client',label:'Cliente'},
    {key:'createdBy',label:'Vendedor',w:90,render:r=><span style={{fontSize:11,color:G.textSec}}>{r.createdBy||'—'}</span>},
    {key:'date',label:'Fecha',w:100},
    {key:'due',label:'Vencimiento',w:100},
    {key:'amount',label:'Monto',w:120,render:r=><span style={{color:G.accent,fontWeight:700}}>{fmtS(r.amount)}</span>},
    {key:'estado',label:'Estado',w:110,render:r=>{
      const map={pendiente:{c:G.warning,l:'Pendiente'},por_vencer:{c:G.warning,l:'Por Vencer'},cobrado:{c:G.accent,l:'Cobrado'},vencido:{c:G.error,l:'Vencido'}};
      const s=map[r.estado]||map.pendiente;
      return <span style={{background:s.c+'22',color:s.c,padding:'2px 8px',borderRadius:3,fontSize:11,fontWeight:600}}>{s.l}</span>;
    }},
    {key:'days',label:'Días',w:70,render:r=>r.credit>0?<DaysBadge days={r.days}/>:<span style={{fontSize:11,color:G.textSec}}>contado</span>},
    {key:'cobrar',label:'',w:120,render:r=>{
      if(r.credit===0||r.paidAt)
        return <div style={{display:'flex',alignItems:'center',gap:4}}>
          <span style={{background:G.accent+'22',color:G.accent,padding:'2px 8px',borderRadius:3,fontSize:11,fontWeight:600}}>✅ Pagado</span>
          {r.paidAt && canManagePay && (!r.paymentLocked || currentUser?.role === 'Administrador') && <Btn sm variant="ghost" style={{color:G.error,borderColor:G.error+'55'}} onClick={()=>unpayFn(r)}>↩️</Btn>}
          {r.paidAt && r.paymentLocked && currentUser?.role !== 'Administrador' && <span style={{color:G.textSec,fontSize:10}}>Bloqueado</span>}
        </div>;
      return canManagePay
        ? <Btn sm variant="accent" onClick={()=>payCobrar(r)}>✅ Cobrar</Btn>
        : <span style={{color:G.textSec,fontSize:11}}>Pendiente</span>;
    }},
  ];

  const rentCols=[
    {key:'month',label:'Mes',w:80},
    {key:'compras',label:'Total Compras',render:r=><span style={{color:G.textSec}}>{fmtS(r.compras)}</span>},
    {key:'ventas',label:'Facturado',render:r=><span style={{color:G.accent}}>{fmtS(r.ventas)}</span>},
    {key:'ganancia',label:'Ganancia Bruta',render:r=><span style={{color:'#29B6F6',fontWeight:700}}>{fmtS(r.ventas-r.compras)}</span>},
    {key:'margen',label:'Margen',w:80,render:r=>r.ventas>0?<span style={{color:G.accent,fontWeight:700}}>{(((r.ventas-r.compras)/r.ventas)*100).toFixed(1)}%</span>:<span style={{color:G.textSec}}>—</span>},
    {key:'markup',label:'Markup s/Compras',w:110,render:r=>r.compras>0?<span style={{color:'#AB47BC',fontWeight:700}}>{(((r.ventas-r.compras)/r.compras)*100).toFixed(1)}%</span>:<span style={{color:G.textSec}}>—</span>},
  ];

  const gastosCols=[
    {key:'date',    label:'Fecha',      w:100,render:r=><span style={{fontSize:11,color:G.textSec}}>{r.date||'—'}</span>},
    {key:'category',label:'Categoría',  w:120,render:r=><Tag label={r.category} color={G.accent}/>},
    {key:'desc',    label:'Descripción',render:r=><span style={{fontSize:12}}>{r.desc}</span>},
    {key:'amount',  label:'Monto',      w:120,render:r=><span style={{color:G.warning,fontWeight:700}}>{fmtS(r.amount)}</span>},
    {key:'est',     label:'Estado',     w:110,render:r=>(
      <span onClick={()=>toggleGasto(r.id)} style={{background:r.paid?G.accent+'22':G.error+'22',color:r.paid?G.accent:G.error,padding:'2px 8px',borderRadius:3,fontSize:11,fontWeight:600,cursor:'pointer'}}>
        {r.paid?'Pagado':'Previsto'}
      </span>
    )},
  ];

  const clientFiltered = selClient !== 'todos' || selVendedor !== 'todos';
  const displayMonthly = clientFiltered
    ? filteredMonthly
    : (filteredMonthly.length ? filteredMonthly : monthlyLive);
  const comprasByMonth = {};
  monthlyLive.forEach(d => { comprasByMonth[`${d.y}-${d.m}`] = d.c || 0; });
  const rentData = displayMonthly.map(d => ({
    ...d,
    c: comprasByMonth[`${d.y}-${d.m}`] ?? (d.c || 0),
  }));
  const rentTotC         = rentData.reduce((s,m)=>s+m.c,0);
  const rentTotFacturado = rentData.reduce((s,m)=>s+(m.v||0),0);
  const rentGanBruta     = rentTotFacturado - rentTotC;
  const rentGanNeta      = incluyeGastos ? rentGanBruta - gastosExtra : rentGanBruta;
  const rentMarg         = rentTotFacturado>0?((rentGanNeta/rentTotFacturado)*100).toFixed(1)+'%':'0.0%';
  const markupBase       = incluyeGastos ? rentTotC + gastosExtra : rentTotC;
  const rentMarkup       = markupBase>0?((rentGanNeta/markupBase)*100).toFixed(1)+'%':'0.0%';
  const rentTab = (
    <div>
      <div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:14,flexWrap:'wrap',gap:8}}>
        <div style={{display:'flex',gap:14,flexWrap:'wrap',flex:1}}>
          {[
            ['Total Compras',fmtS(rentTotC),G.warning],
            ['Total Facturado',fmtS(rentTotFacturado),G.accent],
            incluyeGastos && gastosPagados>0
              ? ['Gastos Pagados',fmtS(gastosPagados),G.error]
              : incluyeGastos ? ['Gastos Pagados','S/ 0',G.error] : null,
            incluyeGastos && gastosPrevistos>0
              ? ['Gastos Previstos',fmtS(gastosPrevistos),'#FF8A65']
              : null,
            [incluyeGastos?'Ganancia Neta':'Ganancia Bruta',fmtS(rentGanNeta),'#29B6F6'],
            [incluyeGastos?'Margen Neto':'Margen Bruto',rentMarg,G.accent],
            ['Markup s/Compras',rentMarkup,'#AB47BC'],
          ].filter(Boolean).map(([l,v,c])=>(
            <KPICard key={l} label={l} value={v} color={c}/>
          ))}
        </div>
        <button onClick={toggleGastos} style={{
          background:incluyeGastos?G.accent+'22':'transparent',
          border:`1px solid ${incluyeGastos?G.accent:G.border}`,
          color:incluyeGastos?G.accent:G.textSec,
          padding:'6px 14px',borderRadius:5,fontSize:12,fontWeight:600,cursor:'pointer',
          whiteSpace:'nowrap',transition:'all 0.15s',flexShrink:0
        }}>
          {incluyeGastos?'✓ Con gastos operativos':'+ Incluir gastos operativos'}
        </button>
      </div>
      <Card title={incluyeGastos?"Compras vs Facturado vs Gastos — Rentabilidad Real":"Compras vs Facturado — Barras + Línea de tendencia"} style={{marginBottom:20}}>
        <ComboChart data={rentData} height={140} highlight={month!=='todos'?month:null}/>
        <div style={{display:'flex',gap:16,marginTop:8}}>
          <div style={{display:'flex',alignItems:'center',gap:4}}><div style={{width:10,height:10,borderRadius:2,background:G.accent}}/><span style={{fontSize:10,color:G.textSec}}>Facturado</span></div>
          <div style={{display:'flex',alignItems:'center',gap:4}}><div style={{width:10,height:10,borderRadius:2,background:G.border}}/><span style={{fontSize:10,color:G.textSec}}>Compras</span></div>
          <div style={{display:'flex',alignItems:'center',gap:4}}><div style={{width:16,height:2,background:G.accent,opacity:0.7}}/><span style={{fontSize:10,color:G.textSec}}>Tendencia facturado</span></div>
        </div>
      </Card>
      <Card title="Desglose mensual" noPad style={{marginBottom: incluyeGastos ? 14 : 0}}>
        <Table cols={rentCols} rows={rentData.map(d=>({month:d.m+(d.y?` ${d.y}`:''),ventas:d.v||0,compras:d.c}))}/>
      </Card>
      {incluyeGastos && (
        <>
          <Card title={`💸 Gastos del Período — ${fmtS(gastosPagados)}`} noPad style={{marginBottom:14}}>
            <Table cols={gastosCols} rows={gastosFiltered.filter(g=>g.paid)} emptyMsg="Sin gastos pagados en este período"/>
          </Card>
          <Card title={`📋 Gastos Previstos — ${fmtS(gastosPrevistos)}`} noPad>
            <Table cols={gastosCols} rows={gastosFiltered.filter(g=>!g.paid)} emptyMsg="Sin gastos previstos en este período — clic en 'Previsto' para marcar como pagado"/>
          </Card>
        </>
      )}
    </div>
  );

  return (
    <div>
      <PageHeader title="CONTABILIDAD" subtitle="Ventas, cobros y rentabilidad" action={filterBar}/>
      <Tabs tabs={['Ventas','Rentabilidad']} active={tab} onChange={setTab}/>

      {tab==='Ventas' && (
        <div>
          <div style={{display:'flex',gap:14,marginBottom:20,flexWrap:'wrap'}}>
            <KPICard label="Total Cobrado" value={fmtS(totalCobrado)} color={G.accent} icon="✅"/>
            <KPICard label="Total Facturado" value={fmtS(totalFact)} color={G.textSec} icon="📄"/>
            <KPICard label="Pendiente de Cobro" value={fmtS(pendiente)} color={G.warning} icon="⏳"/>
            <KPICard label="Vencido" value={fmtS(vencido)} color={G.error} icon="🔴"/>
          </div>
          <div style={{display:'grid',gridTemplateColumns:'1fr 280px',gap:14,marginBottom:20}}>
            <Card title="Facturado mes a mes">
              <ComboChart data={displayMonthly} height={130} highlight={month!=='todos'?month:null}/>
              <div style={{display:'flex',gap:16,marginTop:8}}>
                <div style={{display:'flex',alignItems:'center',gap:4}}><div style={{width:10,height:10,borderRadius:2,background:G.accent}}/><span style={{fontSize:10,color:G.textSec}}>Facturado</span></div>
                <div style={{display:'flex',alignItems:'center',gap:4}}><div style={{width:10,height:10,borderRadius:2,background:G.border}}/><span style={{fontSize:10,color:G.textSec}}>Compras</span></div>
              </div>
            </Card>
            <Card title="Estado de cobros">
              <div style={{display:'flex',gap:14,alignItems:'center'}}>
                <DonutChart data={donutData} size={90}/>
                <div style={{flex:1}}>
                  {donutData.map(d=>(
                    <div key={d.label} style={{display:'flex',justifyContent:'space-between',marginBottom:6}}>
                      <div style={{display:'flex',alignItems:'center',gap:5}}><div style={{width:7,height:7,borderRadius:'50%',background:d.color}}/><span style={{fontSize:11,color:G.textSec}}>{d.label}</span></div>
                      <span style={{fontSize:11,fontWeight:700,color:G.text}}>{fmtS(d.value)}</span>
                    </div>
                  ))}
                </div>
              </div>
            </Card>
          </div>
          {facturasXCobrar.length>0 && (
            <Card title={`💳 Facturas por Cobrar — ${facturasXCobrar.length} pendiente${facturasXCobrar.length!==1?'s':''} · ${fmtS(facturasXCobrar.reduce((s,f)=>s+f.amount,0))}`} noPad style={{marginBottom:14}}>
              <Table cols={factCols} rows={facturasXCobrar} emptyMsg="Sin facturas pendientes de cobro"/>
            </Card>
          )}
          <Card title={`📄 Facturas Emitidas — ${facturasEmitidas.length} factura${facturasEmitidas.length!==1?'s':''}`} noPad>
            <Table cols={factCols} rows={facturasEmitidas} emptyMsg="Sin facturas emitidas para el filtro seleccionado"/>
          </Card>
        </div>
      )}

      {tab==='Rentabilidad' && rentTab}
    </div>
  );
}

// ─── CONTACTOS ────────────────────────────────────────────────
function Contactos({ contacts, setContacts, quotes, logActivity, users, currentUser }) {
  const [tab, setTab] = useState('Clientes');
  const [selected, setSelected] = useState(null);
  const [showModal, setShowModal] = useState(false);
  const [editingId, setEditingId] = useState(null);
  const [assignModal, setAssignModal] = useState(null);
  const [assignOwnerId, setAssignOwnerId] = useState('');
  const [ownerFilter, setOwnerFilter] = useState('todos');
  const [delModal, setDelModal] = useState(null); // contact to delete
  const [deleting, setDeleting] = useState(false);
  const [delErr, setDelErr] = useState('');
  const blankForm = {type:'cliente',name:'',ruc:'',credit:0,email:'',phone:'',attn:'',direccion:'',note:''};
  const [form, setForm] = useState(blankForm);
  const sf = (k,v) => setForm(f=>({...f,[k]:v}));

  const isAdmin = currentUser?.role === 'Administrador';
  const canSeeAll = isAdmin || !!currentUser?.perms?.contactos;
  const canDelete = isAdmin || !!currentUser?.perms?.contactos;

  const shown = (contacts||[])
    .filter(c=>tab==='Clientes'?c.type==='cliente':c.type==='proveedor')
    .filter(c=>{
      if(!canSeeAll || ownerFilter==='todos') return true;
      if(ownerFilter==='mine') return c.ownerId===currentUser?.id;
      return c.ownerId===+ownerFilter;
    });

  const openNew = () => { setForm(blankForm); setEditingId(null); setShowModal(true); };
  const openEdit = (c) => {
    setForm({type:c.type,name:c.name,ruc:c.ruc,credit:c.credit,email:c.email,phone:c.phone,attn:c.attn||'',direccion:c.direccion||'',note:c.note||''});
    setEditingId(c.id); setShowModal(true);
  };
  const doAssign = async () => {
    if(!assignModal) return;
    const res = await window.api(`/contacts/${assignModal.id}/assign`, {
      method:'PATCH', body:JSON.stringify({ownerId:assignOwnerId?+assignOwnerId:null})
    });
    if(res && res.ok) {
      const updated = await res.json();
      setContacts(cs=>cs.map(c=>c.id===assignModal.id?updated:c));
      if(selected?.id===assignModal.id) setSelected(updated);
      setAssignModal(null);
    }
  };

  const confirmDelete = async () => {
    if(!delModal) return;
    setDeleting(true); setDelErr('');
    const res = await window.api(`/contacts/${delModal.id}`, {method:'DELETE'});
    setDeleting(false);
    if(res && res.ok) {
      setContacts(cs=>cs.filter(c=>c.id!==delModal.id));
      if(selected?.id===delModal.id) setSelected(null);
      if(logActivity) logActivity('Eliminó contacto','Contactos',delModal.name);
      setDelModal(null);
    } else {
      const body = res ? await res.json().catch(()=>({})) : {};
      setDelErr(body.error || 'No se pudo eliminar el contacto.');
    }
  };

  const save = async () => {
    if(!form.name) return;
    const body = JSON.stringify({...form, credit:+form.credit});
    if(editingId) {
      const res = await window.api(`/contacts/${editingId}`, {method:'PUT', body});
      if(res && res.ok) {
        const updated = await res.json();
        setContacts(cs=>cs.map(c=>c.id===editingId?updated:c));
        if(selected?.id===editingId) setSelected(updated);
        if(logActivity) logActivity('Editó contacto','Contactos',form.name);
      }
    } else {
      const res = await window.api('/contacts', {method:'POST', body});
      if(res && res.ok) {
        const created = await res.json();
        setContacts(cs=>[...cs,created]);
        if(logActivity) logActivity('Nuevo contacto','Contactos',`${form.name} (${form.type})`);
      }
    }
    setShowModal(false);
  };

  const cols = [
    {key:'name',label:'Empresa / Nombre',render:r=>(
      <div style={{display:'flex',alignItems:'center',gap:8}}>
        <div style={{width:30,height:30,borderRadius:'50%',background:G.accent+'22',border:`1px solid ${G.accent}33`,display:'flex',alignItems:'center',justifyContent:'center',fontSize:12,fontWeight:700,color:G.accent,flexShrink:0}}>{r.name.charAt(0)}</div>
        <div>
          <div style={{fontSize:13,fontWeight:500,color:G.text}}>{r.name}{r.ownerId && <span style={{marginLeft:6,background:G.info+'22',color:G.info,fontSize:9,fontWeight:700,padding:'1px 5px',borderRadius:3,border:`1px solid ${G.info}33`}}>cartera: @{r.ownerUsername||'usuario'}</span>}</div>
          <div style={{fontSize:10,color:G.textSec}}>RUC: {r.ruc}</div>
        </div>
      </div>
    )},
    {key:'credit',label:'Crédito',w:110,render:r=>(
      <div>
        <CreditBadge days={r.credit}/>
        <div style={{fontSize:9,color:G.textSec,marginTop:2}}>{r.type==='cliente'?'otorgamos':'nos otorgan'}</div>
      </div>
    )},
    {key:'email',label:'Email',render:r=><span style={{fontSize:11,color:G.textSec}}>{r.email}</span>},
    {key:'phone',label:'Teléfono',w:130,render:r=><span style={{fontSize:12}}>{r.phone}</span>},
    {key:'special',label:'',w:40,render:r=>r.hasSpecial?<Tag label="⭐" color={G.warning}/>:null},
    {key:'actions',label:'',w:canDelete?130:90,render:r=>(
      <div style={{display:'flex',gap:4}}>
        <Btn sm variant="ghost" onClick={e=>{e.stopPropagation();openEdit(r);}}>✏️</Btn>
        <Btn sm variant="ghost" onClick={e=>{e.stopPropagation();setSelected(r);}}>Ver →</Btn>
        {canDelete && <Btn sm variant="danger" onClick={e=>{e.stopPropagation();setDelModal(r);setDelErr('');}}>✕</Btn>}
      </div>
    )},
  ];

  return (
    <div style={{display:'flex',gap:0}}>
      <div style={{flex:1,minWidth:0}}>
        <PageHeader title="CONTACTOS" subtitle="Clientes y proveedores" action={<Btn onClick={openNew}>+ Nuevo Contacto</Btn>}/>
        <Tabs tabs={['Clientes','Proveedores']} active={tab} onChange={setTab}/>
        {canSeeAll && (
          <div style={{display:'flex',gap:6,marginBottom:14,flexWrap:'wrap',alignItems:'center'}}>
            <span style={{fontSize:11,color:G.textSec,flexShrink:0}}>Ver:</span>
            {[
              {k:'todos', label:'Todos'},
              {k:'mine',  label:'Solo míos'},
              ...(users||[]).filter(u=>u.role!=='Administrador').map(u=>({k:String(u.id),label:`${u.name}${u.apellidos?' '+u.apellidos:''}`}))
            ].map(opt=>(
              <button key={opt.k} onClick={()=>setOwnerFilter(opt.k)} style={{background:ownerFilter===opt.k?G.accent+'22':G.card2,border:`1px solid ${ownerFilter===opt.k?G.accent:G.border}`,color:ownerFilter===opt.k?G.accent:G.textSec,padding:'4px 12px',borderRadius:4,fontSize:12,fontWeight:600,cursor:'pointer'}}>
                {opt.label}
              </button>
            ))}
          </div>
        )}
        <Card noPad>
          <Table cols={cols} rows={shown} onRow={r=>setSelected(r)} emptyMsg="Sin contactos registrados"/>
        </Card>
      </div>

      {selected && (
        <div style={{width:300,marginLeft:16,flexShrink:0}}>
          <Card style={{position:'sticky',top:0}}>
            <div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:14}}>
              <div style={{width:40,height:40,borderRadius:'50%',background:G.accent+'22',border:`1px solid ${G.accent}33`,display:'flex',alignItems:'center',justifyContent:'center',fontSize:16,fontWeight:700,color:G.accent}}>{selected.name.charAt(0)}</div>
              <div style={{display:'flex',gap:6}}>
                <Btn sm variant="ghost" onClick={()=>openEdit(selected)}>✏️ Editar</Btn>
                {users && <Btn sm variant="ghost" onClick={()=>{setAssignModal(selected);setAssignOwnerId(selected.ownerId?String(selected.ownerId):'');}}>👤 Asignar</Btn>}
                <button onClick={()=>setSelected(null)} style={{background:'none',border:'none',color:G.textSec,cursor:'pointer',fontSize:16}}>✕</button>
              </div>
            </div>
            <div style={{fontFamily:"'Barlow Condensed',sans-serif",fontSize:18,fontWeight:700,color:G.text,marginBottom:4}}>{selected.name}</div>
            <CreditBadge days={selected.credit}/>
            <div style={{marginTop:14,display:'flex',flexDirection:'column',gap:10}}>
              {[['RUC',selected.ruc],['Atención',selected.attn],['Dirección',selected.direccion],['Email',selected.email],['Teléfono',selected.phone]].filter(([,v])=>v).map(([k,v])=>(
                <div key={k}><div style={{...T.sm,marginBottom:2}}>{k}</div><div style={{fontSize:12,color:G.text}}>{v}</div></div>
              ))}
              {selected.note && (
                <div><div style={{...T.sm,marginBottom:2}}>Nota interna</div><div style={{fontSize:12,color:G.textSec,background:G.bg,border:`1px solid ${G.border}`,borderRadius:5,padding:'6px 8px'}}>{selected.note}</div></div>
              )}
            </div>
            {selected.type==='cliente' && (
              <div style={{marginTop:14,paddingTop:12,borderTop:`1px solid ${G.border}`}}>
                <div style={{...T.sm,marginBottom:8}}>Cotizaciones recientes</div>
                {(quotes||[]).filter(q=>q.clientId===selected.id).slice(0,3).map(q=>(
                  <div key={q.id} style={{display:'flex',justifyContent:'space-between',alignItems:'center',padding:'5px 0',borderBottom:`1px solid ${G.border}22`}}>
                    <div><div style={{fontSize:11,color:G.text}}>{q.id}</div><div style={{fontSize:10,color:G.textSec}}>{q.date}</div></div>
                    <div style={{textAlign:'right'}}><div style={{fontSize:11,color:G.accent,fontWeight:600}}>{fmtS(q.total)}</div><StatusBadge status={q.status}/></div>
                  </div>
                ))}
              </div>
            )}
          </Card>
        </div>
      )}

      {assignModal && (
        <Modal title={`Asignar cartera — ${assignModal.name}`} onClose={()=>setAssignModal(null)} width={440}>
          <div style={{fontSize:12,color:G.textSec,marginBottom:14}}>Asigna este contacto a la cartera de un empleado o déjalo como contacto global accesible para todos.</div>
          <FSelect label="Asignar a" value={assignOwnerId} onChange={e=>setAssignOwnerId(e.target.value)} options={[
            {value:'',label:'Sin cartera (contacto global)'},
            ...(users||[]).filter(u=>u.role!=='Administrador').map(u=>({value:String(u.id),label:`${u.name}${u.apellidos?' '+u.apellidos:''} (@${u.username})`}))
          ]}/>
          <div style={{display:'flex',justifyContent:'flex-end',gap:8,marginTop:12}}>
            <Btn variant="secondary" onClick={()=>setAssignModal(null)}>Cancelar</Btn>
            <Btn onClick={doAssign}>Confirmar asignación</Btn>
          </div>
        </Modal>
      )}

      {delModal && (
        <Modal title="Eliminar Contacto" onClose={()=>{setDelModal(null);setDelErr('');}} width={440}>
          {(() => {
            const contactQuotes = (quotes||[]).filter(q=>q.clientId===delModal.id);
            const activeQ = contactQuotes.filter(q=>q.status==='vigente'||q.status==='aceptada').length;
            return (
              <>
                <div style={{background:G.bg,border:`1px solid ${G.border}`,borderRadius:6,padding:'12px 14px',marginBottom:14}}>
                  <div style={{fontWeight:600,color:G.text,marginBottom:4}}>{delModal.name}</div>
                  <div style={{fontSize:12,color:G.textSec}}>
                    {contactQuotes.length > 0
                      ? `Este contacto tiene ${contactQuotes.length} cotización${contactQuotes.length!==1?'es':''} asociada${contactQuotes.length!==1?'s':''}.`
                      : 'Sin cotizaciones asociadas.'}
                  </div>
                </div>
                {activeQ > 0 && (
                  <div style={{background:G.error+'22',border:`1px solid ${G.error}55`,borderRadius:5,padding:'10px 14px',fontSize:12,color:G.error,marginBottom:14}}>
                    ⛔ No se puede eliminar: tiene <b>{activeQ}</b> cotización{activeQ!==1?'es':''} activa{activeQ!==1?'s':''} (vigente{activeQ!==1?'s':''} o aceptada{activeQ!==1?'s':''}).
                  </div>
                )}
                {delErr && <div style={{background:G.error+'22',border:`1px solid ${G.error}55`,borderRadius:5,padding:'8px 12px',fontSize:12,color:G.error,marginBottom:10}}>{delErr}</div>}
                <div style={{display:'flex',justifyContent:'flex-end',gap:8}}>
                  <Btn variant="secondary" onClick={()=>{setDelModal(null);setDelErr('');}}>Cancelar</Btn>
                  <Btn variant="danger" onClick={confirmDelete} disabled={deleting||activeQ>0}>
                    {deleting?'Eliminando…':'Eliminar Contacto'}
                  </Btn>
                </div>
              </>
            );
          })()}
        </Modal>
      )}

      {showModal && (
        <Modal title={editingId?'Editar Contacto':'Nuevo Contacto'} onClose={()=>setShowModal(false)} width={520}>
          <div style={{display:'flex',gap:8,marginBottom:14}}>
            {['cliente','proveedor'].map(t=>(
              <Btn key={t} sm variant={form.type===t?'primary':'ghost'} onClick={()=>sf('type',t)}>{t.charAt(0).toUpperCase()+t.slice(1)}</Btn>
            ))}
          </div>
          <Row><FInput label="Razón Social / Nombre *" value={form.name} onChange={e=>sf('name',e.target.value)}/><FInput label="RUC" value={form.ruc} onChange={e=>sf('ruc',e.target.value)}/></Row>
          <Row>
            <FInput label="Persona de contacto (Atención)" value={form.attn} onChange={e=>sf('attn',e.target.value)}/>
            <FSelect label={form.type==='cliente'?'Crédito que otorgamos':'Crédito que nos otorgan'} value={form.credit} onChange={e=>sf('credit',+e.target.value)} options={[0,30,60,90,120].map(d=>({value:d,label:d===0?'Contado':`${d} días`}))}/>
          </Row>
          <FInput label="Dirección" value={form.direccion||''} onChange={e=>sf('direccion',e.target.value)} placeholder="Av. Ejemplo 123, Lima"/>
          <Row><FInput label="Email" type="email" value={form.email} onChange={e=>sf('email',e.target.value)}/><FInput label="Teléfono" value={form.phone} onChange={e=>sf('phone',e.target.value)}/></Row>
          <FTextarea label="Nota interna" value={form.note} onChange={e=>sf('note',e.target.value)} rows={2}/>
          <div style={{display:'flex',justifyContent:'flex-end',gap:8}}>
            <Btn variant="secondary" onClick={()=>setShowModal(false)}>Cancelar</Btn>
            <Btn onClick={save}>{editingId?'Guardar Cambios':'Crear Contacto'}</Btn>
          </div>
        </Modal>
      )}
    </div>
  );
}

// ─── HISTORIAL ────────────────────────────────────────────────
function Historial({ activity }) {
  const [search, setSearch] = useState('');
  const [modFilter, setModFilter] = useState('todos');
  const mods = ['todos','Cotizaciones','Facturación','Movimientos','Almacén','Precios','Contactos'];
  const rows = (activity||[]).filter(a=>{
    const matchMod = modFilter==='todos'||(a.module||'')=== modFilter;
    const matchSearch = !search||[a.action,a.detail,a.user].some(x=>(x||'').toLowerCase().includes(search.toLowerCase()));
    return matchMod && matchSearch;
  });
  const cols = [
    {key:'dt',label:'Fecha/Hora',w:110,render:r=><span style={{fontSize:11,color:G.textSec,fontFamily:'monospace'}}>{r.dt||'—'}</span>},
    {key:'user',label:'Usuario',w:120,render:r=>(
      <div style={{display:'flex',alignItems:'center',gap:5}}>
        <div style={{width:20,height:20,borderRadius:'50%',background:G.accent+'22',display:'flex',alignItems:'center',justifyContent:'center',fontSize:9,fontWeight:700,color:G.accent,flexShrink:0}}>{(r.user||'S').charAt(0)}</div>
        <span style={{fontSize:11}}>{r.user||'Sistema'}</span>
      </div>
    )},
    {key:'module',label:'Módulo',w:110,render:r=><Tag label={r.module||'—'} color={G.accent}/>},
    {key:'action',label:'Acción',w:160,render:r=><span style={{fontSize:12,fontWeight:500}}>{r.action||'—'}</span>},
    {key:'detail',label:'Detalle',render:r=><span style={{fontSize:11,color:G.textSec}}>{r.detail||''}</span>},
  ];
  return (
    <div>
      <PageHeader title="HISTORIAL DE ACTIVIDAD" subtitle="Registro completo de acciones del sistema"/>
      <div style={{display:'flex',gap:8,marginBottom:16,flexWrap:'wrap',alignItems:'center'}}>
        <input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Buscar en historial…" style={{background:G.card,border:`1px solid ${G.border}`,borderRadius:5,color:G.text,padding:'6px 11px',fontSize:12,width:220,outline:'none',fontFamily:"'Inter',sans-serif"}}/>
        {mods.map(m=>(
          <button key={m} onClick={()=>setModFilter(m)} style={{background:modFilter===m?G.accent+'22':G.card2,border:`1px solid ${modFilter===m?G.accent:G.border}`,color:modFilter===m?G.accent:G.textSec,padding:'4px 10px',borderRadius:4,fontSize:11,fontWeight:600,cursor:'pointer'}}>
            {m==='todos'?'Todos':m}
          </button>
        ))}
      </div>
      <Card noPad><Table cols={cols} rows={rows} emptyMsg="Sin registros de actividad"/></Card>
    </div>
  );
}

// ─── USUARIOS ─────────────────────────────────────────────────
function Usuarios({ users, setUsers }) {
  const localUsers = users || window.USERS_DATA || [];
  const setLocalUsers = setUsers || (()=>{});

  const [editing, setEditing] = useState(null);
  const [showModal, setShowModal] = useState(false);
  const [carteraModal, setCarteraModal] = useState(null);
  const [carteraData, setCarteraData] = useState(null);

  const blankPerms = {
    verPrecios:false, catalogo:false, almacen:false, compras:false,
    crearCotizacion:false, confirmarOC:false, entregar:false, otorgarCredito:false,
    cotizaciones:false, facturas:false, precEsp:false, precEspAll:false, modPrecEsp:false,
    cotizarTodos:false, verVentasEquipo:false, ajustarPrecio:false,
    contactos:false, contabilidad:false, historial:false, usuarios:false,
    gestionarCartera:false, verDashboardAdmin:false, gestionarSolicitudesOperativas:false,
    eliminarFacturas:false, eliminarOC:false, eliminarCotizaciones:false,
    gestionarPagos:false, eliminarMovimientos:false,
    editarFechaCotizacion:false,
  };
  const blankForm = {name:'',apellidos:'',username:'',password:'',email:'',phone:'',role:'Usuario',active:true, perms:{...blankPerms}};
  const [form, setForm] = useState(blankForm);
  const sf = (k,v) => setForm(f=>({...f,[k]:v}));
  const sp = (k,v) => setForm(f=>({...f,perms:{...f.perms,[k]:v}}));

  const permGroups = [
    {label:'Catálogo y Almacén', perms:[
      ['verPrecios',    'Ver precios de compra / venta / ganancia'],
      ['catalogo',      'Editar catálogo (crear, editar, borrar productos)'],
      ['almacen',       'Ajustar stock en almacén'],
      ['compras',       'Registrar movimientos de compra'],
    ]},
    {label:'Cotizaciones y Ventas', perms:[
      ['crearCotizacion','Crear cotizaciones + Cartera de clientes'],
      ['otorgarCredito', 'Otorgar crédito a clientes (sin solicitar al admin)'],
      ['confirmarOC',   'Confirmar OC en cotizaciones'],
      ['entregar',      'Marcar entregado y facturar'],
      ['cotizaciones',  'Ver TODAS las cotizaciones del sistema'],
      ['facturas',      'Ver módulo de facturación'],
      ['precEsp',       'Ver precios especiales (solo su cartera)'],
      ['precEspAll',    'Ver precios especiales de TODOS los clientes'],
      ['modPrecEsp',    'Modificar precios especiales'],
      ['ajustarPrecio', 'Ajustar precio al cotizar (no puede quedar bajo costo)'],
      ['cotizarTodos',  'Cotizar a cualquier cliente (no solo su cartera)'],
      ['verVentasEquipo','Ver y gestionar ventas de todo el equipo'],
      ['editarFechaCotizacion','Cambiar fecha de cotización (registrar ventas en meses pasados)'],
    ]},
    {label:'Administración', perms:[
      ['contactos',          'Gestionar contactos globales'],
      ['gestionarCartera',   'Asignar clientes a cartera de empleados'],
      ['contabilidad',       'Ver contabilidad y gastos'],
      ['historial',          'Ver historial de actividad'],
      ['usuarios',           'Gestionar usuarios y permisos'],
      ['verDashboardAdmin',  'Ver dashboard ejecutivo (ventas globales)'],
      ['gestionarSolicitudesOperativas', 'Gestionar solicitudes de OC/facturación'],
      ['gestionarPagos',     'Marcar/revertir facturas como pagadas'],
      ['eliminarCotizaciones','Eliminar órdenes de compra y cotizaciones (cualquier estado)'],
      ['eliminarMovimientos', 'Eliminar registros de historial de movimientos'],
    ]},
  ];

  const openEdit = (u) => {
    const mergedPerms = {...blankPerms, ...(u.perms||{})};
    setForm({name:u.name,apellidos:u.apellidos||'',username:u.username||'',password:'',email:u.email||'',phone:u.phone||'',role:u.role,active:u.active,perms:mergedPerms});
    setEditing(u.id); setShowModal(true);
  };
  const openNew = () => { setForm(blankForm); setEditing(null); setShowModal(true); };

  const openCartera = async (u) => {
    setCarteraModal(u);
    setCarteraData(null);
    const res = await window.api(`/users/${u.id}/cartera`);
    if(res && res.ok) {
      const data = await res.json();
      setCarteraData(data);
    }
  };

  const save = async () => {
    if(!form.name||!form.username) return;
    if(editing) {
      const body = {name:form.name,apellidos:form.apellidos,username:form.username,role:form.role,perms:form.perms,email:form.email||`${form.username}@eutperu.com`,phone:form.phone||''};
      if(form.password) body.password = form.password;
      const res = await window.api(`/users/${editing}`, {method:'PUT', body:JSON.stringify(body)});
      if(res && res.ok) {
        const updated = await res.json();
        setLocalUsers(us=>us.map(u=>u.id===editing?updated:u));
      } else if(res) {
        const err = await res.json().catch(()=>({}));
        if(err.error) alert(err.error);
      }
    } else {
      if(!form.password) return;
      const res = await window.api('/users', {method:'POST', body:JSON.stringify({name:form.name,apellidos:form.apellidos,username:form.username,password:form.password,role:form.role,perms:form.perms,email:form.email||`${form.username}@eutperu.com`,phone:form.phone||''})});
      if(res && res.ok) {
        const created = await res.json();
        setLocalUsers(us=>[...us,created]);
      } else if(res) {
        const err = await res.json().catch(()=>({}));
        if(err.error) alert(err.error);
        return;
      }
    }
    setShowModal(false); setEditing(null);
  };
  const toggle = async (id) => {
    const res = await window.api(`/users/${id}/toggle`, {method:'PATCH'});
    if(res && res.ok) {
      const updated = await res.json();
      setLocalUsers(us=>us.map(u=>u.id===id?updated:u));
    }
  };

  const statusMap = {vigente:'Vigente',aceptada:'Aceptada',entregada:'Entregada',rechazada:'Rechazada',vencida:'Vencida'};

  const cols = [
    {key:'name',label:'Nombre',render:r=>(
      <div style={{display:'flex',alignItems:'center',gap:8}}>
        <div style={{width:30,height:30,borderRadius:'50%',background:G.accent+'22',border:`1px solid ${G.accent}33`,display:'flex',alignItems:'center',justifyContent:'center',fontSize:11,fontWeight:700,color:G.accent,flexShrink:0}}>
          {(r.name||'?').charAt(0)}{(r.apellidos||'').charAt(0)}
        </div>
        <div>
          <div style={{fontSize:13,fontWeight:500}}>{r.name} {r.apellidos}</div>
          <div style={{fontSize:10,color:G.textSec}}>@{r.username} · {r.email}</div>
        </div>
      </div>
    )},
    {key:'role',label:'Rol',w:120,render:r=><Tag label={r.role} color={r.role==='Administrador'?G.accent:G.info}/>},
    {key:'active',label:'Estado',w:90,render:r=>(
      <span style={{background:r.active?G.accent+'22':G.error+'22',color:r.active?G.accent:G.error,padding:'2px 8px',borderRadius:3,fontSize:11,fontWeight:600}}>{r.active?'Activo':'Inactivo'}</span>
    )},
    {key:'lastAccess',label:'Último acceso',w:110,render:r=><span style={{fontSize:11,color:G.textSec}}>{r.lastAccess}</span>},
    {key:'actions',label:'',w:160,render:r=>(
      <div style={{display:'flex',gap:4}}>
        <Btn sm variant="ghost" onClick={()=>openEdit(r)}>✏️</Btn>
        {r.role!=='Administrador' && <Btn sm variant="ghost" onClick={()=>openCartera(r)} title="Ver cartera de clientes">👥</Btn>}
        {r.role!=='Administrador' && <Btn sm variant={r.active?'danger':'secondary'} onClick={()=>toggle(r.id)}>{r.active?'Desact.':'Activar'}</Btn>}
      </div>
    )},
  ];

  return (
    <div>
      <PageHeader title="USUARIOS Y PERMISOS" subtitle="Gestión de acceso al sistema" action={<Btn onClick={openNew}>+ Nuevo Usuario</Btn>}/>
      <Card noPad><Table cols={cols} rows={localUsers}/></Card>

      {showModal && (
        <Modal title={editing?'Editar Usuario':'Nuevo Usuario'} onClose={()=>setShowModal(false)} width={620}>
          <Row>
            <FInput label="Nombre *" value={form.name} onChange={e=>sf('name',e.target.value)} placeholder="Nombre"/>
            <FInput label="Apellidos *" value={form.apellidos} onChange={e=>sf('apellidos',e.target.value)} placeholder="Apellidos"/>
          </Row>
          <Row>
            <FInput label="Nombre de usuario *" value={form.username} onChange={e=>sf('username',e.target.value)} placeholder="usuario"/>
            <FInput label={editing?'Nueva contraseña (vacío = sin cambio)':'Contraseña *'} type="password" value={form.password} onChange={e=>sf('password',e.target.value)} placeholder="••••••••"/>
          </Row>
          <Row>
            <FInput label="Correo electrónico" type="email" value={form.email} onChange={e=>sf('email',e.target.value)} placeholder="correo@empresa.com"/>
            <FInput label="Teléfono / Celular" value={form.phone} onChange={e=>sf('phone',e.target.value)} placeholder="+51 999 999 999"/>
          </Row>
          <FSelect label="Rol" value={form.role} onChange={e=>sf('role',e.target.value)} options={['Administrador','Usuario'].map(r=>({value:r,label:r}))}/>
          {form.role==='Usuario' && (
            <div>
              <div style={{...T.sm,marginBottom:10,textTransform:'uppercase',letterSpacing:0.5,borderBottom:`1px solid ${G.border}`,paddingBottom:6}}>Permisos</div>
              <div style={{background:G.bg,border:`1px solid ${G.border}`,borderRadius:6,padding:'8px 12px',marginBottom:12,fontSize:11,color:G.textSec}}>
                Sin ningún permiso activo, el usuario puede ver el <b style={{color:G.text}}>Dashboard</b>, <b style={{color:G.text}}>Catálogo</b> y <b style={{color:G.text}}>Almacén</b> (sin precios).
              </div>
              {permGroups.map(group=>(
                <div key={group.label} style={{marginBottom:14}}>
                  <div style={{fontSize:10,color:G.accent,textTransform:'uppercase',letterSpacing:0.5,marginBottom:6,fontWeight:700}}>{group.label}</div>
                  <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:5}}>
                    {group.perms.map(([k,label])=>(
                      <label key={k} style={{display:'flex',alignItems:'center',gap:8,cursor:'pointer',padding:'5px 8px',borderRadius:4,background:form.perms[k]?G.accent+'11':'transparent',border:`1px solid ${form.perms[k]?G.accent+'33':G.border}`}}>
                        <input type="checkbox" checked={!!form.perms[k]} onChange={e=>sp(k,e.target.checked)} style={{accentColor:G.accent}}/>
                        <span style={{fontSize:11,color:form.perms[k]?G.text:G.textSec}}>{label}</span>
                      </label>
                    ))}
                  </div>
                </div>
              ))}
            </div>
          )}
          {form.role==='Administrador' && <div style={{background:G.accentDark+'22',border:`1px solid ${G.accent}33`,borderRadius:6,padding:'8px 12px',fontSize:12,color:G.accent,marginTop:8}}>Los administradores tienen acceso completo a todos los módulos.</div>}
          <div style={{display:'flex',justifyContent:'flex-end',gap:8,marginTop:16}}>
            <Btn variant="secondary" onClick={()=>setShowModal(false)}>Cancelar</Btn>
            <Btn onClick={save}>{editing?'Guardar Cambios':'Crear Usuario'}</Btn>
          </div>
        </Modal>
      )}

      {carteraModal && (
        <Modal title={`Cartera de ${carteraModal.name} ${carteraModal.apellidos||''}`} onClose={()=>{setCarteraModal(null);setCarteraData(null);}} width={660}>
          {!carteraData ? (
            <div style={{color:G.textSec,fontSize:13,padding:20,textAlign:'center'}}>Cargando datos…</div>
          ) : (
            <div>
              <div style={{marginBottom:16}}>
                <div style={{fontSize:11,color:G.textSec,textTransform:'uppercase',letterSpacing:0.5,marginBottom:8}}>Clientes en cartera ({carteraData.clients.length})</div>
                {carteraData.clients.length === 0 ? (
                  <div style={{color:G.textSec,fontSize:12,padding:'12px',background:G.bg,borderRadius:6,border:`1px solid ${G.border}`}}>Sin clientes en cartera</div>
                ) : (
                  <div style={{background:G.bg,border:`1px solid ${G.border}`,borderRadius:6,overflow:'hidden'}}>
                    {carteraData.clients.map((c,i)=>(
                      <div key={c.id} style={{display:'flex',alignItems:'center',justifyContent:'space-between',padding:'8px 14px',borderBottom:i<carteraData.clients.length-1?`1px solid ${G.border}`:'none',opacity:c.hidden_for_owner?0.5:1}}>
                        <div>
                          <div style={{fontSize:12,fontWeight:500,color:G.text}}>{c.name} {c.hidden_for_owner && <Tag label="Eliminado" color={G.error}/>}</div>
                          <div style={{fontSize:10,color:G.textSec}}>RUC: {c.ruc||'—'} · {c.email||'sin email'}</div>
                        </div>
                        <span style={{fontSize:10,color:G.textSec}}>{c.phone||'—'}</span>
                      </div>
                    ))}
                  </div>
                )}
              </div>
              <div>
                <div style={{fontSize:11,color:G.textSec,textTransform:'uppercase',letterSpacing:0.5,marginBottom:8}}>Últimas cotizaciones ({carteraData.quotes.length})</div>
                {carteraData.quotes.length === 0 ? (
                  <div style={{color:G.textSec,fontSize:12,padding:'12px',background:G.bg,borderRadius:6,border:`1px solid ${G.border}`}}>Sin cotizaciones registradas</div>
                ) : (
                  <div style={{background:G.bg,border:`1px solid ${G.border}`,borderRadius:6,overflow:'hidden'}}>
                    {carteraData.quotes.map((q,i)=>(
                      <div key={q.id} style={{display:'flex',alignItems:'center',justifyContent:'space-between',padding:'7px 14px',borderBottom:i<carteraData.quotes.length-1?`1px solid ${G.border}`:'none'}}>
                        <div>
                          <span style={{color:G.accent,fontWeight:600,fontSize:12}}>{q.id}</span>
                          <span style={{color:G.textSec,fontSize:11,marginLeft:8}}>{q.client}</span>
                        </div>
                        <div style={{display:'flex',alignItems:'center',gap:10}}>
                          <span style={{fontSize:11,fontWeight:700,color:G.text}}>{fmtS(q.total)}</span>
                          <StatusBadge status={q.status}/>
                        </div>
                      </div>
                    ))}
                  </div>
                )}
              </div>
            </div>
          )}
        </Modal>
      )}
    </div>
  );
}

// ─── MIS CLIENTES (Cartera de clientes del usuario) ───────────
function MisClientes({ contacts, setContacts, quotes, currentUser, creditRequests }) {
  const [showModal, setShowModal] = useState(false);
  const [editingId, setEditingId] = useState(null);
  const [viewHistory, setViewHistory] = useState(null);
  const [history, setHistory] = useState([]);
  const [creditReqModal, setCreditReqModal] = useState(null);
  const [creditReqDays, setCreditReqDays] = useState(30);
  const [creditReqReason, setCreditReqReason] = useState('');
  const [formErr, setFormErr] = useState('');

  const canCredit = currentUser?.role==='Administrador' || !!currentUser?.perms?.otorgarCredito;

  const blankForm = {name:'',ruc:'',credit:0,email:'',phone:'',attn:'',direccion:'',note:''};
  const [form, setForm] = useState(blankForm);
  const sf = (k,v) => setForm(f=>({...f,[k]:v}));

  const myClients = (contacts||[]).filter(c=>
    c.type==='cliente' && c.ownerId===currentUser?.id && !c.hiddenForOwner
  );
  const myQuotes = (quotes||[]).filter(q=>q.createdBy===currentUser?.username);
  const myCreditReqs = (creditRequests||[]).filter(cr=>cr.owner_id===currentUser?.id);

  const openNew  = () => { setForm(blankForm); setEditingId(null); setFormErr(''); setShowModal(true); };
  const openEdit = (c) => {
    setForm({name:c.name,ruc:c.ruc||'',credit:c.credit||0,email:c.email||'',phone:c.phone||'',attn:c.attn||'',direccion:c.direccion||'',note:c.note||''});
    setEditingId(c.id); setFormErr(''); setShowModal(true);
  };

  const openHistory = async (c) => {
    setViewHistory(c);
    const res = await window.api(`/contacts/${c.id}/sales-history`);
    if(res && res.ok) setHistory(await res.json()); else setHistory([]);
  };

  const save = async () => {
    // Campos obligatorios: nombre, ruc, attn, phone
    if(!form.name.trim())  return setFormErr('El nombre / razón social es obligatorio.');
    if(!form.ruc.trim())   return setFormErr('El RUC es obligatorio.');
    if(!form.attn.trim())  return setFormErr('La persona de contacto es obligatoria.');
    if(!form.phone.trim()) return setFormErr('El teléfono es obligatorio.');
    setFormErr('');
    const body = {type:'cliente', ...form, credit: canCredit ? +form.credit : 0};
    const res = await window.api(editingId?`/contacts/${editingId}`:'/contacts', {
      method: editingId?'PUT':'POST', body:JSON.stringify(body)
    });
    if(res && res.ok) {
      const saved = await res.json();
      if(editingId) setContacts(cs=>cs.map(c=>c.id===editingId?saved:c));
      else          setContacts(cs=>[...cs,saved]);
      setShowModal(false);
    }
  };

  const hide = async (id) => {
    const res = await window.api(`/contacts/${id}`, {method:'DELETE'});
    if(res && res.ok) setContacts(cs=>cs.filter(c=>c.id!==id));
  };

  const sendCreditRequest = async () => {
    if(!creditReqModal) return;
    const res = await window.api('/credit-requests', {
      method:'POST',
      body: JSON.stringify({contactId: creditReqModal.id, reqDays: creditReqDays, reason: creditReqReason})
    });
    if(res && res.ok) {
      alert(`Solicitud enviada. El administrador revisará el crédito para ${creditReqModal.name}.`);
      setCreditReqModal(null); setCreditReqReason('');
    }
  };

  const months = ['Ene','Feb','Mar','Abr','May','Jun','Jul','Ago','Sep','Oct','Nov','Dic'];

  const cols = [
    {key:'name',label:'Cliente',render:c=>(
      <div>
        <div style={{fontSize:13,fontWeight:500,color:G.text}}>{c.name}</div>
        <div style={{fontSize:10,color:G.textSec}}>RUC: {c.ruc||'—'} · {c.attn||'—'} · {c.phone||'—'}</div>
      </div>
    )},
    {key:'credit',label:'Crédito',w:120,render:c=>(
      <div style={{display:'flex',alignItems:'center',gap:6,flexWrap:'wrap'}}>
        <CreditBadge days={c.credit}/>
        {!canCredit && (
          <button onClick={()=>{setCreditReqModal(c);setCreditReqDays(c.credit>0?Math.min(c.credit*2,120):30);setCreditReqReason('');}}
            style={{background:'none',border:`1px solid ${G.warning}`,color:G.warning,fontSize:9,padding:'1px 5px',borderRadius:3,cursor:'pointer',fontWeight:700}}>
            {c.credit===0?'Solicitar crédito':'↑ Ampliar'}
          </button>
        )}
      </div>
    )},
    {key:'cots',label:'Cots.',w:60,render:c=>(
      <span style={{fontSize:12,fontWeight:700,color:G.accent}}>{myQuotes.filter(q=>q.clientId===c.id).length}</span>
    )},
    {key:'actions',label:'',w:100,render:c=>(
      <div style={{display:'flex',gap:4}}>
        <Btn sm variant="ghost" onClick={()=>openHistory(c)}>📊</Btn>
        <Btn sm variant="ghost" onClick={()=>openEdit(c)}>✏️</Btn>
        <Btn sm variant="danger" onClick={()=>hide(c.id)}>✕</Btn>
      </div>
    )},
  ];

  return (
    <div>
      <PageHeader title="MIS CLIENTES" subtitle="Tu cartera de clientes" action={<Btn onClick={openNew}>+ Agregar Cliente</Btn>}/>

      {myCreditReqs.length > 0 && (
        <div style={{marginBottom:16}}>
          <div style={{fontSize:11,color:G.textSec,textTransform:'uppercase',letterSpacing:0.5,marginBottom:8}}>
            Mis solicitudes de crédito
          </div>
          <Card noPad>
            {myCreditReqs.map((cr,i)=>{
              const sc = cr.status==='pending'?G.warning:cr.status==='approved'?G.accent:G.error;
              const sl = cr.status==='pending'?'Pendiente':cr.status==='approved'?'Aprobada':'Rechazada';
              return (
                <div key={cr.id} style={{display:'flex',alignItems:'flex-start',justifyContent:'space-between',padding:'10px 14px',borderBottom:i<myCreditReqs.length-1?`1px solid ${G.border}`:'none'}}>
                  <div>
                    <div style={{fontSize:13,fontWeight:500,color:G.text}}>{cr.contact_name}</div>
                    <div style={{fontSize:11,color:G.textSec}}>Solicitado: {cr.req_days} días</div>
                  </div>
                  <div style={{display:'flex',flexDirection:'column',alignItems:'flex-end',gap:4}}>
                    <span style={{background:sc+'22',color:sc,padding:'2px 8px',borderRadius:3,fontSize:11,fontWeight:600}}>{sl}</span>
                    {cr.status==='approved' && (
                      <span style={{fontSize:11,color:G.accent,fontWeight:700}}>{cr.approved_days} días otorgados</span>
                    )}
                    {cr.user_note && (
                      <span style={{fontSize:11,color:G.textSec,fontStyle:'italic',maxWidth:220,textAlign:'right'}}>"{cr.user_note}"</span>
                    )}
                  </div>
                </div>
              );
            })}
          </Card>
        </div>
      )}

      {myClients.length===0 ? (
        <div style={{background:G.card,border:`1px solid ${G.border}`,borderRadius:8,padding:40,textAlign:'center'}}>
          <div style={{fontSize:32,marginBottom:12}}>👥</div>
          <div style={{fontSize:14,color:G.text,fontWeight:600,marginBottom:6}}>Tu cartera está vacía</div>
          <div style={{fontSize:12,color:G.textSec,marginBottom:16}}>Agrega clientes para gestionarlos y asociarles cotizaciones</div>
          <Btn onClick={openNew}>+ Agregar primer cliente</Btn>
        </div>
      ) : (
        <Card noPad><Table cols={cols} rows={myClients}/></Card>
      )}

      {showModal && (
        <Modal title={editingId?'Editar Cliente':'Nuevo Cliente'} onClose={()=>setShowModal(false)} width={500}>
          <Row>
            <FInput label="Razón Social / Nombre *" value={form.name} onChange={e=>sf('name',e.target.value)} placeholder="Empresa SAC"/>
            <FInput label="RUC *" value={form.ruc} onChange={e=>sf('ruc',e.target.value)} placeholder="20XXXXXXXXX"/>
          </Row>
          <Row>
            <FInput label="Persona de contacto *" value={form.attn} onChange={e=>sf('attn',e.target.value)} placeholder="Nombre del contacto"/>
            <FInput label="Teléfono *" value={form.phone} onChange={e=>sf('phone',e.target.value)} placeholder="+51 9XX XXX XXX"/>
          </Row>
          <Row>
            <FInput label="Email" type="email" value={form.email} onChange={e=>sf('email',e.target.value)}/>
            {canCredit ? (
              <FSelect label="Crédito" value={form.credit} onChange={e=>sf('credit',+e.target.value)} options={[0,30,60,90,120].map(d=>({value:d,label:d===0?'Contado':`${d} días`}))}/>
            ) : (
              <div style={{flex:1}}>
                <div style={{...T.sm,marginBottom:4}}>Crédito</div>
                <div style={{background:G.bg,border:`1px solid ${G.border}`,borderRadius:5,padding:'7px 11px',fontSize:13,color:G.textSec}}>Contado (solicitar al admin)</div>
              </div>
            )}
          </Row>
          <FInput label="Dirección" value={form.direccion} onChange={e=>sf('direccion',e.target.value)} placeholder="Av. Ejemplo 123, Lima"/>
          <FTextarea label="Nota" value={form.note} onChange={e=>sf('note',e.target.value)} rows={2}/>
          {formErr && <div style={{color:G.error,fontSize:12,marginBottom:8}}>⚠ {formErr}</div>}
          <div style={{display:'flex',justifyContent:'flex-end',gap:8,marginTop:8}}>
            <Btn variant="secondary" onClick={()=>setShowModal(false)}>Cancelar</Btn>
            <Btn onClick={save}>{editingId?'Guardar Cambios':'Agregar Cliente'}</Btn>
          </div>
        </Modal>
      )}

      {creditReqModal && (
        <Modal title={`Solicitar crédito — ${creditReqModal.name}`} onClose={()=>setCreditReqModal(null)} width={420}>
          <div style={{background:G.bg,border:`1px solid ${G.border}`,borderRadius:6,padding:'10px 14px',marginBottom:14,fontSize:12,color:G.textSec}}>
            Crédito actual: <span style={{fontWeight:700,color:G.text}}>{creditReqModal.credit===0?'Contado':`${creditReqModal.credit} días`}</span>
          </div>
          <FSelect label="Días de crédito solicitados" value={creditReqDays} onChange={e=>setCreditReqDays(+e.target.value)}
            options={[30,60,90,120].filter(d=>d>creditReqModal.credit).map(d=>({value:d,label:`${d} días`}))}/>
          <FTextarea label="Motivo / justificación *" value={creditReqReason} onChange={e=>setCreditReqReason(e.target.value)} rows={3} placeholder="Ej: Cliente frecuente con buen historial de pago…"/>
          <div style={{display:'flex',justifyContent:'flex-end',gap:8,marginTop:8}}>
            <Btn variant="secondary" onClick={()=>setCreditReqModal(null)}>Cancelar</Btn>
            <Btn onClick={sendCreditRequest} disabled={!creditReqReason.trim()}>Enviar solicitud</Btn>
          </div>
        </Modal>
      )}

      {viewHistory && (
        <Modal title={`Historial — ${viewHistory.name}`} onClose={()=>{setViewHistory(null);setHistory([]);}} width={560}>
          {history.length===0 ? (
            <div style={{color:G.textSec,fontSize:12,textAlign:'center',padding:20}}>Sin historial de ventas aceptadas</div>
          ) : (
            <div>
              {Object.entries(history.reduce((acc,r)=>{
                const key=`${r.year}-${r.month}`;
                if(!acc[key]) acc[key]={year:r.year,month:r.month,rows:[],total:0};
                acc[key].rows.push(r); acc[key].total+=+r.total; return acc;
              },{})).map(([key,g])=>(
                <div key={key} style={{marginBottom:14}}>
                  <div style={{fontSize:11,color:G.accent,fontWeight:700,marginBottom:6}}>{months[g.month-1]} {g.year} — {fmtS(g.total)}</div>
                  {g.rows.map((r,i)=>(
                    <div key={i} style={{display:'flex',justifyContent:'space-between',padding:'4px 10px',background:G.bg,borderRadius:4,marginBottom:2}}>
                      <span style={{fontSize:12,color:G.text}}>{r.name}</span>
                      <span style={{fontSize:12,color:G.textSec}}>{r.qty} uds — <span style={{color:G.accent,fontWeight:600}}>{fmtS(r.total)}</span></span>
                    </div>
                  ))}
                </div>
              ))}
            </div>
          )}
        </Modal>
      )}
    </div>
  );
}

// ─── SOLICITUDES DE CRÉDITO ───────────────────────────────────
function SolicitudesCredito({ creditRequests, setCreditRequests, operationRequests, setOperationRequests, currentUser, setQuotes }) {
  const [actionModal, setActionModal] = useState(null); // { req, action: 'approve'|'reject' }
  const [approveDays, setApproveDays] = useState(30);
  const [userNote, setUserNote] = useState('');
  const [internalNote, setInternalNote] = useState('');
  const [processing, setProcessing] = useState(false);

  React.useEffect(()=>{
    if (!creditRequests) {
      window.api('/credit-requests').then(r=>r&&r.json()).then(d=>{ if(Array.isArray(d)&&setCreditRequests) setCreditRequests(d); });
    }
    if (!operationRequests) {
      window.api('/operation-requests').then(r=>r&&r.json()).then(d=>{ if(Array.isArray(d)&&setOperationRequests) setOperationRequests(d); });
    }
  }, []);

  const requests = creditRequests || [];
  const opRequests = operationRequests || [];

  const openModal = (req, action) => {
    setActionModal({ req, action });
    setApproveDays(req.req_days);
    setUserNote('');
    setInternalNote('');
  };

  const handle = async () => {
    if (!actionModal) return;
    const { req, action } = actionModal;
    setProcessing(true);
    try {
      const res = await window.api(`/credit-requests/${req.id}`, {
        method: 'PUT',
        body: JSON.stringify({ action, approvedDays: action==='approve' ? approveDays : undefined, userNote, internalNote })
      });
      if (res && res.ok) {
        const updated = await res.json();
        if (setCreditRequests) setCreditRequests(rs => rs.map(r => r.id === req.id ? updated : r));
        setActionModal(null);
      }
    } finally { setProcessing(false); }
  };

  const pending = requests.filter(r => r.status === 'pending');
  const opPending = opRequests.filter(r => r.status === 'pending');

  const statusBadge = (s) => {
    const c = s==='pending'?G.warning:s==='approved'?G.accent:G.error;
    const l = s==='pending'?'Pendiente':s==='approved'?'Aprobada':'Rechazada';
    return <span style={{background:c+'22',color:c,padding:'2px 8px',borderRadius:3,fontSize:11,fontWeight:600}}>{l}</span>;
  };

  const cols = [
    {key:'contact',label:'Cliente',render:r=>(
      <div>
        <div style={{fontWeight:500,fontSize:13,color:G.text}}>{r.contact_name}</div>
        <div style={{fontSize:10,color:G.textSec}}>RUC: {r.ruc||'—'}</div>
      </div>
    )},
    {key:'empleado',label:'Empleado',w:140,render:r=>(
      <div>
        <div style={{fontSize:12,fontWeight:500,color:G.text}}>{r.owner_name||'—'}</div>
        <div style={{fontSize:10,color:G.textSec}}>@{r.owner_username}</div>
      </div>
    )},
    {key:'req',label:'Días solicitados',w:130,render:r=><span style={{fontWeight:700,color:G.warning}}>{r.req_days} días</span>},
    {key:'reason',label:'Motivo del empleado',render:r=><span style={{fontSize:12,color:G.textSec}}>{r.reason||'—'}</span>},
    {key:'status',label:'Estado',w:110,render:r=>statusBadge(r.status)},
    {key:'result',label:'Notas',w:200,render:r=>(
      <div style={{display:'flex',flexDirection:'column',gap:3}}>
        {r.status==='approved' && <span style={{color:G.accent,fontWeight:700,fontSize:12}}>{r.approved_days} días otorgados</span>}
        {r.user_note && (
          <span style={{fontSize:11,color:G.textSec}}>
            <span style={{color:G.text,fontWeight:600}}>💬 Empleado: </span>{r.user_note}
          </span>
        )}
        {r.internal_note && (
          <span style={{fontSize:11,color:G.warning}}>
            <span style={{fontWeight:600}}>🔒 Interna: </span>{r.internal_note}
          </span>
        )}
        {!r.user_note && !r.internal_note && r.status!=='pending' && (
          <span style={{color:G.textSec,fontSize:12}}>—</span>
        )}
      </div>
    )},
    {key:'actions',label:'',w:170,render:r=>r.status==='pending'?(
      <div style={{display:'flex',gap:4}}>
        <Btn sm variant="accent" onClick={()=>openModal(r,'approve')}>✓ Aprobar</Btn>
        <Btn sm variant="danger" onClick={()=>openModal(r,'reject')}>✕ Rechazar</Btn>
      </div>
    ) : null},
  ];

  const isApprove = actionModal?.action === 'approve';

  const handleOp = async (req, action) => {
    const managerNote = action === 'reject' ? prompt('Motivo de rechazo (opcional):') : '';
    const res = await window.api(`/operation-requests/${req.id}`, {
      method:'PUT',
      body: JSON.stringify({ action, managerNote }),
    });
    if (res && res.ok) {
      const updated = await res.json();
      if (setOperationRequests) setOperationRequests(rs => rs.map(r => r.id === req.id ? updated : r));
      window.api('/quotes').then(r=>r&&r.json()).then(d=>{ if(Array.isArray(d)&&setQuotes) setQuotes(d); });
      if (window.refreshDashboard) window.refreshDashboard();
    } else if (res) {
      const err = await res.json().catch(()=>({}));
      alert(err.error || 'Error procesando solicitud');
    }
  };

  const opTypeLabel = (t) => t === 'confirm_oc' ? 'Confirmar OC' : 'Entregar y facturar';
  const opCols = [
    {key:'type',label:'Solicitud',w:140,render:r=><Tag label={opTypeLabel(r.type)} color={r.type==='confirm_oc'?G.warning:G.accent}/>},
    {key:'quote',label:'Cotización',w:120,render:r=><span style={{color:G.accent,fontWeight:700}}>{r.quoteId}</span>},
    {key:'client',label:'Cliente',render:r=><span style={{fontSize:12,color:G.text}}>{r.client||'—'}</span>},
    {key:'requester',label:'Solicita',w:130,render:r=><span style={{fontSize:12,color:G.textSec}}>@{r.requesterUsername}</span>},
    {key:'payload',label:'Datos',render:r=>(
      <span style={{fontSize:11,color:G.textSec}}>
        {r.type==='confirm_oc' ? `OC ${r.payload?.ocNum||'—'} · entrega ${r.payload?.deliveryDate||'—'}` : `Factura ${r.payload?.invoice||'—'}`}
      </span>
    )},
    {key:'status',label:'Estado',w:110,render:r=>statusBadge(r.status)},
    {key:'actions',label:'',w:170,render:r=>r.status==='pending'?(
      <div style={{display:'flex',gap:4}}>
        <Btn sm variant="accent" onClick={()=>handleOp(r,'approve')}>✓ Aprobar</Btn>
        <Btn sm variant="danger" onClick={()=>handleOp(r,'reject')}>✕ Rechazar</Btn>
      </div>
    ):null},
  ];

  return (
    <div>
      <PageHeader title="SOLICITUDES" subtitle={`${pending.length + opPending.length} pendiente${pending.length + opPending.length!==1?'s':''} de revisión`}/>
      <Card title={`Solicitudes de operaciones — ${opPending.length} pendiente${opPending.length!==1?'s':''}`} noPad style={{marginBottom:14}}>
        <Table cols={opCols} rows={opRequests} emptyMsg="No hay solicitudes operativas"/>
      </Card>
      {pending.length > 0 && (
        <div style={{background:G.warning+'11',border:`1px solid ${G.warning}44`,borderRadius:8,padding:'10px 16px',marginBottom:14,fontSize:12,color:G.warning}}>
          ⚠ Hay {pending.length} solicitud{pending.length!==1?'es':''} de crédito esperando tu aprobación.
        </div>
      )}
      <Card noPad>
        <Table cols={cols} rows={requests} emptyMsg="No hay solicitudes de crédito"/>
      </Card>
      {actionModal && (
        <Modal
          title={isApprove ? `Aprobar crédito — ${actionModal.req.contact_name}` : `Rechazar solicitud — ${actionModal.req.contact_name}`}
          onClose={()=>setActionModal(null)}
          width={460}
        >
          <div style={{fontSize:12,color:G.textSec,marginBottom:14}}>
            Solicitud de <b style={{color:G.text}}>@{actionModal.req.owner_username}</b> · <b style={{color:G.text}}>{actionModal.req.contact_name}</b>
          </div>
          {actionModal.req.reason && (
            <div style={{background:G.bg,border:`1px solid ${G.border}`,borderRadius:5,padding:'8px 12px',marginBottom:14,fontSize:12,color:G.textSec}}>
              <span style={{color:G.text,fontWeight:600}}>Motivo del empleado:</span> {actionModal.req.reason}
            </div>
          )}
          {isApprove && (
            <FSelect label="Días de crédito a otorgar" value={approveDays} onChange={e=>setApproveDays(+e.target.value)} options={[30,60,90,120].map(d=>({value:d,label:`${d} días`}))}/>
          )}
          <FInput
            label="Nota para el empleado (él la verá en sus solicitudes)"
            value={userNote}
            onChange={e=>setUserNote(e.target.value)}
            placeholder={isApprove ? 'Ej: Aprobado, buen historial de pagos' : 'Ej: Necesitamos más ventas antes de ampliar el crédito'}
          />
          <FTextarea
            label="Nota interna (solo visible para administración)"
            value={internalNote}
            onChange={e=>setInternalNote(e.target.value)}
            rows={2}
            placeholder="Ej: Revisar situación del cliente en 3 meses…"
          />
          <div style={{display:'flex',justifyContent:'flex-end',gap:8,marginTop:8}}>
            <Btn variant="secondary" onClick={()=>setActionModal(null)}>Cancelar</Btn>
            <Btn variant={isApprove?'primary':'danger'} onClick={handle} disabled={processing}>
              {processing ? 'Procesando…' : isApprove ? 'Aprobar y otorgar crédito' : 'Rechazar solicitud'}
            </Btn>
          </div>
        </Modal>
      )}
    </div>
  );
}

Object.assign(window, { Contabilidad, Contactos, Historial, Usuarios, Festivos, Gastos, MisClientes, SolicitudesCredito });

// ─── FESTIVOS ─────────────────────────────────────────────────
function Festivos() {
  const [festivos, setFestivos] = React.useState([]);
  const [showModal, setShowModal] = React.useState(false);
  const [form, setForm] = React.useState({name:'',date:''});
  const sf = (k,v) => setForm(f=>({...f,[k]:v}));

  React.useEffect(()=>{
    window.api('/festivos').then(r=>r&&r.json()).then(d=>{ if(Array.isArray(d)) setFestivos(d); });
  }, []);

  const del = async (id) => {
    const res = await window.api(`/festivos/${id}`, {method:'DELETE'});
    if(res && res.ok) setFestivos(fs=>fs.filter(f=>f.id!==id));
  };
  const save = async () => {
    if(!form.name||!form.date) return;
    const res = await window.api('/festivos', {method:'POST', body:JSON.stringify({name:form.name,date:form.date})});
    if(res && res.ok) {
      const created = await res.json();
      setFestivos(fs=>[...fs,created]);
      setShowModal(false); setForm({name:'',date:''});
    }
  };

  const cols = [
    {key:'date',label:'Fecha',w:120,render:r=><span style={{fontFamily:'monospace',color:G.accent,fontWeight:600}}>{r.date}</span>},
    {key:'name',label:'Descripción',render:r=><span style={{fontSize:13}}>{r.name}</span>},
    {key:'del',label:'',w:60,render:r=><Btn sm variant="danger" onClick={()=>del(r.id)}>✕</Btn>},
  ];

  // Group by month
  const sorted = [...festivos].sort((a,b)=>{
    const [da,ma] = a.date.split('/').map(Number);
    const [db,mb] = b.date.split('/').map(Number);
    return ma!==mb?ma-mb:da-db;
  });

  return (
    <div>
      <PageHeader title="DÍAS FESTIVOS / NO LABORABLES"
        subtitle="Fechas que no se computan como días hábiles en entregas"
        action={<Btn onClick={()=>setShowModal(true)}>+ Agregar Festivo</Btn>}/>
      <div style={{background:G.card,border:`1px solid ${G.warning}33`,borderRadius:8,padding:'10px 16px',marginBottom:16,fontSize:12,color:G.warning}}>
        ⚠ Estos días se excluyen automáticamente del cálculo de fecha de entrega en cotizaciones.
      </div>
      <Card noPad>
        <Table cols={cols} rows={sorted} emptyMsg="No hay festivos registrados"/>
      </Card>
      {showModal && (
        <Modal title="Agregar Día Festivo" onClose={()=>setShowModal(false)} width={400}>
          <FInput label="Nombre / Descripción *" value={form.name} onChange={e=>sf('name',e.target.value)} placeholder="Ej: Día del Trabajo"/>
          <FInput label="Fecha (DD/MM/YYYY) *" value={form.date} onChange={e=>sf('date',e.target.value)} placeholder="01/05/2026"/>
          <div style={{display:'flex',justifyContent:'flex-end',gap:8,marginTop:8}}>
            <Btn variant="secondary" onClick={()=>setShowModal(false)}>Cancelar</Btn>
            <Btn onClick={save}>Guardar</Btn>
          </div>
        </Modal>
      )}
    </div>
  );
}

// ─── GASTOS ───────────────────────────────────────────────────
const MESES_G = ['Ene','Feb','Mar','Abr','May','Jun','Jul','Ago','Sep','Oct','Nov','Dic'];
function Gastos() {
  const [gastos,        setGastos]        = React.useState([]);
  const [tab,           setTab]           = React.useState('periodo');
  const [showModal,     setShowModal]     = React.useState(false);
  const [showFijoModal, setShowFijoModal] = React.useState(false);
  const [showDonutBig,  setShowDonutBig]  = React.useState(false);
  const [form,     setForm]     = React.useState({date:'',category:'Alquiler',desc:'',amount:'',paid:false});
  const [fijoForm, setFijoForm] = React.useState({category:'Alquiler',desc:'',amount:'',dueDay:''});
  const [filterYear,  setFilterYear]  = React.useState('todos');
  const [filterMonth, setFilterMonth] = React.useState('todos');
  const [errMsg,      setErrMsg]      = React.useState('');
  const sf  = (k,v) => setForm(f=>({...f,[k]:v}));
  const sff = (k,v) => setFijoForm(f=>({...f,[k]:v}));
  const cats = ['Alquiler','Servicios','Transporte','Sueldos','Marketing','Impuestos','Bancario','Otros'];
  const CAT_COLORS = {Alquiler:'#6DBF2E',Servicios:'#29B6F6',Transporte:'#FFA726',Sueldos:'#AB47BC',Marketing:'#FF7043',Impuestos:'#E53935',Bancario:'#26A69A',Otros:'#78909C'};

  React.useEffect(()=>{
    window.api('/gastos').then(r=>r&&r.json()).then(d=>{ if(Array.isArray(d)) setGastos(d); });
  }, []);

  const del = async (id) => {
    const res = await window.api(`/gastos/${id}`, {method:'DELETE'});
    if(res && res.ok) setGastos(gs=>gs.filter(g=>g.id!==id));
  };
  const save = async () => {
    console.log('[Gastos] save() form:', form);
    if(!form.desc || !form.amount) {
      setErrMsg('Completa descripción y monto antes de guardar.');
      return;
    }
    setErrMsg('');
    const res = await window.api('/gastos', {method:'POST', body:JSON.stringify({...form,amount:+form.amount,recurring:false})});
    if(res && res.ok) {
      const created = await res.json();
      setGastos(gs=>[...gs,created]);
      setShowModal(false); setForm({date:'',category:'Alquiler',desc:'',amount:'',paid:false});
    } else {
      const body = res ? await res.json().catch(()=>({})) : {};
      setErrMsg(body.error || 'Error al guardar el gasto. Revisa la consola.');
    }
  };
  const saveFijo = async () => {
    if(!fijoForm.desc||!fijoForm.amount) return;
    const res = await window.api('/gastos', {method:'POST', body:JSON.stringify({...fijoForm,amount:+fijoForm.amount,recurring:true,paid:false,dueDay:fijoForm.dueDay?+fijoForm.dueDay:null})});
    if(res && res.ok) {
      const created = await res.json();
      setGastos(gs=>[...gs,created]);
      setShowFijoModal(false); setFijoForm({category:'Alquiler',desc:'',amount:'',dueDay:''});
    }
  };
  const toggle = async (id) => {
    const res = await window.api(`/gastos/${id}/toggle`, {method:'PATCH'});
    if(res && res.ok) {
      const updated = await res.json();
      setGastos(gs=>gs.map(g=>g.id===id?updated:g));
    }
  };
  const aplicar = async (fijo) => {
    const now = new Date();
    const pad = n=>String(n).padStart(2,'0');
    let date;
    if (fijo.dueDay) {
      const d = new Date(now.getFullYear(), now.getMonth(), fijo.dueDay);
      date = `${pad(d.getDate())}/${pad(d.getMonth()+1)}/${d.getFullYear()}`;
    } else {
      date = `${pad(now.getDate())}/${pad(now.getMonth()+1)}/${now.getFullYear()}`;
    }
    const res = await window.api('/gastos', {method:'POST', body:JSON.stringify({
      category:fijo.category, desc:fijo.desc, amount:fijo.amount, date, recurring:false, paid:false
    })});
    if(res && res.ok) {
      const created = await res.json();
      setGastos(gs=>[created,...gs]);
    }
  };
  const aplicarTodos = async () => {
    for(const f of fijos) await aplicar(f);
    setTab('periodo');
  };

  const allPeriodicos = gastos.filter(g=>!g.recurring && g.category !== 'Compras');
  const fijos         = gastos.filter(g=>g.recurring);
  const totalFijos    = fijos.reduce((s,g)=>s+g.amount,0);

  // Available years for filter
  const availYears = ['todos', ...[...new Set(allPeriodicos.map(g=>{
    const parts=(g.date||'').split('/'); return parts[2]||'';
  }).filter(Boolean))].sort((a,b)=>+b-+a)];
  const availMonths = ['todos',...MESES_G];

  // Apply filters
  const periodicos = allPeriodicos.filter(g=>{
    const parts=(g.date||'').split('/');
    const y=parts[2]||''; const m=+parts[1]||0;
    if(filterYear!=='todos' && y!==filterYear) return false;
    if(filterMonth!=='todos' && MESES_G[m-1]!==filterMonth) return false;
    return true;
  });

  const totalGastos = periodicos.reduce((s,g)=>s+g.amount,0);
  const pendiente   = periodicos.filter(g=>!g.paid).reduce((s,g)=>s+g.amount,0);
  const pagado      = periodicos.filter(g=>g.paid).reduce((s,g)=>s+g.amount,0);

  const byCat   = cats.map(c=>({cat:c, total:periodicos.filter(g=>g.category===c).reduce((s,g)=>s+g.amount,0)})).filter(x=>x.total>0);
  const byCatOp = byCat.filter(x=>x.cat!=='Compras');
  const donutData = byCatOp.map(x=>({label:x.cat,value:x.total,color:CAT_COLORS[x.cat]||'#888'}));
  const totalOp = byCatOp.reduce((s,x)=>s+x.total,0)||1;

  // Bar chart: if year filter active show all 12 months of that year, else last 12 months
  const barData = React.useMemo(()=>{
    const now = new Date();
    const slots = [];
    if(filterYear!=='todos'){
      const y=+filterYear;
      for(let m=0;m<12;m++) slots.push({m:MESES_G[m],mm:m+1,yyyy:y});
    } else {
      for(let i=11;i>=0;i--){
        const d=new Date(now.getFullYear(),now.getMonth()-i,1);
        slots.push({m:MESES_G[d.getMonth()],mm:d.getMonth()+1,yyyy:d.getFullYear()});
      }
    }
    return slots.map(s=>({
      m:s.m,
      v:allPeriodicos.filter(g=>{
        const p=(g.date||'').split('/');
        return +p[1]===s.mm && +p[2]===s.yyyy && g.category!=='Compras';
      }).reduce((a,g)=>a+g.amount,0),
    }));
  }, [allPeriodicos, filterYear]);

  const cols = [
    {key:'date',label:'Fecha',w:100,render:r=><span style={{fontSize:11,color:G.textSec}}>{r.date}</span>},
    {key:'category',label:'Categoría',w:110,render:r=><Tag label={r.category} color={G.accent}/>},
    {key:'desc',label:'Descripción',render:r=><span style={{fontSize:12}}>{r.desc}</span>},
    {key:'amount',label:'Monto',w:110,render:r=><span style={{color:G.warning,fontWeight:700}}>{fmtS(r.amount)}</span>},
    {key:'paid',label:'Estado',w:100,render:r=>(
      <span onClick={()=>toggle(r.id)} style={{background:r.paid?G.accent+'22':G.error+'22',color:r.paid?G.accent:G.error,padding:'2px 8px',borderRadius:3,fontSize:11,fontWeight:600,cursor:'pointer'}}>
        {r.paid?'Pagado':'Pendiente'}
      </span>
    )},
    {key:'del',label:'',w:50,render:r=><Btn sm variant="danger" onClick={()=>del(r.id)}>✕</Btn>},
  ];

  const fijosCols = [
    {key:'category',label:'Categoría',w:120,render:r=><Tag label={r.category} color={G.accent}/>},
    {key:'desc',label:'Descripción',render:r=><span style={{fontSize:12}}>{r.desc}</span>},
    {key:'amount',label:'Monto / mes',w:130,render:r=><span style={{color:G.warning,fontWeight:700}}>{fmtS(r.amount)}</span>},
    {key:'dueDay',label:'Día cobro',w:90,render:r=>r.dueDay?<span style={{fontSize:12,color:G.text}}>Día {r.dueDay}</span>:<span style={{fontSize:11,color:G.textSec}}>al aplicar</span>},
    {key:'actions',label:'',w:170,render:r=>(
      <div style={{display:'flex',gap:4,justifyContent:'flex-end'}}>
        <Btn sm variant="accent" onClick={()=>aplicar(r)}>+ Aplicar al mes</Btn>
        <Btn sm variant="danger" onClick={()=>del(r.id)}>✕</Btn>
      </div>
    )},
  ];

  const DonutLegend = ({data,total,size}) => (
    <div style={{display:'flex',gap:24,alignItems:'center',flexWrap:'wrap'}}>
      <div style={{position:'relative',flexShrink:0,cursor:'pointer'}} onClick={()=>setShowDonutBig(true)} title="Ampliar gráfico">
        <DonutChart data={data} size={size||150}/>
        <div style={{position:'absolute',top:'50%',left:'50%',transform:'translate(-50%,-50%)',textAlign:'center',pointerEvents:'none'}}>
          <div style={{fontFamily:"'Barlow Condensed',sans-serif",fontSize:size?15:13,fontWeight:700,color:G.warning,lineHeight:1}}>{fmtS(total)}</div>
          <div style={{fontSize:9,color:G.textSec}}>total</div>
        </div>
        <div style={{position:'absolute',bottom:-16,left:'50%',transform:'translateX(-50%)',fontSize:9,color:G.accent,whiteSpace:'nowrap'}}>🔍 Ampliar</div>
      </div>
      <div style={{flex:1,minWidth:200,display:'flex',flexDirection:'column',gap:7}}>
        {data.map(d=>(
          <div key={d.label} style={{display:'flex',alignItems:'center',gap:8}}>
            <div style={{width:10,height:10,borderRadius:'50%',background:d.color,flexShrink:0}}/>
            <span style={{fontSize:12,color:G.textSec,flex:1}}>{d.label}</span>
            <span style={{fontSize:12,fontWeight:700,color:G.warning}}>{fmtS(d.value)}</span>
            <span style={{fontSize:11,color:G.textSec,width:38,textAlign:'right'}}>{(d.value/total*100).toFixed(1)}%</span>
          </div>
        ))}
        {byCat.find(x=>x.cat==='Compras') && (
          <div style={{marginTop:4,fontSize:10,color:G.textSec,borderTop:`1px solid ${G.border}`,paddingTop:6}}>
            * Compras de mercancía ({fmtS(byCat.find(x=>x.cat==='Compras').total)}) excluidas → ver módulo Compras
          </div>
        )}
      </div>
    </div>
  );

  const selSt = {background:G.bg,border:`1px solid ${G.border}`,borderRadius:5,color:G.text,padding:'5px 10px',fontSize:12,outline:'none',fontFamily:"'Inter',sans-serif"};

  return (
    <div>
      <PageHeader title="GESTIÓN DE GASTOS" subtitle="Gastos operativos"
        action={tab==='fijos'
          ? <Btn onClick={()=>setShowFijoModal(true)}>+ Añadir Gasto Fijo</Btn>
          : <Btn onClick={()=>setShowModal(true)}>+ Registrar Gasto</Btn>
        }/>

      <Tabs tabs={['Del Período','Fijos']} active={tab==='periodo'?'Del Período':'Fijos'} onChange={t=>setTab(t==='Del Período'?'periodo':'fijos')}/>

      {tab==='periodo' && (
        <div>
          {/* Filtros */}
          <div style={{display:'flex',gap:8,alignItems:'center',marginBottom:14,flexWrap:'wrap'}}>
            <span style={{fontSize:11,color:G.textSec}}>Filtrar:</span>
            <select value={filterYear} onChange={e=>setFilterYear(e.target.value)} style={selSt}>
              {availYears.map(y=><option key={y} value={y}>{y==='todos'?'Todos los años':y}</option>)}
            </select>
            <select value={filterMonth} onChange={e=>setFilterMonth(e.target.value)} style={selSt}>
              {availMonths.map(m=><option key={m} value={m}>{m==='todos'?'Todos los meses':m}</option>)}
            </select>
            {(filterYear!=='todos'||filterMonth!=='todos') && (
              <button onClick={()=>{setFilterYear('todos');setFilterMonth('todos');}} style={{background:'none',border:'none',color:G.accent,cursor:'pointer',fontSize:12}}>✕ Limpiar</button>
            )}
          </div>

          <div style={{display:'flex',gap:12,marginBottom:18,flexWrap:'wrap'}}>
            <KPICard label="Total Gastos" value={fmtS(totalGastos)} color={G.warning} icon="💸"/>
            <KPICard label="Pagados" value={fmtS(pagado)} color={G.accent} icon="✅"/>
            <KPICard label="Pendiente de Pago" value={fmtS(pendiente)} color={G.error} icon="⏳"/>
            {totalFijos>0 && <KPICard label="Gastos Fijos / mes" value={fmtS(totalFijos)} color={G.textSec} icon="🔁"/>}
          </div>

          {/* Gráficos lado a lado */}
          {(donutData.length>0||barData.some(d=>d.v>0)) && (
            <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:16,marginBottom:16}}>
              {donutData.length>0 && (
                <Card title="Distribución por categoría (operativos)" style={{marginBottom:0}}>
                  <DonutLegend data={donutData} total={totalOp}/>
                </Card>
              )}
              <Card title={filterYear!=='todos'?`Gastos mes a mes — ${filterYear}`:'Gastos mes a mes (últimos 12 meses)'} style={{marginBottom:0}}>
                <BarChart data={barData} height={140}/>
                <div style={{display:'flex',justifyContent:'space-between',marginTop:6}}>
                  {barData.filter((_,i)=>i%3===0||i===barData.length-1).map((d,i)=>(
                    <div key={i} style={{textAlign:'center'}}>
                      <div style={{fontSize:9,color:G.textSec}}>{d.m}</div>
                      {d.v>0&&<div style={{fontSize:8,color:G.warning}}>{fmtS(d.v)}</div>}
                    </div>
                  ))}
                </div>
              </Card>
            </div>
          )}

          <Card noPad>
            <Table cols={cols} rows={periodicos} emptyMsg="Sin gastos registrados para este período"/>
          </Card>
        </div>
      )}

      {tab==='fijos' && (
        <div>
          {fijos.length>0 && (
            <div style={{background:G.card,border:`1px solid ${G.border}`,borderRadius:8,padding:'14px 20px',marginBottom:16,display:'flex',justifyContent:'space-between',alignItems:'center',flexWrap:'wrap',gap:12}}>
              <div>
                <div style={{fontSize:11,color:G.textSec,marginBottom:2}}>Total gastos fijos por mes</div>
                <div style={{fontFamily:"'Barlow Condensed',sans-serif",fontSize:28,fontWeight:700,color:G.warning,lineHeight:1}}>{fmtS(totalFijos)}</div>
              </div>
              <Btn onClick={aplicarTodos}>Aplicar todos al mes actual →</Btn>
            </div>
          )}
          <Card noPad>
            <Table cols={fijosCols} rows={fijos} emptyMsg="Sin gastos fijos definidos. Añade sueldos, alquiler y servicios mensuales."/>
          </Card>
        </div>
      )}

      {showModal && (
        <Modal title="Registrar Gasto" onClose={()=>{setShowModal(false);setErrMsg('');}} width={460}>
          <Row>
            <FInput label="Fecha" value={form.date} onChange={e=>sf('date',e.target.value)} placeholder="DD/MM/YYYY"/>
            <FSelect label="Categoría" value={form.category} onChange={e=>sf('category',e.target.value)} options={cats.map(c=>({value:c,label:c}))}/>
          </Row>
          <FInput label="Descripción *" value={form.desc} onChange={e=>sf('desc',e.target.value)} placeholder="Ej: Factura de luz Abril"/>
          <FInput label="Monto (S/) *" type="number" value={form.amount} onChange={e=>sf('amount',e.target.value)} placeholder="0.00"/>
          <label style={{display:'flex',alignItems:'center',gap:8,cursor:'pointer',marginBottom:14}}>
            <input type="checkbox" checked={form.paid} onChange={e=>sf('paid',e.target.checked)} style={{accentColor:G.accent}}/>
            <span style={{fontSize:12,color:G.textSec}}>Ya pagado</span>
          </label>
          {errMsg && <div style={{background:G.error+'22',border:`1px solid ${G.error}55`,borderRadius:5,padding:'7px 12px',fontSize:12,color:G.error,marginBottom:10}}>{errMsg}</div>}
          <div style={{display:'flex',justifyContent:'flex-end',gap:8}}>
            <Btn variant="secondary" onClick={()=>{setShowModal(false);setErrMsg('');}}>Cancelar</Btn>
            <Btn onClick={save}>Guardar Gasto</Btn>
          </div>
        </Modal>
      )}

      {showFijoModal && (
        <Modal title="Añadir Gasto Fijo Mensual" onClose={()=>setShowFijoModal(false)} width={460}>
          <div style={{background:G.bg,border:`1px solid ${G.border}`,borderRadius:6,padding:'10px 14px',marginBottom:14,fontSize:12,color:G.textSec}}>
            🔁 Los gastos fijos se definen una sola vez. Cada mes los aplicas con un clic para que aparezcan en el período correspondiente.
          </div>
          <FSelect label="Categoría" value={fijoForm.category} onChange={e=>sff('category',e.target.value)} options={cats.map(c=>({value:c,label:c}))}/>
          <FInput label="Descripción *" value={fijoForm.desc} onChange={e=>sff('desc',e.target.value)} placeholder="Ej: Alquiler local, Sueldo vendedor"/>
          <FInput label="Monto mensual (S/) *" type="number" value={fijoForm.amount} onChange={e=>sff('amount',e.target.value)} placeholder="0.00"/>
          <FSelect label="Día del mes para cobro (opcional)" value={fijoForm.dueDay} onChange={e=>sff('dueDay',e.target.value)} options={[{value:'',label:'Mismo día al aplicar'}, ...Array.from({length:31},(_,i)=>({value:String(i+1),label:`Día ${i+1}`}))]}/>
          <div style={{display:'flex',justifyContent:'flex-end',gap:8,marginTop:8}}>
            <Btn variant="secondary" onClick={()=>setShowFijoModal(false)}>Cancelar</Btn>
            <Btn onClick={saveFijo} disabled={!fijoForm.desc||!fijoForm.amount}>Guardar Gasto Fijo</Btn>
          </div>
        </Modal>
      )}

      {showDonutBig && donutData.length>0 && (
        <Modal title="Distribución de gastos operativos" onClose={()=>setShowDonutBig(false)} width={540}>
          <div style={{display:'flex',gap:32,alignItems:'center',flexWrap:'wrap',padding:'8px 0'}}>
            <div style={{position:'relative',flexShrink:0}}>
              <DonutChart data={donutData} size={240}/>
              <div style={{position:'absolute',top:'50%',left:'50%',transform:'translate(-50%,-50%)',textAlign:'center',pointerEvents:'none'}}>
                <div style={{fontFamily:"'Barlow Condensed',sans-serif",fontSize:20,fontWeight:700,color:G.warning,lineHeight:1}}>{fmtS(totalOp)}</div>
                <div style={{fontSize:10,color:G.textSec}}>total operativo</div>
              </div>
            </div>
            <div style={{flex:1,minWidth:180,display:'flex',flexDirection:'column',gap:10}}>
              {donutData.map(d=>(
                <div key={d.label} style={{display:'flex',alignItems:'center',gap:10}}>
                  <div style={{width:12,height:12,borderRadius:'50%',background:d.color,flexShrink:0}}/>
                  <span style={{fontSize:13,color:G.textSec,flex:1}}>{d.label}</span>
                  <span style={{fontSize:14,fontWeight:700,color:G.warning}}>{fmtS(d.value)}</span>
                  <span style={{fontSize:12,color:G.textSec,width:44,textAlign:'right'}}>{(d.value/totalOp*100).toFixed(1)}%</span>
                </div>
              ))}
              {byCat.find(x=>x.cat==='Compras') && (
                <div style={{marginTop:6,fontSize:10,color:G.textSec,borderTop:`1px solid ${G.border}`,paddingTop:8}}>
                  * Compras de mercancía ({fmtS(byCat.find(x=>x.cat==='Compras').total)}) excluidas → ver módulo Compras
                </div>
              )}
            </div>
          </div>
        </Modal>
      )}
    </div>
  );
}
