// ============================================================================
// PRESENTATIONAL COMPONENT: Charts.jsx & TransactionTable.jsx (SHADCN/UI STYLE)
// ============================================================================

const { useState, useEffect, useRef, useMemo, useCallback } = React;

function formatCurrencyPYG(val) {
  const num = Math.round(parseFloat(val) || 0);
  const formatted = num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.');
  return `G$ ${formatted}`;
}

const formatCurrencyBRL = formatCurrencyPYG;

function formatDateBR(dateStr) {
  if (!dateStr) return '';
  const parts = dateStr.split('-');
  return parts.length === 3 ? `${parts[2]}/${parts[1]}/${parts[0]}` : dateStr;
}

// FACTORY PATTERN: Badge de Tipo de Transação (Alto Contraste & Legibilidade)
function TransactionBadge({ type, title }) {
  let settings = null;
  try {
    if (typeof window.useFinance === 'function') {
      const ctx = window.useFinance();
      settings = ctx?.settings;
    }
  } catch (e) {}

  const creditLabel = settings?.movement_credit_title ? `+ ${settings.movement_credit_title}` : '+ Servicio Prestado';
  let debitLabel = settings?.movement_debit_title ? `- ${settings.movement_debit_title}` : '- Cuota';
  if (title) {
    const tLower = title.toLowerCase();
    if (tLower.includes('alan')) {
      debitLabel = '- Cuota (Alan)';
    } else if (tLower.includes('aleh')) {
      debitLabel = '- Cuota (Aleh)';
    }
  }
  const payRecLabel = settings?.movement_payment_received_title || 'Dinero en Mano / Recibido';
  const payMadeLabel = settings?.movement_payment_made_title || 'Pago Realizado';

  switch (type) {
    case 'CREDIT':
      return (
        <span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md bg-emerald-50 text-emerald-900 border border-emerald-300 font-bold text-xs whitespace-nowrap shadow-2xs">
          <span className="w-1.5 h-1.5 rounded-full bg-emerald-600 shrink-0"></span>
          <span>{creditLabel}</span>
        </span>
      );
    case 'DEBIT':
      return (
        <span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md bg-rose-50 text-rose-900 border border-rose-300 font-bold text-xs whitespace-nowrap shadow-2xs">
          <span className="w-1.5 h-1.5 rounded-full bg-rose-600 shrink-0"></span>
          <span>{debitLabel}</span>
        </span>
      );
    case 'PAYMENT_RECEIVED':
      return (
        <span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md bg-sky-50 text-sky-900 border border-sky-300 font-bold text-xs whitespace-nowrap shadow-2xs">
          <span className="w-1.5 h-1.5 rounded-full bg-sky-600 shrink-0"></span>
          <span>{payRecLabel}</span>
        </span>
      );
    case 'PAYMENT_MADE':
      return (
        <span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md bg-amber-50 text-amber-900 border border-amber-300 font-bold text-xs whitespace-nowrap shadow-2xs">
          <span className="w-1.5 h-1.5 rounded-full bg-amber-600 shrink-0"></span>
          <span>{payMadeLabel}</span>
        </span>
      );
    default:
      return (
        <span className="inline-flex items-center px-2 py-0.5 rounded bg-zinc-100 text-zinc-900 font-medium text-xs whitespace-nowrap">
          {type}
        </span>
      );
  }
}

function ComparisonBarChart({ history }) {
  const canvasRef = useRef(null);
  const chartInstanceRef = useRef(null);
  const [hoveredData, setHoveredData] = useState(null);
  const [chartReady, setChartReady] = useState(typeof window.Chart !== 'undefined');
  const [useFallback, setUseFallback] = useState(false);

  useEffect(() => {
    if (typeof window.Chart !== 'undefined') {
      setChartReady(true);
      return;
    }
    const timer = setInterval(() => {
      if (typeof window.Chart !== 'undefined') {
        setChartReady(true);
        clearInterval(timer);
      }
    }, 150);
    const timeout = setTimeout(() => {
      if (typeof window.Chart === 'undefined') {
        setUseFallback(true);
        clearInterval(timer);
      }
    }, 2000);
    return () => {
      clearInterval(timer);
      clearTimeout(timeout);
    };
  }, []);

  useEffect(() => {
    if (!chartReady || !canvasRef.current || !history || history.length === 0) return;

    if (chartInstanceRef.current) {
      chartInstanceRef.current.destroy();
      chartInstanceRef.current = null;
    }

    const labels = history.map(item => `${item.month.substring(5, 7)}/${item.month.substring(2, 4)}`);
    const creditsData = history.map(item => item.credits || 0);
    const debitsData = history.map(item => item.debits || 0);

    const ctx = canvasRef.current.getContext('2d');
    chartInstanceRef.current = new window.Chart(ctx, {
      type: 'bar',
      data: {
        labels,
        datasets: [
          {
            label: 'Servicios Prestados',
            data: creditsData,
            backgroundColor: '#10b981',
            hoverBackgroundColor: '#059669',
            borderRadius: 6,
            borderSkipped: false,
            maxBarThickness: 26,
            categoryPercentage: 0.82,
            barPercentage: 0.9
          },
          {
            label: 'Cuotas Descontadas',
            data: debitsData,
            backgroundColor: '#f43f5e',
            hoverBackgroundColor: '#e11d48',
            borderRadius: 6,
            borderSkipped: false,
            maxBarThickness: 26,
            categoryPercentage: 0.82,
            barPercentage: 0.9
          }
        ]
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        animation: { duration: 350 },
        interaction: {
          mode: 'index',
          intersect: false
        },
        onHover: (event, activeElements) => {
          if (activeElements && activeElements.length > 0) {
            const index = activeElements[0].index;
            setHoveredData(history[index]);
          } else {
            setHoveredData(null);
          }
        },
        plugins: {
          legend: { display: false },
          tooltip: {
            enabled: true,
            backgroundColor: 'rgba(9, 9, 11, 0.95)',
            titleColor: '#ffffff',
            titleFont: { size: 13, weight: 'bold', family: 'sans-serif' },
            bodyColor: '#f4f4f5',
            bodyFont: { size: 12, family: 'sans-serif' },
            footerColor: '#38bdf8',
            footerFont: { size: 12, weight: 'bold', family: 'sans-serif' },
            borderColor: 'rgba(255, 255, 255, 0.15)',
            borderWidth: 1,
            padding: 12,
            boxPadding: 6,
            usePointStyle: true,
            callbacks: {
              title: (items) => {
                if (!items.length) return '';
                const idx = items[0].dataIndex;
                const h = history[idx];
                const [y, m] = h.month.split('-');
                const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'];
                const nomeMes = meses[parseInt(m, 10) - 1] || m;
                return `📅 Competencia: ${nomeMes} / ${y}`;
              },
              label: (item) => {
                const val = item.parsed.y || 0;
                const label = item.dataset.label || '';
                return ` ${label}: ${formatCurrencyPYG(val)}`;
              },
              footer: (items) => {
                if (!items.length) return '';
                const idx = items[0].dataIndex;
                const h = history[idx];
                const net = (h.credits || 0) - (h.debits || 0);
                const prefix = net >= 0 ? '+ ' : '';
                return `Diferencia en el Mes: ${prefix}${formatCurrencyPYG(net)}`;
              }
            }
          }
        },
        scales: {
          x: {
            grid: { display: false },
            ticks: {
              color: '#71717a',
              font: { size: 11, weight: '600' }
            }
          },
          y: {
            grid: {
              color: '#f4f4f5',
              borderDash: [3, 3]
            },
            ticks: {
              color: '#71717a',
              font: { size: 10 },
              callback: (val) => {
                if (val >= 1000000) return 'G$ ' + (val / 1000000).toFixed(1) + 'M';
                return 'G$ ' + val.toLocaleString('pt-BR');
              }
            }
          }
        }
      }
    });

    return () => {
      if (chartInstanceRef.current) {
        chartInstanceRef.current.destroy();
        chartInstanceRef.current = null;
      }
    };
  }, [chartReady, history]);

  if (!history || history.length === 0) {
    return (
      <div className="flex items-center justify-center h-[240px] text-zinc-400 text-xs font-medium">
        Sin datos suficientes para el gráfico
      </div>
    );
  }

  if (useFallback && !chartReady) {
    const maxVal = Math.max(...history.map(h => Math.max(h.credits || 0, h.debits || 0)), 100);
    const height = 180;
    const paddingBottom = 25;
    const usableHeight = height - paddingBottom;
    const barGroupWidth = 100 / history.length;
    const barWidth = Math.min(barGroupWidth * 0.36, 12);

    return (
      <div className="relative w-full">
        <div className="h-6 mb-2 flex items-center justify-end text-xs font-medium">
          {hoveredData ? (
            <div className="inline-flex items-center gap-2 px-2.5 py-0.5 rounded-full bg-zinc-950 text-white text-[11px] font-mono shadow-xs">
              <span className="text-zinc-400 font-sans">{hoveredData.month}:</span>
              <span className="text-emerald-400 font-bold">+{formatCurrencyPYG(hoveredData.credits)}</span>
              <span className="text-zinc-600">|</span>
              <span className="text-rose-400 font-bold">-{formatCurrencyPYG(hoveredData.debits)}</span>
            </div>
          ) : (
            <span className="text-zinc-400 text-[11px] font-sans">💡 Pase el cursor sobre las columnas para ver los valores</span>
          )}
        </div>
        <div className="w-full h-[220px] relative">
          <svg width="100%" height="100%" style={{ overflow: 'visible' }}>
            <line x1="0" y1="0" x2="100%" y2="0" stroke="#f4f4f5" strokeDasharray="3,3" />
            <line x1="0" y1={usableHeight * 0.5} x2="100%" y2={usableHeight * 0.5} stroke="#f4f4f5" strokeDasharray="3,3" />
            <line x1="0" y1={usableHeight} x2="100%" y2={usableHeight} stroke="#e4e4e7" />

            {history.map((item, index) => {
              const xCenter = (index + 0.5) * barGroupWidth;
              const hCredit = ((item.credits || 0) / maxVal) * usableHeight;
              const hDebit = ((item.debits || 0) / maxVal) * usableHeight;
              const isHovered = hoveredData?.month === item.month;

              return (
                <g 
                  key={item.month} 
                  className="cursor-pointer"
                  onMouseEnter={() => setHoveredData(item)}
                  onMouseLeave={() => setHoveredData(null)}
                >
                  <rect
                    x={`calc(${xCenter - barGroupWidth * 0.48}%)`}
                    y="0"
                    width={`${barGroupWidth * 0.96}%`}
                    height={height}
                    fill={isHovered ? 'rgba(0,0,0,0.04)' : 'transparent'}
                    rx="4"
                  />
                  <rect
                    x={`calc(${xCenter}% - ${barWidth + 2}px)`}
                    y={usableHeight - hCredit}
                    width={barWidth}
                    height={hCredit}
                    fill={isHovered ? '#059669' : '#10b981'}
                    rx="2"
                  />
                  <rect
                    x={`calc(${xCenter}% + 2px)`}
                    y={usableHeight - hDebit}
                    width={barWidth}
                    height={hDebit}
                    fill={isHovered ? '#e11d48' : '#f43f5e'}
                    rx="2"
                  />
                  <text
                    x={`${xCenter}%`}
                    y={height - 6}
                    textAnchor="middle"
                    fontSize="11"
                    fontWeight={isHovered ? "700" : "500"}
                    fill={isHovered ? "#09090b" : "#71717a"}
                    fontFamily="sans-serif"
                  >
                    {item.month.substring(5, 7)}/{item.month.substring(2, 4)}
                  </text>
                </g>
              );
            })}
          </svg>
        </div>
      </div>
    );
  }

  return (
    <div className="relative w-full">
      {/* Indicador interativo dinâmico ao passar o mouse */}
      <div className="h-6 mb-2 flex items-center justify-end text-xs font-medium">
        {hoveredData ? (
          <div className="inline-flex items-center gap-2 px-2.5 py-0.5 rounded-full bg-zinc-950 text-white text-[11px] font-mono shadow-xs">
            <span className="text-zinc-400 font-sans">{hoveredData.month}:</span>
            <span className="text-emerald-400 font-bold">+{formatCurrencyPYG(hoveredData.credits)}</span>
            <span className="text-zinc-600">|</span>
            <span className="text-rose-400 font-bold">-{formatCurrencyPYG(hoveredData.debits)}</span>
          </div>
        ) : (
          <span className="text-zinc-400 text-[11px] font-sans">💡 Pase el cursor sobre las columnas para ver los valores detallados</span>
        )}
      </div>

      <div className="w-full h-[220px] relative">
        <canvas ref={canvasRef} />
      </div>
    </div>
  );
}

function RunningBalanceLineChart({ history }) {
  const canvasRef = useRef(null);
  const chartInstanceRef = useRef(null);
  const [hoveredData, setHoveredData] = useState(null);
  const [chartReady, setChartReady] = useState(typeof window.Chart !== 'undefined');
  const [useFallback, setUseFallback] = useState(false);

  useEffect(() => {
    if (typeof window.Chart !== 'undefined') {
      setChartReady(true);
      return;
    }
    const timer = setInterval(() => {
      if (typeof window.Chart !== 'undefined') {
        setChartReady(true);
        clearInterval(timer);
      }
    }, 150);
    const timeout = setTimeout(() => {
      if (typeof window.Chart === 'undefined') {
        setUseFallback(true);
        clearInterval(timer);
      }
    }, 2000);
    return () => {
      clearInterval(timer);
      clearTimeout(timeout);
    };
  }, []);

  useEffect(() => {
    if (!chartReady || !canvasRef.current || !history || history.length === 0) return;

    if (chartInstanceRef.current) {
      chartInstanceRef.current.destroy();
      chartInstanceRef.current = null;
    }

    const labels = history.map(item => `${item.month.substring(5, 7)}/${item.month.substring(2, 4)}`);
    const balanceData = history.map(item => item.runningBalance ?? item.balance ?? 0);

    const ctx = canvasRef.current.getContext('2d');
    const gradient = ctx.createLinearGradient(0, 0, 0, 220);
    gradient.addColorStop(0, 'rgba(16, 185, 129, 0.22)');
    gradient.addColorStop(1, 'rgba(16, 185, 129, 0.01)');

    chartInstanceRef.current = new window.Chart(ctx, {
      type: 'line',
      data: {
        labels,
        datasets: [
          {
            label: 'Saldo Acumulado a Favor do Prestador',
            data: balanceData,
            borderColor: '#09090b',
            borderWidth: 2.5,
            backgroundColor: gradient,
            fill: true,
            tension: 0.35,
            pointBackgroundColor: '#ffffff',
            pointBorderColor: '#09090b',
            pointBorderWidth: 2,
            pointRadius: 4,
            pointHoverRadius: 7,
            pointHoverBackgroundColor: '#10b981',
            pointHoverBorderColor: '#09090b',
            pointHoverBorderWidth: 3
          }
        ]
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        animation: { duration: 350 },
        interaction: {
          mode: 'index',
          intersect: false
        },
        onHover: (event, activeElements) => {
          if (activeElements && activeElements.length > 0) {
            const index = activeElements[0].index;
            setHoveredData(history[index]);
          } else {
            setHoveredData(null);
          }
        },
        plugins: {
          legend: { display: false },
          tooltip: {
            enabled: true,
            backgroundColor: 'rgba(9, 9, 11, 0.95)',
            titleColor: '#ffffff',
            titleFont: { size: 13, weight: 'bold', family: 'sans-serif' },
            bodyColor: '#f4f4f5',
            bodyFont: { size: 12, family: 'sans-serif' },
            footerColor: '#34d399',
            footerFont: { size: 12, weight: 'bold', family: 'sans-serif' },
            borderColor: 'rgba(255, 255, 255, 0.15)',
            borderWidth: 1,
            padding: 12,
            boxPadding: 6,
            usePointStyle: true,
            callbacks: {
              title: (items) => {
                if (!items.length) return '';
                const idx = items[0].dataIndex;
                const h = history[idx];
                const [y, m] = h.month.split('-');
                const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'];
                const nomeMes = meses[parseInt(m, 10) - 1] || m;
                return `📅 Competencia: ${nomeMes} / ${y}`;
              },
              label: (item) => {
                const val = item.parsed.y || 0;
                return ` Saldo Acumulado: ${formatCurrencyPYG(val)}`;
              },
              footer: (items) => {
                if (!items.length) return '';
                const idx = items[0].dataIndex;
                const h = history[idx];
                const bal = h.runningBalance ?? h.balance ?? 0;
                return bal > 0 ? 'Estado: La Universidad le debe' : (bal < 0 ? 'Estado: Usted debe a la Universidad' : 'Estado: Equilibrado');
              }
            }
          }
        },
        scales: {
          x: {
            grid: { display: false },
            ticks: {
              color: '#71717a',
              font: { size: 11, weight: '600' }
            }
          },
          y: {
            grid: {
              color: '#f4f4f5',
              borderDash: [3, 3]
            },
            ticks: {
              color: '#71717a',
              font: { size: 10 },
              callback: (val) => {
                if (val >= 1000000) return 'G$ ' + (val / 1000000).toFixed(1) + 'M';
                return 'G$ ' + val.toLocaleString('pt-BR');
              }
            }
          }
        }
      }
    });

    return () => {
      if (chartInstanceRef.current) {
        chartInstanceRef.current.destroy();
        chartInstanceRef.current = null;
      }
    };
  }, [chartReady, history]);

  if (!history || history.length === 0) {
    return (
      <div className="flex items-center justify-center h-[240px] text-zinc-400 text-xs font-medium">
        Sin datos suficientes para el gráfico
      </div>
    );
  }

  if (useFallback && !chartReady) {
    const balances = history.map(h => h.runningBalance ?? h.balance ?? 0);
    const minBal = Math.min(...balances, 0);
    const maxBal = Math.max(...balances, 0);
    const range = maxBal - minBal || 1;
    const height = 180;
    const paddingBottom = 25;
    const usableHeight = height - paddingBottom;

    const points = history.map((item, index) => {
      const x = ((index + 0.5) / history.length) * 100;
      const val = item.runningBalance ?? item.balance ?? 0;
      const y = usableHeight - ((val - minBal) / range) * usableHeight;
      return { x, y, val, month: item.month, item };
    });

    const pathD = points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x}% ${p.y}`).join(' ');

    return (
      <div className="relative w-full">
        <div className="h-6 mb-2 flex items-center justify-end text-xs font-medium">
          {hoveredData ? (
            <div className="inline-flex items-center gap-2 px-2.5 py-0.5 rounded-full bg-zinc-950 text-white text-[11px] font-mono shadow-xs">
              <span className="text-zinc-400 font-sans">{hoveredData.month}:</span>
              <span className="text-emerald-400 font-bold">{formatCurrencyPYG(hoveredData.runningBalance ?? hoveredData.balance ?? 0)}</span>
            </div>
          ) : (
            <span className="text-zinc-400 text-[11px] font-sans">💡 Pase el cursor sobre la línea para ver el saldo</span>
          )}
        </div>
        <div className="w-full h-[220px] relative">
          <svg width="100%" height="100%" style={{ overflow: 'visible' }}>
            <line x1="0" y1="0" x2="100%" y2="0" stroke="#f4f4f5" strokeDasharray="3,3" />
            <line x1="0" y1={usableHeight * 0.5} x2="100%" y2={usableHeight * 0.5} stroke="#f4f4f5" strokeDasharray="3,3" />
            <line x1="0" y1={usableHeight} x2="100%" y2={usableHeight} stroke="#e4e4e7" />

            <path d={pathD} fill="none" stroke="#09090b" strokeWidth="2.5" />

            {points.map((p, i) => {
              const isHovered = hoveredData?.month === p.month;
              return (
                <g 
                  key={i} 
                  className="cursor-pointer"
                  onMouseEnter={() => setHoveredData(p.item)}
                  onMouseLeave={() => setHoveredData(null)}
                >
                  <circle 
                    cx={`${p.x}%`} 
                    cy={p.y} 
                    r={isHovered ? "7" : "4.5"} 
                    fill={isHovered ? "#10b981" : "#ffffff"} 
                    stroke="#09090b" 
                    strokeWidth={isHovered ? "3" : "2"} 
                  />
                  <text
                    x={`${p.x}%`}
                    y={height - 6}
                    textAnchor="middle"
                    fontSize="11"
                    fontWeight={isHovered ? "700" : "500"}
                    fill={isHovered ? "#09090b" : "#71717a"}
                    fontFamily="sans-serif"
                  >
                    {p.month.substring(5, 7)}/{p.month.substring(2, 4)}
                  </text>
                </g>
              );
            })}
          </svg>
        </div>
      </div>
    );
  }

  const currentBal = hoveredData ? (hoveredData.runningBalance ?? hoveredData.balance ?? 0) : null;

  return (
    <div className="relative w-full">
      {/* Indicador interativo dinâmico ao passar o mouse */}
      <div className="h-6 mb-2 flex items-center justify-end text-xs font-medium">
        {hoveredData ? (
          <div className="inline-flex items-center gap-2 px-2.5 py-0.5 rounded-full bg-zinc-950 text-white text-[11px] font-mono shadow-xs">
            <span className="text-zinc-400 font-sans">{hoveredData.month}:</span>
            <span className="text-emerald-400 font-bold">{formatCurrencyPYG(currentBal)}</span>
          </div>
        ) : (
          <span className="text-zinc-400 text-[11px] font-sans">💡 Pase el cursor sobre la línea para ver el saldo exacto</span>
        )}
      </div>

      <div className="w-full h-[220px] relative">
        <canvas ref={canvasRef} />
      </div>
    </div>
  );
}

function TransactionTable({ transactions, onEdit, onDelete, showDelete = true }) {
  const { Button, Lucide } = window.Shadcn || {};
  const { setDetailTx, isAdmin } = window.useFinance ? window.useFinance() : { isAdmin: true };

  if (!transactions || transactions.length === 0) {
    return (
      <div className="p-10 text-center text-zinc-500 text-sm border border-zinc-200 rounded-xl bg-white shadow-xs">
        <span className="text-2xl block mb-2">📋</span>
        <div className="font-semibold text-zinc-800">Ningún movimiento encontrado</div>
        <div className="text-xs text-zinc-400 mt-1">Ajuste los filtros de búsqueda o fecha para visualizar otros períodos.</div>
      </div>
    );
  }

  return (
    <div className="rounded-xl border border-zinc-200 bg-white shadow-xs overflow-hidden">
      <div className="overflow-x-auto">
        <table className="w-full text-left border-collapse">
          <thead>
            <tr className="border-b border-zinc-200 bg-zinc-50/90 text-zinc-700 font-sans">
              <th className="py-3 px-3.5 text-xs font-bold uppercase tracking-wider w-16">ID</th>
              <th className="py-3 px-3.5 text-xs font-bold uppercase tracking-wider w-24">Fecha</th>
              <th className="py-3 px-3.5 text-xs font-bold uppercase tracking-wider w-36">Tipo</th>
              <th className="py-3 px-3.5 text-xs font-bold uppercase tracking-wider min-w-[260px]">Servicio Ejecutado</th>
              <th className="py-3 px-3.5 text-xs font-bold uppercase tracking-wider min-w-[220px]">Detalle / Entregable</th>
              <th className="py-3 px-3.5 text-xs font-bold uppercase tracking-wider w-28 text-center">Doc / Ref</th>
              <th className="py-3 px-3.5 text-xs font-bold uppercase tracking-wider text-right w-36">Monto</th>
              <th className="py-3 px-3.5 text-xs font-bold uppercase tracking-wider text-right w-24">{isAdmin ? 'Acciones' : 'Ficha'}</th>
            </tr>
          </thead>
          <tbody className="divide-y divide-zinc-100 font-sans">
            {transactions.map(tx => {
              const isCredit = tx.type === 'CREDIT' || tx.type === 'PAYMENT_MADE';
              const isDebit = tx.type === 'DEBIT';
              const amountPrefix = isCredit ? '+ ' : '- ';

              return (
                <tr key={tx.id} className="hover:bg-zinc-50/70 transition-colors">
                  {/* ID */}
                  <td className="py-3 px-3.5 whitespace-nowrap">
                    <button 
                      type="button" 
                      onClick={() => setDetailTx && setDetailTx(tx)}
                      className="inline-flex items-center gap-1 px-2 py-0.5 rounded bg-zinc-100 hover:bg-zinc-200 text-zinc-900 border border-zinc-200 font-mono text-xs font-bold cursor-pointer transition-colors shadow-2xs"
                      title="Ver ficha completa del movimiento"
                    >
                      <span>#{String(tx.id).padStart(3, '0')}</span>
                      {Lucide?.FileText ? <Lucide.FileText size={11} className="text-zinc-500" /> : '📄'}
                    </button>
                  </td>

                  {/* DATA */}
                  <td className="py-3 px-3.5 font-mono text-xs font-semibold text-zinc-800 whitespace-nowrap">
                    {formatDateBR(tx.date)}
                  </td>

                  {/* TIPO BADGE */}
                  <td className="py-3 px-3.5 whitespace-nowrap">
                    <TransactionBadge type={tx.type} title={tx.title} />
                  </td>

                  {/* SERVIÇO EXECUTADO */}
                  <td className="py-3 px-3.5">
                    <div className="font-bold text-sm text-zinc-950 leading-snug">{tx.title}</div>
                    {tx.service_name && tx.service_name !== tx.title && (
                      <div className="text-xs text-zinc-500 font-medium mt-0.5">
                        Catálogo: {tx.service_name}
                      </div>
                    )}
                    {tx.tags && tx.tags.length > 0 && (
                      <div className="flex items-center gap-1.5 flex-wrap mt-1.5">
                        {tx.tags.map(t => (
                          <span 
                            key={t.id || t.name}
                            className="inline-flex items-center text-[10px] font-bold font-mono px-2 py-0.5 rounded text-white shadow-2xs"
                            style={{ backgroundColor: t.color || '#18181b' }}
                          >
                            #{t.name}
                          </span>
                        ))}
                      </div>
                    )}

                    {/* MOSTRA ENTREGÁVEIS SOMENTE SE HOUVER MAIS DE 1 ITEM */}
                    {tx.items && tx.items.length > 1 && (
                      <div className="mt-2 p-2 rounded-md bg-zinc-50 border border-zinc-200/80 space-y-1">
                        <div className="text-[10px] font-bold text-zinc-600 uppercase tracking-wider flex items-center justify-between border-b border-zinc-200/80 pb-1">
                          <span>🎬 {tx.items.length} Ítems Incluidos</span>
                          <span className="font-mono text-zinc-900">{formatCurrencyPYG(tx.amount)}</span>
                        </div>
                        {tx.items.map((it, idx) => (
                          <div key={idx} className="flex items-center justify-between text-xs py-0.5">
                            <span className="font-medium text-zinc-800 truncate">• {it.title}</span>
                            <span className="font-mono text-[11px] font-bold text-emerald-700 ml-2">
                              {formatCurrencyPYG(it.total_price || (it.quantity * it.unit_price))}
                            </span>
                          </div>
                        ))}
                      </div>
                    )}
                  </td>

                  {/* O QUE FOI FEITO / ENTREGUE */}
                  <td className="py-3 px-3.5">
                    {tx.description ? (
                      <div className="text-xs text-zinc-700 leading-relaxed font-normal" title={tx.description}>
                        {tx.description}
                      </div>
                    ) : (
                      <span className="text-zinc-300 text-xs font-mono">-</span>
                    )}
                    {tx.deliverable_url && (
                      <div className="mt-1 flex items-center gap-1.5 flex-wrap">
                        {(() => {
                          const info = window.getEmbedDeliverable ? window.getEmbedDeliverable(tx.deliverable_url) : null;
                          return (
                            <>
                              <a 
                                href={tx.deliverable_url} 
                                target="_blank" 
                                rel="noreferrer"
                                className="inline-flex items-center gap-1 text-[11px] font-semibold text-blue-700 bg-blue-50/80 hover:bg-blue-100 hover:underline border border-blue-200/80 px-2 py-0.5 rounded shadow-2xs transition-colors"
                                onClick={(e) => e.stopPropagation()}
                                title={tx.deliverable_url}
                              >
                                <span>{info?.icon || '🔗'}</span>
                                <span>{info?.label || 'Entregable'}</span>
                                <span className="text-[10px]">↗</span>
                              </a>
                              <button
                                type="button"
                                className="text-[11px] text-zinc-400 hover:text-zinc-800 p-0.5 rounded hover:bg-zinc-100 transition-colors cursor-pointer"
                                title="Copiar enlace al portapapeles"
                                onClick={(e) => {
                                  e.stopPropagation();
                                  if (navigator.clipboard?.writeText) {
                                    navigator.clipboard.writeText(tx.deliverable_url);
                                  } else {
                                    const ta = document.createElement('textarea');
                                    ta.value = tx.deliverable_url;
                                    document.body.appendChild(ta);
                                    ta.select();
                                    document.execCommand('copy');
                                    document.body.removeChild(ta);
                                  }
                                  if (window.useFinance) {
                                    // Feedback visual
                                  }
                                }}
                              >
                                📋
                              </button>
                            </>
                          );
                        })()}
                      </div>
                    )}
                  </td>

                  {/* DOC / REF */}
                  <td className="py-3 px-3.5 text-center whitespace-nowrap">
                    {tx.document_ref ? (
                      <span className="font-mono text-xs font-semibold text-zinc-700 bg-zinc-100 px-2 py-0.5 rounded border border-zinc-200/80 inline-block shadow-2xs">
                        {tx.document_ref}
                      </span>
                    ) : (
                      <span className="text-zinc-300 font-mono text-xs">-</span>
                    )}
                  </td>

                  {/* VALOR */}
                  <td className="py-3 px-3.5 text-right whitespace-nowrap">
                    <span className={`font-mono font-bold text-sm ${
                      isCredit 
                        ? 'text-emerald-700' 
                        : (isDebit ? 'text-rose-700' : 'text-sky-700')
                    }`}>
                      {amountPrefix}{formatCurrencyPYG(tx.amount)}
                    </span>
                  </td>

                  {/* AÇÕES */}
                  <td className="py-3 px-3.5 text-right whitespace-nowrap">
                    <div className="flex items-center justify-end gap-1">
                      <button 
                        type="button" 
                        onClick={() => setDetailTx && setDetailTx(tx)} 
                        title="Ver Ficha Completa / Orden de Servicio / Entregables"
                        className="p-1 rounded text-zinc-500 hover:text-zinc-950 hover:bg-zinc-100 transition-colors"
                      >
                        {Lucide?.FileText ? <Lucide.FileText size={15} /> : '📄'}
                      </button>
                      {isAdmin && onEdit && (
                        <button 
                          type="button" 
                          onClick={() => onEdit(tx)} 
                          title="Editar Movimiento"
                          className="p-1 rounded text-zinc-500 hover:text-zinc-950 hover:bg-zinc-100 transition-colors"
                        >
                          {Lucide?.Edit ? <Lucide.Edit size={15} /> : '✏️'}
                        </button>
                      )}
                      {isAdmin && showDelete && onDelete && (
                        <button 
                          type="button" 
                          onClick={() => onDelete(tx.id, tx)} 
                          title="Eliminar Movimiento"
                          className="p-1 rounded text-zinc-400 hover:text-rose-600 hover:bg-rose-50 transition-colors"
                        >
                          {Lucide?.Trash ? <Lucide.Trash size={15} /> : '🗑️'}
                        </button>
                      )}
                    </div>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    </div>
  );
}

function CategoryDonutChart({ transactions }) {
  const canvasRef = useRef(null);
  const chartInstanceRef = useRef(null);
  const [chartReady, setChartReady] = useState(typeof window.Chart !== 'undefined');

  useEffect(() => {
    if (typeof window.Chart !== 'undefined') setChartReady(true);
  }, []);

  const categories = useMemo(() => {
    if (!transactions || transactions.length === 0) return [];
    const map = {};
    transactions.forEach(t => {
      let cat = 'Otros Servicios';
      const title = (t.title || '').toLowerCase();
      const srvName = (t.service_name || '').toLowerCase();
      
      if (t.type === 'DEBIT') {
        cat = 'Cuotas Universitarias';
      } else if (title.includes('safari') || title.includes('folclorica') || title.includes('evento')) {
        cat = 'Eventos & Coberturas (Safari/Festivales)';
      } else if (title.includes('reels') || title.includes('video') || title.includes('audiovisual')) {
        cat = 'Reels & Producción Audiovisual';
      } else if (title.includes('anuncio') || title.includes('criativo') || title.includes('pietra') || title.includes('diseño')) {
        cat = 'Creativos & Anuncios Publicitarios';
      } else if (title.includes('medicina') || title.includes('derecho') || srvName.includes('academica')) {
        cat = 'Coberturas Académicas & Carreras';
      } else if (t.type === 'PAYMENT_RECEIVED') {
        cat = 'Pagos Recibidos en Mano';
      }

      if (!map[cat]) map[cat] = 0;
      map[cat] += t.amount;
    });

    const colors = {
      'Eventos & Coberturas (Safari/Festivales)': '#10b981',
      'Reels & Producción Audiovisual': '#06b6d4',
      'Creativos & Anuncios Publicitarios': '#8b5cf6',
      'Coberturas Académicas & Carreras': '#f59e0b',
      'Cuotas Universitarias': '#f43f5e',
      'Pagos Recibidos en Mano': '#3b82f6',
      'Otros Servicios': '#71717a'
    };

    return Object.entries(map).map(([name, total]) => ({
      name,
      total,
      color: colors[name] || '#71717a'
    })).sort((a, b) => b.total - a.total);
  }, [transactions]);

  useEffect(() => {
    if (!chartReady || !canvasRef.current || categories.length === 0) return;

    if (chartInstanceRef.current) {
      chartInstanceRef.current.destroy();
      chartInstanceRef.current = null;
    }

    const ctx = canvasRef.current.getContext('2d');
    chartInstanceRef.current = new window.Chart(ctx, {
      type: 'doughnut',
      data: {
        labels: categories.map(c => c.name),
        datasets: [{
          data: categories.map(c => c.total),
          backgroundColor: categories.map(c => c.color),
          borderWidth: 2,
          borderColor: '#ffffff',
          hoverOffset: 6
        }]
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: {
          legend: {
            position: 'right',
            labels: {
              boxWidth: 12,
              font: { size: 10, family: 'sans-serif' },
              color: '#52525b'
            }
          },
          tooltip: {
            backgroundColor: '#09090b',
            titleColor: '#ffffff',
            bodyColor: '#a1a1aa',
            callbacks: {
              label: (ctx) => ` ${ctx.label}: ${formatCurrencyPYG(ctx.raw)}`
            }
          }
        },
        cutout: '66%'
      }
    });

    return () => {
      if (chartInstanceRef.current) {
        chartInstanceRef.current.destroy();
        chartInstanceRef.current = null;
      }
    };
  }, [chartReady, categories]);

  if (categories.length === 0) {
    return (
      <div className="flex items-center justify-center h-[220px] text-zinc-400 text-xs">
        Sin datos para la distribución
      </div>
    );
  }

  return (
    <div className="w-full h-[220px] relative">
      <canvas ref={canvasRef} />
    </div>
  );
}

window.ComparisonBarChart = ComparisonBarChart;
window.RunningBalanceLineChart = RunningBalanceLineChart;
window.CategoryDonutChart = CategoryDonutChart;
window.TransactionTable = TransactionTable;
window.TransactionBadge = TransactionBadge;
window.formatCurrencyPYG = formatCurrencyPYG;
window.formatCurrencyBRL = formatCurrencyPYG;
window.formatDateBR = formatDateBR;

