import { Icon } from "@iconify/react";
import {
  Alert,
  AlertTitle,
  Box,
  Button,
  CircularProgress,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  IconButton,
  Tooltip,
  Typography,
} from "@mui/material";
import { useEffect, useMemo, useState } from "react";
import { useNavigate } from "react-router-dom";
import { toast } from "sonner";
import {
  agregarLineaLiquidacion,
  anularLiquidacion,
  calcularLiquidacion,
  cerrarLiquidacion,
  crearLiquidacion,
  eliminarLineaLiquidacion,
  getAsientoLiquidacion,
  getConceptos,
  getLiquidacion,
  getLiquidacionEmpleado,
  getLiquidaciones,
  getPlanillaLiquidacion,
  integrarLiquidacionContabilidad,
  descargarPlanillaLiquidacionXlsx,
  getPlanillaControlLiquidacion,
  descargarPlanillaControlXlsx,
  getTiposEmpleado,
} from "../../api/rrhh.service";
import { getSucursales } from "../../api/sucursales.service";
import { useConfirmDialog } from "../../hooks/useConfirmDialog";
import { useAuthStore } from "../../store/AuthStore";
import {
  generarReciboLiquidacionPDF,
  previsualizarReciboLiquidacionPDF,
} from "../../reportesPDF/generarReciboLiquidacion";
import { generarPlanillaLiquidacionPDF as generarPlanillaConsolidadaPDF } from "../../reportesPDF/generarPlanillaLiquidacionPdf";
import { generarPlanillaControlPDF } from "../../reportesPDF/generarPlanillaControlLiquidacion";
import {
  Badge,
  Container,
  Divider,
  EmptyState,
  Field,
  FieldsGrid,
  Footer,
  FooterActionButton,
  FormHead,
  FormPanel,
  GhostButton,
  ListBody,
  ListPanel,
  RowActions,
  SectionTitle,
  TableWrap,
  ToolBar,
} from "../ui/FormShell";
import { TablePaginationBar } from "../_standards";
import { SearchableSelect } from "../ui/SearchableSelect";
import { RRHHGuia } from "./_shared/RRHHGuia";
import { RRHHPrereqChecklist } from "./_shared/RRHHPrereqChecklist";
import { RRHHEmptyState } from "./_shared/RRHHEmptyState";
import { MonedaInput } from "../common/MonedaInput";

const ESTADO_OPTIONS = [
  { id: "BORRADOR", label: "Borrador" },
  { id: "PRE_LIQUIDACION", label: "Pre-liquidación" },
  { id: "CERRADA", label: "Cerrada" },
  { id: "ANULADA", label: "Anulada" },
];
const MES_OPTIONS = [
  { id: 1, label: "01 — Enero" }, { id: 2, label: "02 — Febrero" },
  { id: 3, label: "03 — Marzo" }, { id: 4, label: "04 — Abril" },
  { id: 5, label: "05 — Mayo" }, { id: 6, label: "06 — Junio" },
  { id: 7, label: "07 — Julio" }, { id: 8, label: "08 — Agosto" },
  { id: 9, label: "09 — Septiembre" }, { id: 10, label: "10 — Octubre" },
  { id: 11, label: "11 — Noviembre" }, { id: 12, label: "12 — Diciembre" },
];
const TIPO_LINEA_OPTIONS = [
  { id: "INGRESO", label: "Ingreso (a favor del empleado)" },
  { id: "EGRESO", label: "Egreso (descuento)" },
];

// Tipo de liquidación a crear (combina tipo + quincena)
const TIPO_LIQ_OPTIONS = [
  { id: "MENSUAL", label: "Mensual" },
  { id: "QUINCENAL_1", label: "Quincenal — 1ª (días 1-15)" },
  { id: "QUINCENAL_2", label: "Quincenal — 2ª (días 16-fin)" },
  { id: "AGUINALDO", label: "Aguinaldo anual (Art. 243)" },
  { id: "VACACIONES", label: "Vacaciones gozadas (Art. 219)" },
];

const fmtMonto = (v) => Number(v || 0).toLocaleString("es-PY");
const fmtPeriodo = (a, m) => `${String(m).padStart(2, "0")}/${a}`;
const fmtTipoLiq = (liq) => {
  if (liq.tipo === "QUINCENAL") return `Quincenal ${liq.quincena === 2 ? "2ª" : "1ª"}`;
  if (liq.tipo === "AGUINALDO") return "Aguinaldo";
  if (liq.tipo === "VACACIONES") return "Vacaciones";
  return liq.tipo === "MENSUAL" ? "Mensual" : liq.tipo;
};
const fmtFecha = (v) => {
  if (!v) return "-";
  const d = new Date(v);
  return Number.isNaN(d.getTime()) ? "-" : d.toLocaleDateString("es-PY");
};

export function LiquidacionesTab() {
  const navigate = useNavigate();
  const { confirm, prompt, dialogs } = useConfirmDialog();
  const empresa = useAuthStore((s) => s.empresa);

  const [data, setData] = useState([]);
  // Advertencias del último cálculo (topes legales excedidos, etc.). Se
  // muestran en un banner y no en un toast: el usuario tiene que poder leerlas
  // mientras ajusta, no verlas pasar.
  const [advertencias, setAdvertencias] = useState([]);
  const [total, setTotal] = useState(0);
  const [page, setPage] = useState(1);
  const [limit, setLimit] = useState(20);
  const [estadoFiltro, setEstadoFiltro] = useState("");
  const [loading, setLoading] = useState(false);

  const [sucursales, setSucursales] = useState([]);
  const [tiposEmpleado, setTiposEmpleado] = useState([]);
  const [conceptos, setConceptos] = useState([]);

  // Vista "detalle de liquidación" (in-place, no dialog)
  const [verLiq, setVerLiq] = useState(null); // objeto liquidación con resumenes
  const [asiento, setAsiento] = useState(null);
  const [integrandoCont, setIntegrandoCont] = useState(false);
  const [planillaLoading, setPlanillaLoading] = useState("");
  const [verLoading, setVerLoading] = useState(false);
  const [calcLoading, setCalcLoading] = useState(false);

  // Crear nueva liquidación
  const [showCrear, setShowCrear] = useState(false);
  const [crearForm, setCrearForm] = useState(() => {
    const t = new Date();
    return { tipo: "MENSUAL", periodo_anio: t.getFullYear(), periodo_mes: t.getMonth() + 1, sucursal_id: "", tipo_empleado_id: "", fecha_pago_programada: "", observaciones: "" };
  });
  const [creando, setCreando] = useState(false);

  // Dialog de detalle por empleado
  const [empDialog, setEmpDialog] = useState({ open: false, loading: false, data: null, empleado: null });
  // Form de línea manual (dentro del dialog de empleado)
  const [lineaForm, setLineaForm] = useState({ concepto_id: "", tipo: "INGRESO", monto: 0, observacion: "" });
  const [agregandoLinea, setAgregandoLinea] = useState(false);
  // Dialog de preview del recibo PDF
  const [reciboDialog, setReciboDialog] = useState({
    open: false,
    loading: false,
    dataUrl: null,
    fileName: null,
    empleado: null,
  });

  const totalPages = useMemo(() => Math.max(1, Math.ceil(total / limit)), [total, limit]);

  const loadCatalogos = async () => {
    try {
      const [sucResp, concResp, tiposResp] = await Promise.all([getSucursales(1, 100), getConceptos(), getTiposEmpleado()]);
      setSucursales(sucResp?.data || sucResp || []);
      setConceptos(concResp || []);
      setTiposEmpleado((tiposResp?.data || tiposResp || []).filter((t) => t.activo));
    } catch {
      toast.error("No se pudieron cargar catálogos");
    }
  };

  const load = async () => {
    try {
      setLoading(true);
      const params = { page, limit };
      if (estadoFiltro) params.estado = estadoFiltro;
      const resp = await getLiquidaciones(params);
      setData(resp?.data || []);
      setTotal(resp?.total || 0);
    } catch {
      toast.error("Error al cargar liquidaciones");
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => { loadCatalogos(); }, []);
  useEffect(() => { load(); /* eslint-disable-next-line */ }, [page, limit, estadoFiltro]);

  // ── Abrir detalle de una liquidación ──
  const cargarAsiento = async (liqId, estado) => {
    if (estado !== "CERRADA") { setAsiento(null); return; }
    try {
      const resp = await getAsientoLiquidacion(liqId);
      setAsiento(resp?.asiento ?? null);
    } catch {
      setAsiento(null);
    }
  };

  const abrirLiquidacion = async (liq) => {
    setVerLoading(true);
    setAsiento(null);
    try {
      const full = await getLiquidacion(liq.id);
      setVerLiq(full);
      cargarAsiento(full.id, full.estado);
    } catch {
      toast.error("No se pudo cargar la liquidación");
    } finally {
      setVerLoading(false);
    }
  };
  const recargarVerLiq = async () => {
    if (!verLiq) return;
    const full = await getLiquidacion(verLiq.id);
    setVerLiq(full);
    cargarAsiento(full.id, full.estado);
  };
  const cerrarVista = () => { setVerLiq(null); setAsiento(null); load(); };

  const handleIntegrarContabilidad = async () => {
    if (!verLiq) return;
    try {
      setIntegrandoCont(true);
      const resp = await integrarLiquidacionContabilidad(verLiq.id);
      if (resp?.asiento) {
        setAsiento(resp.asiento);
        toast.success(`Asiento contable #${resp.asiento.numero} generado`);
      } else {
        await cargarAsiento(verLiq.id, verLiq.estado);
      }
    } catch (error) {
      toast.error(error?.response?.data?.message || "Error al integrar con Contabilidad");
    } finally {
      setIntegrandoCont(false);
    }
  };

  const mapErrorPlanilla = (error, accion) => {
    const status = error?.response?.status;
    if (status === 403) return `Sin permiso RH_LIQ_LIQUIDACION_VER para ${accion}.`;
    if (status === 404) return "La liquidación no existe o no pertenece a tu empresa.";
    if (status === 409) return "La planilla consolidada solo está disponible para liquidaciones mensuales cerradas.";
    return error?.response?.data?.message || `No se pudo ${accion}.`;
  };

  const handleDescargarPlanillaXlsx = async (liq) => {
    try {
      setPlanillaLoading("xlsx");
      const blob = await descargarPlanillaLiquidacionXlsx(liq.id);
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = `planilla_rrhh_${liq.periodo_anio}-${String(liq.periodo_mes).padStart(2, "0")}.xlsx`;
      document.body.appendChild(a);
      a.click();
      a.remove();
      URL.revokeObjectURL(url);
    } catch (error) {
      toast.error(mapErrorPlanilla(error, "descargar la planilla XLSX"));
    } finally {
      setPlanillaLoading("");
    }
  };

  const handleDescargarPlanillaPdf = async (liq) => {
    try {
      setPlanillaLoading("pdf");
      const planilla = await getPlanillaLiquidacion(liq.id, { format: "json" });
      generarPlanillaConsolidadaPDF(planilla);
    } catch (error) {
      toast.error(mapErrorPlanilla(error, "generar la planilla PDF"));
    } finally {
      setPlanillaLoading("");
    }
  };

  const handleDescargarPlanillaControlPdf = async (liq) => {
    try {
      setPlanillaLoading("control_pdf");
      const data = await getPlanillaControlLiquidacion(liq.id);
      generarPlanillaControlPDF(data);
    } catch (error) {
      toast.error(mapErrorPlanilla(error, "generar la planilla de control PDF"));
    } finally {
      setPlanillaLoading("");
    }
  };

  const handleDescargarPlanillaControlXlsx = async (liq) => {
    try {
      setPlanillaLoading("control_xlsx");
      const blob = await descargarPlanillaControlXlsx(liq.id);
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = `planilla_control_${liq.periodo_anio}-${String(liq.periodo_mes).padStart(2, "0")}_${(liq.estado || "").toLowerCase()}.xlsx`;
      document.body.appendChild(a);
      a.click();
      a.remove();
      URL.revokeObjectURL(url);
    } catch (error) {
      toast.error(mapErrorPlanilla(error, "descargar la planilla de control XLSX"));
    } finally {
      setPlanillaLoading("");
    }
  };

  // ── Crear ──
  const handleCrear = async () => {
    if (!crearForm.fecha_pago_programada) {
      toast.error("La fecha de pago programada es obligatoria");
      return;
    }
    try {
      setCreando(true);
      const t = crearForm.tipo;
      const esQuincenal = t === "QUINCENAL_1" || t === "QUINCENAL_2";
      const esAguinaldo = t === "AGUINALDO";
      const esVacaciones = t === "VACACIONES";
      // El backend sólo conoce MENSUAL/QUINCENAL/AGUINALDO/VACACIONES; el tipo
      // QUINCENAL se discrimina con `quincena`. Para AGUINALDO ignoramos el mes
      // (el backend lo fija en 12).
      const tipoBackend = esQuincenal
        ? "QUINCENAL"
        : esAguinaldo
          ? "AGUINALDO"
          : esVacaciones
            ? "VACACIONES"
            : "MENSUAL";
      const payload = {
        tipo: tipoBackend,
        quincena: esQuincenal ? (t === "QUINCENAL_2" ? 2 : 1) : undefined,
        periodo_anio: Number(crearForm.periodo_anio),
        periodo_mes: esAguinaldo ? undefined : Number(crearForm.periodo_mes),
        sucursal_id: crearForm.sucursal_id || undefined,
        tipo_empleado_id: crearForm.tipo_empleado_id || undefined,
        fecha_pago_programada: crearForm.fecha_pago_programada,
        observaciones: crearForm.observaciones || undefined,
      };
      const liq = await crearLiquidacion(payload);
      toast.success("Liquidación creada en BORRADOR");
      setShowCrear(false);
      await load();
      abrirLiquidacion(liq);
    } catch (error) {
      toast.error(error?.response?.data?.message || "Error al crear liquidación");
    } finally {
      setCreando(false);
    }
  };

  // ── Calcular ──
  const handleCalcular = async (liq) => {
    const ok = await confirm({
      title: "Calcular liquidación",
      message: `¿Ejecutar el motor de cálculo para ${fmtPeriodo(liq.periodo_anio, liq.periodo_mes)}? Esto reemplaza cualquier cálculo previo.`,
      confirmText: "Calcular",
      confirmColor: "primary",
    });
    if (!ok) return;
    try {
      setCalcLoading(true);
      const resp = await calcularLiquidacion(liq.id);
      const adv = resp?.advertencias || [];
      setAdvertencias(adv);
      if (adv.length) {
        toast.warning(`Calculada con ${adv.length} advertencia(s) — revisalas antes de cerrar`);
      } else {
        toast.success("Liquidación calculada");
      }
      if (verLiq?.id === liq.id) await recargarVerLiq();
      else { await load(); abrirLiquidacion(liq); }
    } catch (error) {
      toast.error(error?.response?.data?.message || "Error al calcular");
    } finally {
      setCalcLoading(false);
    }
  };

  // ── Cerrar ──
  const handleCerrar = async (liq) => {
    const comentario = await prompt({
      title: "Cerrar liquidación",
      message: `Una vez cerrada NO se puede modificar. Se descontarán anticipos y cuotas de préstamo del período, y se aplicarán las planillas externas.`,
      label: "Comentario de cierre",
      placeholder: "Opcional",
      confirmText: "Cerrar definitivamente",
      confirmColor: "error",
    });
    if (comentario === null) return;
    try {
      await cerrarLiquidacion(liq.id, comentario ? { comentario } : {});
      toast.success("Liquidación cerrada");
      if (verLiq?.id === liq.id) await recargarVerLiq();
      else load();
    } catch (error) {
      toast.error(error?.response?.data?.message || "No se pudo cerrar");
    }
  };

  // ── Anular ──
  const handleAnular = async (liq) => {
    const comentario = await prompt({
      title: "Anular liquidación",
      message: `Período ${fmtPeriodo(liq.periodo_anio, liq.periodo_mes)}. Se borrarán los cálculos.`,
      label: "Motivo de anulación",
      placeholder: "Opcional",
      confirmText: "Anular",
      confirmColor: "warning",
    });
    if (comentario === null) return;
    try {
      await anularLiquidacion(liq.id, comentario ? { comentario } : {});
      toast.success("Liquidación anulada");
      if (verLiq?.id === liq.id) cerrarVista();
      else load();
    } catch (error) {
      toast.error(error?.response?.data?.message || "No se pudo anular");
    }
  };

  // ── Detalle por empleado ──
  const abrirEmpleado = async (empleadoId, empleado) => {
    setEmpDialog({ open: true, loading: true, data: null, empleado });
    setLineaForm({ concepto_id: "", tipo: "INGRESO", monto: 0, observacion: "" });
    try {
      const det = await getLiquidacionEmpleado(verLiq.id, empleadoId);
      setEmpDialog({ open: true, loading: false, data: det, empleado });
    } catch {
      toast.error("No se pudo cargar el detalle del empleado");
      setEmpDialog({ open: false, loading: false, data: null, empleado: null });
    }
  };
  const recargarEmpleado = async () => {
    if (!empDialog.empleado) return;
    const det = await getLiquidacionEmpleado(verLiq.id, empDialog.empleado.id);
    setEmpDialog((p) => ({ ...p, data: det }));
  };

  const handleAgregarLinea = async () => {
    if (!lineaForm.concepto_id) return toast.error("Elegí un concepto");
    if (!Number(lineaForm.monto) || Number(lineaForm.monto) <= 0) return toast.error("Monto debe ser > 0");
    try {
      setAgregandoLinea(true);
      await agregarLineaLiquidacion(verLiq.id, {
        empleado_id: empDialog.empleado.id,
        concepto_id: lineaForm.concepto_id,
        tipo: lineaForm.tipo,
        monto: Number(lineaForm.monto),
        observacion: lineaForm.observacion || undefined,
      });
      toast.success("Ajuste agregado");
      setLineaForm({ concepto_id: "", tipo: "INGRESO", monto: 0, observacion: "" });
      await recargarEmpleado();
      await recargarVerLiq();
    } catch (error) {
      toast.error(error?.response?.data?.message || "No se pudo agregar el ajuste");
    } finally {
      setAgregandoLinea(false);
    }
  };

  const handleVerRecibo = async () => {
    if (!empDialog.data || !verLiq) return;
    const empleado = empDialog.empleado;
    setReciboDialog({ open: true, loading: true, dataUrl: null, fileName: null, empleado });
    try {
      const { dataUrl, fileName } = await previsualizarReciboLiquidacionPDF({
        liquidacion: empDialog.data.liquidacion || verLiq,
        resumen: empDialog.data.resumen,
        lineas: empDialog.data.lineas,
        empresa,
      });
      setReciboDialog({ open: true, loading: false, dataUrl, fileName, empleado });
    } catch (error) {
      console.error(error);
      toast.error("No se pudo generar el recibo");
      setReciboDialog({ open: false, loading: false, dataUrl: null, fileName: null, empleado: null });
    }
  };

  const handleDescargarReciboDesdePreview = () => {
    if (!empDialog.data || !verLiq) return;
    try {
      generarReciboLiquidacionPDF({
        liquidacion: empDialog.data.liquidacion || verLiq,
        resumen: empDialog.data.resumen,
        lineas: empDialog.data.lineas,
        empresa,
      });
    } catch (error) {
      console.error(error);
      toast.error("No se pudo descargar el recibo");
    }
  };

  const cerrarRecibo = () =>
    setReciboDialog({ open: false, loading: false, dataUrl: null, fileName: null, empleado: null });

  // Una línea de consumo se puede quitar solo de esta liquidación (recalcular
  // la vuelve a proponer) o marcando la factura para no proponerla más: las
  // compras grandes como cliente común no se cobran por planilla.
  const [quitarConsumo, setQuitarConsumo] = useState({ linea: null, loading: false });

  const confirmarQuitarConsumo = async (excluirFactura) => {
    const linea = quitarConsumo.linea;
    setQuitarConsumo((q) => ({ ...q, loading: true }));
    try {
      await eliminarLineaLiquidacion(verLiq.id, linea.id, { excluirFactura });
      toast.success(
        excluirFactura
          ? "Factura quitada. No se va a volver a proponer (se puede revertir en Configuración → Consumo de funcionarios)."
          : "Factura quitada de esta liquidación",
      );
      setQuitarConsumo({ linea: null, loading: false });
      await recargarEmpleado();
      await recargarVerLiq();
    } catch (error) {
      toast.error(error?.response?.data?.message || "No se pudo quitar");
      setQuitarConsumo((q) => ({ ...q, loading: false }));
    }
  };

  const handleEliminarLinea = async (linea) => {
    if (linea.origen === "CONSUMO_FUNCIONARIO") {
      setQuitarConsumo({ linea, loading: false });
      return;
    }
    const ok = await confirm({
      title: "Quitar ajuste",
      message: "¿Quitar este ajuste manual?",
      confirmText: "Quitar",
      confirmColor: "error",
    });
    if (!ok) return;
    try {
      await eliminarLineaLiquidacion(verLiq.id, linea.id);
      toast.success("Ajuste quitado");
      await recargarEmpleado();
      await recargarVerLiq();
    } catch (error) {
      toast.error(error?.response?.data?.message || "No se pudo quitar");
    }
  };

  const updateCrear = (k, v) => setCrearForm((p) => ({ ...p, [k]: v }));
  const updateLinea = (k, v) => setLineaForm((p) => ({ ...p, [k]: v }));

  const sucursalOptions = useMemo(
    () => [{ id: "", label: "Todas las sucursales" }, ...sucursales.map((s) => ({ id: s.id, label: s.descripcion || s.codigo || "Sin nombre" }))],
    [sucursales],
  );
  const tipoEmpleadoOptions = useMemo(
    () => [{ id: "", label: "Todos los tipos de empleado" }, ...tiposEmpleado.map((t) => ({ id: t.id, label: `${t.codigo} — ${t.nombre}` }))],
    [tiposEmpleado],
  );
  const conceptoOptions = useMemo(
    () => conceptos.filter((c) => c.activo).map((c) => ({ id: c.id, label: `${c.codigo} — ${c.nombre}` })),
    [conceptos],
  );

  // ════════════════════════════════════════════════════════
  // Vista: crear liquidación
  // ════════════════════════════════════════════════════════
  if (showCrear) {
    const esAguinaldoFc = crearForm.tipo === "AGUINALDO";
    const esVacacionesFc = crearForm.tipo === "VACACIONES";
    const esQuincenalFc = crearForm.tipo === "QUINCENAL_1" || crearForm.tipo === "QUINCENAL_2";
    const tituloFc = esAguinaldoFc
      ? "Nuevo aguinaldo anual"
      : esVacacionesFc
        ? "Nueva liquidación de vacaciones"
        : esQuincenalFc
          ? "Nueva liquidación quincenal"
          : "Nueva liquidación mensual";
    return (
      <Container id="rrhh-liq-create-view">
        <FormPanel>
          <FormHead>
            <SectionTitle><Icon icon="lucide:file-plus-2" /> {tituloFc}</SectionTitle>
            <GhostButton onClick={() => setShowCrear(false)}><Icon icon="lucide:x" /> Cerrar</GhostButton>
          </FormHead>
          <FieldsGrid $cols={4}>
            <Field $span={2}>
              <label>Tipo de liquidación *</label>
              <SearchableSelect options={TIPO_LIQ_OPTIONS} value={crearForm.tipo}
                onChange={(id) => updateCrear("tipo", id || "MENSUAL")} clearable={false} />
            </Field>
            <Field>
              <label>Período año *</label>
              <input type="number" min="2020" max="2100" value={crearForm.periodo_anio}
                onChange={(e) => updateCrear("periodo_anio", Number(e.target.value))} />
              <small style={{ opacity: 0.6, fontSize: "0.75rem" }}>Ej: 2026 — año al que pertenece esta liquidación</small>
            </Field>
            {!esAguinaldoFc && (
              <Field>
                <label>Período mes *</label>
                <SearchableSelect options={MES_OPTIONS} value={crearForm.periodo_mes}
                  onChange={(id) => updateCrear("periodo_mes", id ?? crearForm.periodo_mes)} clearable={false} />
              </Field>
            )}
            <Field $span={2}>
              <label>Sucursal</label>
              <SearchableSelect options={sucursalOptions} value={crearForm.sucursal_id}
                onChange={(id) => updateCrear("sucursal_id", id || "")} placeholder="Todas las sucursales" />
            </Field>
            <Field $span={2}>
              <label>Tipo de empleado</label>
              <SearchableSelect options={tipoEmpleadoOptions} value={crearForm.tipo_empleado_id}
                onChange={(id) => updateCrear("tipo_empleado_id", id || "")} placeholder="Todos los tipos de empleado" />
              <small style={{ opacity: 0.6, fontSize: "0.75rem" }}>Ej: solo Asalariados o solo Prestadores de servicios</small>
            </Field>
            <Field>
              <label>Fecha de pago programada *</label>
              <input type="date" value={crearForm.fecha_pago_programada} required
                onChange={(e) => updateCrear("fecha_pago_programada", e.target.value)} />
            </Field>
            <Field>
              <label>Observaciones</label>
              <input value={crearForm.observaciones}
                onChange={(e) => updateCrear("observaciones", e.target.value)} />
            </Field>
          </FieldsGrid>
          {esQuincenalFc && (
            <Alert severity="info" sx={{ mt: 1 }}>
              La quincenal paga el salario proporcional de la quincena y descuenta cuotas de préstamo de esa quincena.
              No calcula IPS ni descuenta anticipos: eso se hace al cerrar la <strong>mensual</strong>, que además resta lo ya pagado en quincenas cerradas.
            </Alert>
          )}
          {esAguinaldoFc && (
            <Alert severity="info" sx={{ mt: 1 }}>
              <strong>Aguinaldo (Art. 243 CT)</strong>: liquidación anual igual a 1/12 de las remuneraciones brutas
              percibidas en el año por cada empleado. Se calcula sobre las liquidaciones <strong>mensuales CERRADAS</strong> del año.
              No aporta IPS. Plazo legal: hasta el 31 de diciembre.
            </Alert>
          )}
          {esVacacionesFc && (
            <Alert severity="info" sx={{ mt: 1 }}>
              <strong>Vacaciones gozadas (Art. 219 CT)</strong>: paga el salario por los días de vacaciones aprobados
              que inician en el mes y tengan «afecta salario». Monto = días × (salario base / 30).
              Sí aporta IPS si el empleado aporta.
            </Alert>
          )}
          <Footer>
            <FooterActionButton type="button" $variant="danger" disabled={creando} onClick={() => setShowCrear(false)}>
              <Icon icon="lucide:x-circle" /> Cancelar
            </FooterActionButton>
            <FooterActionButton type="button" $variant="primary" disabled={creando} onClick={handleCrear}>
              <Icon icon="lucide:check-circle" /> {creando ? "Creando..." : "Crear liquidación"}
            </FooterActionButton>
          </Footer>
        </FormPanel>
        {dialogs}
      </Container>
    );
  }

  // ════════════════════════════════════════════════════════
  // Vista: detalle de una liquidación
  // ════════════════════════════════════════════════════════
  if (verLiq) {
    const liq = verLiq;
    const esBorrador = liq.estado === "BORRADOR";
    const esPre = liq.estado === "PRE_LIQUIDACION";
    const esCerrada = liq.estado === "CERRADA";
    const esMensual = liq.tipo === "MENSUAL";
    return (
      <Container id="rrhh-liq-detail-view">
        <FormPanel>
          <FormHead id="rrhh-liq-detail-head">
            <SectionTitle>
              <Icon icon="lucide:receipt" /> {fmtTipoLiq(liq)} {fmtPeriodo(liq.periodo_anio, liq.periodo_mes)}
              {liq.sucursal?.descripcion ? ` · ${liq.sucursal.descripcion}` : " · todas las sucursales"}
              {liq.tipo_empleado?.nombre ? ` · ${liq.tipo_empleado.nombre}` : ""}
              {" "}<Badge $state={liq.estado}>{liq.estado}</Badge>
            </SectionTitle>
            <Box id="rrhh-liq-detail-actions" sx={{ display: "flex", gap: 0.5 }}>
              {(esBorrador || esPre) && (
                <GhostButton onClick={() => handleCalcular(liq)} disabled={calcLoading}>
                  <Icon icon="lucide:calculator" /> {esPre ? "Recalcular" : "Calcular"}
                </GhostButton>
              )}
              {esPre && (
                <FooterActionButton type="button" $variant="primary" onClick={() => handleCerrar(liq)}>
                  <Icon icon="lucide:lock" /> Cerrar
                </FooterActionButton>
              )}
              {(esBorrador || esPre) && (
                <GhostButton onClick={() => handleAnular(liq)}>
                  <Icon icon="lucide:ban" /> Anular
                </GhostButton>
              )}
              {(esPre || esCerrada) && (
                <GhostButton
                  id="rrhh-liq-planilla-control-pdf-btn"
                  onClick={() => handleDescargarPlanillaControlPdf(liq)}
                  disabled={planillaLoading === "control_pdf"}
                  title="Planilla con conceptos en columnas (una fila por empleado) para firma gerencial"
                >
                  <Icon icon="lucide:clipboard-list" /> {planillaLoading === "control_pdf" ? "Generando..." : "Planilla control PDF"}
                </GhostButton>
              )}
              {(esPre || esCerrada) && (
                <GhostButton
                  id="rrhh-liq-planilla-control-xlsx-btn"
                  onClick={() => handleDescargarPlanillaControlXlsx(liq)}
                  disabled={planillaLoading === "control_xlsx"}
                  title="Planilla con conceptos en columnas (una fila por empleado) para firma gerencial"
                >
                  <Icon icon="lucide:file-spreadsheet" /> {planillaLoading === "control_xlsx" ? "Descargando..." : "Planilla control XLSX"}
                </GhostButton>
              )}
              {esCerrada && esMensual && (
                <GhostButton
                  id="rrhh-liq-planilla-xlsx-btn"
                  onClick={() => handleDescargarPlanillaXlsx(liq)}
                  disabled={planillaLoading === "xlsx"}
                >
                  <Icon icon="lucide:file-spreadsheet" /> {planillaLoading === "xlsx" ? "Descargando..." : "Descargar planilla XLSX"}
                </GhostButton>
              )}
              {esCerrada && esMensual && (
                <GhostButton
                  id="rrhh-liq-planilla-pdf-btn"
                  onClick={() => handleDescargarPlanillaPdf(liq)}
                  disabled={planillaLoading === "pdf"}
                >
                  <Icon icon="lucide:file-text" /> {planillaLoading === "pdf" ? "Generando..." : "Descargar planilla PDF"}
                </GhostButton>
              )}
              <GhostButton onClick={cerrarVista}><Icon icon="lucide:arrow-left" /> Volver</GhostButton>
            </Box>
          </FormHead>

          {esBorrador && (
            <Alert severity="info" sx={{ mb: 2 }}>
              Liquidación en borrador. Hacé click en <strong>Calcular</strong> para que el motor genere el detalle por empleado.
            </Alert>
          )}

          {/* Advertencias del cálculo. Las más frecuentes son los topes legales
              de descuento: acá todavía se pueden corregir; al cerrar frenan. */}
          {esPre && advertencias.length > 0 && (
            <Alert severity="warning" sx={{ mb: 2 }}>
              <AlertTitle>
                {advertencias.length === 1
                  ? "Hay 1 advertencia en este cálculo"
                  : `Hay ${advertencias.length} advertencias en este cálculo`}
              </AlertTitle>
              <Box component="ul" sx={{ m: 0, pl: 2.5 }}>
                {advertencias.map((a, i) => (
                  <li key={i}>
                    <Typography variant="body2">{a}</Typography>
                  </li>
                ))}
              </Box>
              <Typography variant="caption" sx={{ display: "block", mt: 1, opacity: 0.85 }}>
                Si superan el tope legal de descuentos, la liquidación no va a poder cerrarse hasta
                corregirlo: quitá o bajá alguna línea de descuento del empleado afectado.
              </Typography>
            </Alert>
          )}
          {esCerrada && (
            <Alert severity="success" sx={{ mb: 2 }}>
              Liquidación cerrada el {fmtFecha(liq.fecha_cierre)}. Es inmutable.
            </Alert>
          )}

          {esCerrada && (
            <Alert
              severity={asiento ? "info" : "warning"}
              sx={{ mb: 2 }}
              icon={<Icon icon={asiento ? "lucide:landmark" : "lucide:landmark-off"} width={18} />}
              action={
                !asiento && (
                  <GhostButton onClick={handleIntegrarContabilidad} disabled={integrandoCont}>
                    <Icon icon="lucide:refresh-cw" />
                    {integrandoCont ? "Integrando…" : "Generar asiento"}
                  </GhostButton>
                )
              }
            >
              {asiento ? (
                <>
                  <Typography variant="body2" sx={{ fontWeight: 600 }}>
                    Asiento contable #{asiento.numero} · {fmtFecha(asiento.fecha)} · {asiento.estado}
                  </Typography>
                  <Typography variant="caption">
                    Se generó automáticamente al cerrar. Lo podés ver y revertir desde Contabilidad → Asientos.
                  </Typography>
                </>
              ) : (
                <>
                  <Typography variant="body2" sx={{ fontWeight: 600 }}>
                    No hay asiento contable de la liquidación
                  </Typography>
                  <Box sx={{ mt: 0.75, display: "grid", gap: 0.75 }}>
                    <Typography variant="caption" component="div">
                      Este asiento registra el devengamiento de sueldos antes del pago. Si no se genera, normalmente falta completar el mapeo contable de RRHH.
                    </Typography>
                    <Box
                      component="ol"
                      sx={{
                        m: 0,
                        pl: 2.4,
                        display: "grid",
                        gap: 0.35,
                        "& li": { fontSize: "0.75rem", lineHeight: 1.45 },
                      }}
                    >
                      <li>Entrá a Contabilidad → Mapeo de Cuentas.</li>
                      <li>Presioná Crear cuentas y mapeos faltantes para completar la configuración estándar de RRHH.</li>
                      <li>En el grupo RRHH, verificá que SUELDOS_JORNALES y SUELDOS_A_PAGAR queden en verde.</li>
                      <li>Volvé a esta liquidación y presioná Generar asiento.</li>
                    </Box>
                    <Typography variant="caption" component="div" color="text.secondary">
                      Si el mapeo está completo y sigue sin generarse, revisá que Contabilidad esté activa y que exista un período contable abierto para la fecha de cierre.
                    </Typography>
                    <Box>
                      <GhostButton type="button" onClick={() => navigate("/contabilidad?tab=mapeo")}>
                        <Icon icon="lucide:git-merge" /> Abrir mapeo contable
                      </GhostButton>
                    </Box>
                  </Box>
                </>
              )}
            </Alert>
          )}

          {/* Totales */}
          <FieldsGrid $cols={4}>
            <Field><label>Empleados</label><input readOnly value={liq.cantidad_empleados} /></Field>
            <Field><label>Total ingresos</label><input readOnly value={fmtMonto(liq.total_ingresos)} /></Field>
            <Field><label>Total egresos</label><input readOnly value={fmtMonto(liq.total_egresos)} /></Field>
            <Field><label>Neto a pagar</label><input readOnly value={fmtMonto(liq.total_neto)} /></Field>
            <Field><label>IPS obrero</label><input readOnly value={fmtMonto(liq.total_ips_obrero)} /></Field>
            <Field><label>IPS patronal (costo empresa)</label><input readOnly value={fmtMonto(liq.total_ips_patronal)} /></Field>
            <Field><label>IPS admin (costo empresa)</label><input readOnly value={fmtMonto(liq.total_ips_admin)} /></Field>
            <Field><label>Fecha de cálculo</label><input readOnly value={fmtFecha(liq.fecha_calculo)} /></Field>
          </FieldsGrid>

          <Divider />
          <SectionTitle><Icon icon="lucide:users" /> Empleados ({liq.resumenes?.length || 0})</SectionTitle>
          {(!liq.resumenes || liq.resumenes.length === 0) ? (
            <EmptyState>
              <Typography variant="body2" sx={{ opacity: 0.7 }}>
                {esBorrador ? "Calculá la liquidación para ver el detalle." : "Sin empleados en esta liquidación."}
              </Typography>
            </EmptyState>
          ) : (
            <TableWrap>
              <table>
                <thead>
                  <tr>
                    <th>Empleado</th>
                    <th style={{ textAlign: "center" }}>Días</th>
                    <th style={{ textAlign: "right" }}>Bruto</th>
                    <th style={{ textAlign: "right" }}>IPS obrero</th>
                    <th style={{ textAlign: "right" }}>Egresos</th>
                    <th style={{ textAlign: "right" }}>Neto a pagar</th>
                    <th style={{ textAlign: "center" }}>Alerta</th>
                    <th style={{ textAlign: "center" }}>Detalle</th>
                  </tr>
                </thead>
                <tbody>
                  {liq.resumenes.map((r) => {
                    const emp = r.empleado;
                    return (
                      <tr key={r.id}>
                        <td>{emp ? `${emp.numero_empleado} — ${emp.apellidos}, ${emp.nombres}` : "-"}</td>
                        <td style={{ textAlign: "center" }}>{r.dias_trabajados}/{r.dias_mes}</td>
                        <td style={{ textAlign: "right", fontFamily: "monospace" }}>{fmtMonto(r.salario_bruto)}</td>
                        <td style={{ textAlign: "right", fontFamily: "monospace" }}>{fmtMonto(r.ips_obrero)}</td>
                        <td style={{ textAlign: "right", fontFamily: "monospace" }}>{fmtMonto(r.total_egresos)}</td>
                        <td style={{ textAlign: "right", fontFamily: "monospace", fontWeight: 600 }}>{fmtMonto(r.neto_a_pagar)}</td>
                        <td style={{ textAlign: "center" }}>
                          {r.alerta_descuento ? <Icon icon="lucide:alert-triangle" width={16} style={{ color: "#f59e0b" }} /> : "—"}
                        </td>
                        <td style={{ textAlign: "center" }}>
                          <Tooltip title="Ver desglose / ajustar">
                            <IconButton size="small" onClick={() => abrirEmpleado(emp.id, emp)}>
                              <Icon icon="lucide:eye" width={16} />
                            </IconButton>
                          </Tooltip>
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </TableWrap>
          )}
        </FormPanel>

        {/* Dialog detalle por empleado */}
        <Dialog open={empDialog.open} onClose={() => setEmpDialog({ open: false, loading: false, data: null, empleado: null })}
          maxWidth="md" fullWidth>
          <DialogTitle>
            Desglose de liquidación
            {empDialog.empleado && (
              <Typography variant="caption" sx={{ display: "block", opacity: 0.7 }}>
                {empDialog.empleado.numero_empleado} — {empDialog.empleado.apellidos}, {empDialog.empleado.nombres}
              </Typography>
            )}
          </DialogTitle>
          <DialogContent dividers>
            {empDialog.loading ? (
              <Typography>Cargando...</Typography>
            ) : empDialog.data ? (
              <>
                <Box sx={{ display: "flex", gap: 2, mb: 2, flexWrap: "wrap" }}>
                  <Box><Typography variant="caption" sx={{ opacity: 0.7 }}>Bruto</Typography>
                    <Typography variant="body2" sx={{ fontFamily: "monospace" }}>{fmtMonto(empDialog.data.resumen.salario_bruto)}</Typography></Box>
                  <Box><Typography variant="caption" sx={{ opacity: 0.7 }}>Egresos</Typography>
                    <Typography variant="body2" sx={{ fontFamily: "monospace" }}>{fmtMonto(empDialog.data.resumen.total_egresos)}</Typography></Box>
                  <Box><Typography variant="caption" sx={{ opacity: 0.7 }}>Base IPS</Typography>
                    <Typography variant="body2" sx={{ fontFamily: "monospace" }}>{fmtMonto(empDialog.data.resumen.base_ips)}</Typography></Box>
                  <Box><Typography variant="caption" sx={{ opacity: 0.7 }}>Neto a pagar</Typography>
                    <Typography variant="body2" sx={{ fontFamily: "monospace", fontWeight: 600 }}>{fmtMonto(empDialog.data.resumen.neto_a_pagar)}</Typography></Box>
                </Box>

                <TableWrap>
                  <table>
                    <thead>
                      <tr>
                        <th>Concepto</th>
                        <th>Origen</th>
                        <th>Tipo</th>
                        <th style={{ textAlign: "right" }}>Monto</th>
                        <th>Observación</th>
                        {esPre && <th style={{ textAlign: "center" }}></th>}
                      </tr>
                    </thead>
                    <tbody>
                      {empDialog.data.lineas.map((l) => (
                        <tr key={l.id}>
                          <td>{l.concepto ? `${l.concepto.codigo} — ${l.concepto.nombre}` : "-"}</td>
                          <td>
                            <Badge
                              $state={
                                l.origen === "MANUAL" || l.origen === "CONSUMO_FUNCIONARIO"
                                  ? "PENDIENTE"
                                  : "INACTIVO"
                              }
                            >
                              {l.origen === "CONSUMO_FUNCIONARIO" ? "CONSUMO" : l.origen}
                            </Badge>
                          </td>
                          <td>
                            <Badge $state={l.tipo === "INGRESO" ? "ACTIVO" : "ANULADA"}>{l.tipo}</Badge>
                          </td>
                          <td style={{ textAlign: "right", fontFamily: "monospace" }}>{fmtMonto(l.monto)}</td>
                          <td style={{ fontSize: "0.8rem", opacity: 0.8 }}>{l.observacion || "—"}</td>
                          {esPre && (
                            <td style={{ textAlign: "center" }}>
                              {(l.origen === "MANUAL" || l.origen === "CONSUMO_FUNCIONARIO") && (
                                <Tooltip
                                  title={
                                    l.origen === "CONSUMO_FUNCIONARIO"
                                      ? "No cobrar esta factura por planilla"
                                      : "Quitar ajuste"
                                  }
                                >
                                  <IconButton size="small" color="error" onClick={() => handleEliminarLinea(l)}>
                                    <Icon icon="lucide:trash-2" width={14} />
                                  </IconButton>
                                </Tooltip>
                              )}
                            </td>
                          )}
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </TableWrap>

                {esPre && (
                  <>
                    <Divider />
                    <SectionTitle><Icon icon="lucide:plus-circle" /> Agregar ajuste manual</SectionTitle>
                    <FieldsGrid $cols={4}>
                      <Field $span={2}>
                        <label>Concepto *</label>
                        <SearchableSelect options={conceptoOptions} value={lineaForm.concepto_id}
                          onChange={(id) => updateLinea("concepto_id", id || "")}
                          placeholder="Buscar concepto..." />
                      </Field>
                      <Field>
                        <label>Tipo *</label>
                        <SearchableSelect options={TIPO_LINEA_OPTIONS} value={lineaForm.tipo}
                          onChange={(id) => updateLinea("tipo", id || "INGRESO")} clearable={false} />
                      </Field>
                      <MonedaInput
                        label="Monto *"
                        fullWidth
                        value={lineaForm.monto}
                        onChange={(v) => updateLinea("monto", v)}
                      />
                      <Field $span={4}>
                        <label>Observación</label>
                        <input value={lineaForm.observacion}
                          onChange={(e) => updateLinea("observacion", e.target.value)}
                          placeholder="Ej: Horas extra 50% noviembre" />
                      </Field>
                    </FieldsGrid>
                    <Box sx={{ display: "flex", justifyContent: "flex-end" }}>
                      <FooterActionButton type="button" $variant="primary" disabled={agregandoLinea} onClick={handleAgregarLinea}>
                        <Icon icon="lucide:plus" /> {agregandoLinea ? "Agregando..." : "Agregar ajuste"}
                      </FooterActionButton>
                    </Box>
                  </>
                )}
              </>
            ) : (
              <Typography color="text.secondary">Sin datos</Typography>
            )}
          </DialogContent>
          <DialogActions>
            <GhostButton onClick={() => setEmpDialog({ open: false, loading: false, data: null, empleado: null })}>
              Cerrar
            </GhostButton>
            <FooterActionButton
              type="button"
              $variant="primary"
              disabled={!empDialog.data || empDialog.loading}
              onClick={handleVerRecibo}
            >
              <Icon icon="lucide:file-text" /> Ver recibo PDF
            </FooterActionButton>
          </DialogActions>
        </Dialog>

        {/* Dialog: preview del recibo PDF */}
        <Dialog
          open={reciboDialog.open}
          onClose={cerrarRecibo}
          maxWidth="md"
          fullWidth
          PaperProps={{ sx: { height: "92vh" } }}
        >
          <DialogTitle sx={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 1 }}>
            <Box>
              Recibo de sueldo
              {reciboDialog.empleado && (
                <Typography variant="caption" sx={{ display: "block", opacity: 0.7 }}>
                  {reciboDialog.empleado.numero_empleado} — {reciboDialog.empleado.apellidos}, {reciboDialog.empleado.nombres}
                </Typography>
              )}
            </Box>
            <FooterActionButton
              type="button"
              $variant="primary"
              disabled={reciboDialog.loading}
              onClick={handleDescargarReciboDesdePreview}
            >
              <Icon icon="lucide:download" /> Descargar
            </FooterActionButton>
          </DialogTitle>
          <DialogContent dividers sx={{ p: 0, height: "100%", overflow: "hidden" }}>
            {reciboDialog.loading ? (
              <Box sx={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%" }}>
                <Typography color="text.secondary">Generando recibo…</Typography>
              </Box>
            ) : reciboDialog.dataUrl ? (
              <iframe
                title="Recibo de sueldo"
                src={reciboDialog.dataUrl}
                style={{ width: "100%", height: "100%", border: "none" }}
              />
            ) : (
              <Box sx={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%" }}>
                <Typography color="text.secondary">Sin contenido</Typography>
              </Box>
            )}
          </DialogContent>
          <DialogActions>
            <GhostButton onClick={cerrarRecibo}>Cerrar</GhostButton>
          </DialogActions>
        </Dialog>

        <Dialog
          open={Boolean(quitarConsumo.linea)}
          onClose={() => !quitarConsumo.loading && setQuitarConsumo({ linea: null, loading: false })}
          maxWidth="sm"
          fullWidth
        >
          <DialogTitle>Quitar factura del descuento</DialogTitle>
          <DialogContent>
            <Typography variant="body2" sx={{ mb: 1.5 }}>
              {quitarConsumo.linea?.observacion || "Factura del funcionario"} —{" "}
              <strong>{fmtMonto(quitarConsumo.linea?.monto)}</strong>
            </Typography>
            <Typography variant="body2" color="text.secondary">
              <strong>Solo en esta liquidación:</strong> no se descuenta este mes; si recalculás o en la próxima
              liquidación, se vuelve a proponer.
              <br />
              <strong>No volver a proponerla:</strong> para facturas que no se cobran por planilla (por ejemplo una
              compra grande como cliente común). Sigue pendiente en Cuentas por cobrar y tampoco se descuenta en
              la desvinculación. Se revierte en Configuración → Consumo de funcionarios.
            </Typography>
          </DialogContent>
          <DialogActions sx={{ flexWrap: "wrap", gap: 1 }}>
            <Button
              onClick={() => setQuitarConsumo({ linea: null, loading: false })}
              disabled={quitarConsumo.loading}
            >
              Cancelar
            </Button>
            <Button variant="outlined" onClick={() => confirmarQuitarConsumo(false)} disabled={quitarConsumo.loading}>
              Solo en esta liquidación
            </Button>
            <Button
              variant="contained"
              color="error"
              onClick={() => confirmarQuitarConsumo(true)}
              disabled={quitarConsumo.loading}
              startIcon={quitarConsumo.loading ? <CircularProgress size={16} color="inherit" /> : null}
            >
              No volver a proponerla
            </Button>
          </DialogActions>
        </Dialog>

        {dialogs}
      </Container>
    );
  }

  // ════════════════════════════════════════════════════════
  // Vista: listado
  // ════════════════════════════════════════════════════════
  return (
    <Container id="rrhh-liq-list-view">
      <RRHHGuia seccion="liquidaciones" />
      <RRHHPrereqChecklist tabKey="liquidaciones" />
      <ListPanel>
        <ListBody>
          <ToolBar id="rrhh-liq-toolbar">
            <Box sx={{ minWidth: 200 }}>
              <SearchableSelect label="Estado" options={ESTADO_OPTIONS} value={estadoFiltro}
                onChange={(id) => { setEstadoFiltro(id || ""); setPage(1); }}
                placeholder="Todos los estados" />
            </Box>
            <Tooltip title="Refrescar">
              <GhostButton onClick={load} disabled={loading}><Icon icon="lucide:refresh-cw" /></GhostButton>
            </Tooltip>
            <Box sx={{ flex: 1 }} />
            <FooterActionButton id="rrhh-liq-new-btn" type="button" $variant="primary"
              onClick={() => {
                const t = new Date();
                setCrearForm({ tipo: "MENSUAL", periodo_anio: t.getFullYear(), periodo_mes: t.getMonth() + 1, sucursal_id: "", fecha_pago_programada: "", observaciones: "" });
                setShowCrear(true);
              }}>
              <Icon icon="lucide:plus" /> Nueva liquidación
            </FooterActionButton>
          </ToolBar>

          <div id="rrhh-liq-list-content">
            {loading || verLoading ? (
              <EmptyState>Cargando...</EmptyState>
            ) : data.length === 0 ? (
              <RRHHEmptyState
                icon="lucide:receipt"
                titulo="Sin liquidaciones registradas"
                descripcion="Las liquidaciones calculan el sueldo neto de cada empleado según novedades, conceptos y parámetros del período. Creá una liquidación quincenal o mensual para el período actual."
                ctaLabel="Nueva liquidación"
                onCta={() => setShowCrear(true)}
                guiaSeccion="liquidaciones"
              />
            ) : (
              <TableWrap id="rrhh-liq-table">
                <table>
                  <thead>
                    <tr>
                      <th>Período</th>
                      <th>Sucursal</th>
                      <th>Tipo empleado</th>
                      <th>Tipo liq.</th>
                      <th style={{ textAlign: "right" }}>Empleados</th>
                      <th style={{ textAlign: "right" }}>Ingresos</th>
                      <th style={{ textAlign: "right" }}>Egresos</th>
                      <th style={{ textAlign: "right" }}>Neto</th>
                      <th>Estado</th>
                      <th style={{ textAlign: "center" }}>Acciones</th>
                    </tr>
                  </thead>
                  <tbody>
                    {data.map((liq) => {
                      const esBorrador = liq.estado === "BORRADOR";
                      const esPre = liq.estado === "PRE_LIQUIDACION";
                      return (
                        <tr key={liq.id}>
                          <td>{fmtPeriodo(liq.periodo_anio, liq.periodo_mes)}</td>
                          <td>{liq.sucursal?.descripcion || "Todas"}</td>
                          <td>{liq.tipo_empleado?.nombre || "Todos"}</td>
                          <td>{fmtTipoLiq(liq)}</td>
                          <td style={{ textAlign: "right" }}>{liq.cantidad_empleados}</td>
                          <td style={{ textAlign: "right", fontFamily: "monospace" }}>{fmtMonto(liq.total_ingresos)}</td>
                          <td style={{ textAlign: "right", fontFamily: "monospace" }}>{fmtMonto(liq.total_egresos)}</td>
                          <td style={{ textAlign: "right", fontFamily: "monospace", fontWeight: 600 }}>{fmtMonto(liq.total_neto)}</td>
                          <td><Badge $state={liq.estado}>{liq.estado}</Badge></td>
                          <td style={{ textAlign: "center" }}>
                            <RowActions>
                              <Tooltip title="Abrir">
                                <IconButton size="small" onClick={() => abrirLiquidacion(liq)}>
                                  <Icon icon="lucide:eye" width={16} />
                                </IconButton>
                              </Tooltip>
                              {(esBorrador || esPre) && (
                                <Tooltip title={esPre ? "Recalcular" : "Calcular"}>
                                  <IconButton size="small" color="primary" onClick={() => handleCalcular(liq)}>
                                    <Icon icon="lucide:calculator" width={16} />
                                  </IconButton>
                                </Tooltip>
                              )}
                              {esPre && (
                                <Tooltip title="Cerrar">
                                  <IconButton size="small" color="success" onClick={() => handleCerrar(liq)}>
                                    <Icon icon="lucide:lock" width={16} />
                                  </IconButton>
                                </Tooltip>
                              )}
                              {(esBorrador || esPre) && (
                                <Tooltip title="Anular">
                                  <IconButton size="small" color="error" onClick={() => handleAnular(liq)}>
                                    <Icon icon="lucide:ban" width={16} />
                                  </IconButton>
                                </Tooltip>
                              )}
                            </RowActions>
                          </td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </TableWrap>
            )}
          </div>

          <TablePaginationBar
            page={page}
            totalPages={totalPages}
            onPageChange={setPage}
            total={total}
            shown={data.length}
            noun="liquidaciones"
            rowsPerPage={limit}
            onRowsPerPageChange={(n) => {
              setLimit(n);
              setPage(1);
            }}
          />
        </ListBody>
      </ListPanel>
      {dialogs}
    </Container>
  );
}
