/* eslint-disable react/prop-types */
import { Icon } from "@iconify/react";
import {
  Alert,
  Autocomplete,
  Box,
  Button,
  Checkbox,
  Chip,
  Collapse,
  Container,
  FormControlLabel,
  LinearProgress,
  MenuItem,
  Paper,
  Stack,
  Step,
  StepLabel,
  Stepper,
  Switch,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  TextField,
  Typography,
} from "@mui/material";
import { useMutation, useQuery } from "@tanstack/react-query";
import { useMemo, useState } from "react";
import { Link } from "react-router-dom";
import { toast } from "sonner";
import {
  confirmarImportacionGastos,
  descargarPlantillaGastos,
  getJobImportacionGastos,
  guardarMapeoGastos,
  subirArchivoGastos,
} from "../../api/gastos-importador.service";
import { getTiposGasto } from "../../api/gastos.service";
import { useMediosPagoActivosQuery } from "../../tanstack/PagosStack";
import { useTesCuentasQuery } from "../../tanstack/TesoreriaStack";
import { esMedioPagoAnticipo, getMotivoOmisionGasto, medioNoMueveCaja, ScreenGuia } from "../../components/_standards";
import { useFilasImportacionGastosQuery } from "../../tanstack/GastosImportadorStack";
import { usePermission } from "../../hooks/usePermission";

const STEPS = ["Subir archivo", "Mapear tipos de gasto", "Revisar y confirmar", "Resultado"];

const ESTADOS_FINALES = ["completado", "completado_con_errores", "error"];


const comoLista = (data) => (Array.isArray(data) ? data : data?.data ?? []);

export default function ImportarGastosPage() {
  // Gastos vive bajo el módulo COMPRAS (los códigos conservan el prefijo TES_ por historia).
  const { can: canCompras } = usePermission("COMPRAS");
  const canImportar = canCompras("TES_GAS_GASTO_IMPORTAR");

  const [step, setStep] = useState(0);
  const [archivo, setArchivo] = useState(null);
  const [resultadoSubida, setResultadoSubida] = useState(null);
  const [mapeos, setMapeos] = useState({});
  const [resultadoMapeo, setResultadoMapeo] = useState(null);
  const [jobId, setJobId] = useState(null);
  // historico: comprobantes de un sistema anterior, ya pagados y contabilizados allá.
  const [pagoContado, setPagoContado] = useState({ medio_pago_id: "", cuenta_tesoreria_id: "", historico: false });

  const { data: tiposGasto = [] } = useQuery({
    queryKey: ["tipos-gasto"],
    queryFn: getTiposGasto,
    enabled: canImportar,
  });

  const subir = useMutation({
    mutationFn: () => subirArchivoGastos(archivo),
    onSuccess: (data) => {
      setResultadoSubida(data);
      setJobId(data.job_id);
      const inicial = {};
      (data.valores_tipo_gasto ?? []).forEach((v) => {
        inicial[v.texto] = {
          accion: v.alias_existente?.accion ?? "MAPEAR",
          // Lo recordado de otra importación; si no, el tipo del sistema con el mismo nombre.
          tipo_gasto_id: v.alias_existente?.tipo_gasto_id ?? v.sugerido?.tipo_gasto_id ?? "",
          // Tildado por defecto: la próxima importación ya viene mapeada.
          recordar: true,
        };
      });
      setMapeos(inicial);
      setStep(1);
    },
    onError: (err) => {
      toast.error(err?.response?.data?.message ?? "No se pudo procesar el archivo");
    },
  });

  const guardarMapeo = useMutation({
    mutationFn: () =>
      guardarMapeoGastos(jobId, {
        mapeos: (resultadoSubida.valores_tipo_gasto ?? []).map((v) => ({
          tipo_gasto_texto: v.texto,
          accion: mapeos[v.texto]?.accion ?? "MAPEAR",
          tipo_gasto_id: mapeos[v.texto]?.accion === "MAPEAR" ? mapeos[v.texto]?.tipo_gasto_id : undefined,
          recordar: Boolean(mapeos[v.texto]?.recordar),
        })),
      }),
    onSuccess: (data) => {
      setResultadoMapeo(data);
      setStep(2);
    },
    onError: (err) => {
      toast.error(err?.response?.data?.message ?? "No se pudo guardar el mapeo");
    },
  });

  const confirmar = useMutation({
    mutationFn: () =>
      confirmarImportacionGastos(
        jobId,
        pagoContado.historico
          ? { historico: true }
          : {
              medio_pago_id: pagoContado.medio_pago_id || undefined,
              cuenta_tesoreria_id: pagoContado.cuenta_tesoreria_id || undefined,
            },
      ),
    onSuccess: () => {
      setStep(3);
    },
    onError: (err) => {
      toast.error(err?.response?.data?.message ?? "No se pudo confirmar la importación");
    },
  });

  const { data: jobEstado } = useQuery({
    queryKey: ["gasto-import-job", jobId],
    queryFn: () => getJobImportacionGastos(jobId),
    enabled: Boolean(jobId) && step === 3,
    refetchInterval: (query) => (ESTADOS_FINALES.includes(query.state.data?.estado) ? false : 2000),
  });

  const camposMapeoOk = useMemo(() => {
    return (resultadoSubida?.valores_tipo_gasto ?? []).every((v) => {
      const m = mapeos[v.texto];
      if (!m) return false;
      return m.accion === "OMITIR" || (m.accion === "MAPEAR" && Boolean(m.tipo_gasto_id));
    });
  }, [resultadoSubida, mapeos]);

  if (!canImportar) {
    return (
      <Box sx={{ py: 3 }}>
        <Typography variant="body2" color="text.secondary">
          Necesitás el permiso TES_GAS_GASTO_IMPORTAR para importar gastos desde Excel.
        </Typography>
      </Box>
    );
  }

  return (
    <Container maxWidth="lg" sx={{ py: 3 }}>
      <Box mb={2}>
        <Button component={Link} to="/gastos" startIcon={<Icon icon="mdi:arrow-left" width={18} />} size="small" variant="text">
          Volver a Gastos
        </Button>
        <Stack direction="row" alignItems="center" spacing={1} mt={1}>
          <Icon icon="mdi:file-excel-outline" width={28} />
          <Typography variant="h5" fontWeight={700}>
            Importar gastos desde Excel
          </Typography>
        </Stack>
      </Box>

      <ScreenGuia
        titulo="¿Cómo funciona la importación?"
        intro="Subís el Libro de Compras del SET (.xlsx) tal como lo exporta el contador, mapeás los tipos de gasto y confirmás. Los gastos se crean en segundo plano."
        pasos={[
          {
            icon: "mdi:file-upload-outline",
            color: "#60a5fa",
            titulo: "1. Subir archivo",
            desc: "El sistema detecta las columnas del Libro de Compras SET y agrupa los tipos de gasto encontrados.",
          },
          {
            icon: "mdi:swap-horizontal",
            color: "#f59e0b",
            titulo: "2. Mapear tipos de gasto",
            desc: "Asignás cada tipo de gasto detectado a un tipo del catálogo del sistema (o lo omitís).",
          },
          {
            icon: "mdi:clipboard-check-outline",
            color: "#22c55e",
            titulo: "3. Revisar y confirmar",
            desc: "Revisás cuántas filas son válidas y por qué se omite cada una. Indicás con qué se pagaron las de contado, o las marcás como comprobantes históricos.",
          },
          {
            icon: "mdi:progress-check",
            color: "#8b5cf6",
            titulo: "4. Resultado",
            desc: "El procesamiento corre en segundo plano; la pantalla se actualiza sola hasta que termina.",
          },
        ]}
        notas={[
          {
            icon: "mdi:content-save-check-outline",
            text: 'Los mapeos con "Recordar" tildado (viene así por defecto) quedan guardados para la próxima importación de la misma empresa.',
          },
          {
            icon: "mdi:history",
            text: "Comprobantes históricos: facturas viejas ya pagadas y contabilizadas en el sistema anterior. Entran sólo al Libro IVA y a Marangatu, sin asiento, cuenta a pagar ni movimiento de banco.",
          },
        ]}
      />

      <Paper variant="outlined" sx={{ p: 3, mt: 2 }}>
        <Stepper activeStep={step} sx={{ mb: 3 }}>
          {STEPS.map((label) => (
            <Step key={label}>
              <StepLabel>{label}</StepLabel>
            </Step>
          ))}
        </Stepper>

        {step === 0 && <PasoSubir archivo={archivo} setArchivo={setArchivo} subir={subir} />}

        {step === 1 && resultadoSubida && (
          <PasoMapearTipos
            resultado={resultadoSubida}
            tiposGasto={tiposGasto}
            mapeos={mapeos}
            setMapeos={setMapeos}
            camposMapeoOk={camposMapeoOk}
            onGuardar={() => guardarMapeo.mutate()}
            guardando={guardarMapeo.isPending}
            onVolver={() => setStep(0)}
          />
        )}

        {step === 2 && resultadoMapeo && (
          <PasoRevisar
            job={resultadoMapeo}
            pagoContado={pagoContado}
            setPagoContado={setPagoContado}
            onConfirmar={() => confirmar.mutate()}
            confirmando={confirmar.isPending}
            onVolver={() => setStep(1)}
          />
        )}

        {step === 3 && (
          <PasoResultado
            job={jobEstado}
            onNuevaImportacion={() => {
              setStep(0);
              setArchivo(null);
              setResultadoSubida(null);
              setMapeos({});
              setResultadoMapeo(null);
              setJobId(null);
              setPagoContado({ medio_pago_id: "", cuenta_tesoreria_id: "", historico: false });
            }}
          />
        )}
      </Paper>
    </Container>
  );
}

function PasoSubir({ archivo, setArchivo, subir }) {
  const handleDescargarPlantilla = async () => {
    try {
      const blob = await descargarPlantillaGastos();
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = "plantilla_importacion_gastos.xlsx";
      document.body.appendChild(a);
      a.click();
      a.remove();
      URL.revokeObjectURL(url);
    } catch {
      toast.error("No se pudo descargar la plantilla");
    }
  };

  return (
    <Stack spacing={2}>
      <Alert severity="info">
        Tamaño máximo 10 MB. Formato: .xlsx. La primera fila debe contener los encabezados del Libro de Compras del SET.
        ¿No tenés el archivo a mano? Descargá la plantilla con datos de ejemplo para ver el formato exacto.
      </Alert>
      <Stack direction="row" spacing={1.5} flexWrap="wrap">
        <Button variant="outlined" component="label" startIcon={<Icon icon="mdi:paperclip" width={18} />}>
          Seleccionar archivo
          <input type="file" hidden accept=".xlsx" onChange={(e) => setArchivo(e.target.files?.[0] ?? null)} />
        </Button>
        <Button variant="text" onClick={handleDescargarPlantilla} startIcon={<Icon icon="mdi:download" width={18} />}>
          Descargar plantilla de ejemplo
        </Button>
      </Stack>
      <Box>
        {archivo && (
          <Stack direction="row" alignItems="center" spacing={1}>
            <Icon icon="mdi:file-document-outline" width={18} />
            <Typography variant="body2">{archivo.name}</Typography>
            <Chip size="small" label={`${(archivo.size / 1024).toFixed(1)} KB`} />
          </Stack>
        )}
      </Box>
      <Box>
        <Button
          variant="contained"
          disabled={!archivo || subir.isPending}
          onClick={() => subir.mutate()}
          startIcon={<Icon icon="mdi:cloud-upload-outline" width={18} />}
        >
          {subir.isPending ? "Procesando…" : "Subir y procesar"}
        </Button>
      </Box>
    </Stack>
  );
}

function PasoMapearTipos({ resultado, tiposGasto, mapeos, setMapeos, camposMapeoOk, onGuardar, guardando, onVolver }) {
  const valores = resultado.valores_tipo_gasto ?? [];

  const actualizar = (texto, patch) => {
    setMapeos((prev) => ({ ...prev, [texto]: { ...prev[texto], ...patch } }));
  };

  return (
    <Stack spacing={2}>
      <Alert severity="info">
        Archivo: <strong>{resultado.nombre_archivo}</strong> — {resultado.total_filas} filas detectadas.
        {resultado.filas_omitidas_auto > 0 && (
          <> {resultado.filas_omitidas_auto} fila(s) se omitieron automáticamente (no son gastos: importación en curso, mercadería, remuneración de personal).</>
        )}
      </Alert>

      {valores.length === 0 ? (
        <Alert severity="success">No hay tipos de gasto pendientes de mapear.</Alert>
      ) : (
        <TableContainer sx={{ maxHeight: 420 }}>
          <Table size="small" stickyHeader>
            <TableHead>
              <TableRow>
                <TableCell>Tipo de gasto (texto original)</TableCell>
                <TableCell align="center">Filas</TableCell>
                <TableCell>Acción</TableCell>
                <TableCell>Tipo de gasto del sistema</TableCell>
                <TableCell align="center">Recordar</TableCell>
              </TableRow>
            </TableHead>
            <TableBody>
              {valores.map((v) => {
                const m = mapeos[v.texto] ?? { accion: "MAPEAR", tipo_gasto_id: "", recordar: true };
                return (
                  <TableRow key={v.texto} hover>
                    <TableCell>
                      <Typography variant="body2">{v.texto}</Typography>
                      {v.alias_existente ? (
                        <Typography variant="caption" color="success.main">
                          Ya mapeado previamente
                        </Typography>
                      ) : (
                        v.sugerido &&
                        m.tipo_gasto_id === v.sugerido.tipo_gasto_id && (
                          <Typography variant="caption" color="info.main">
                            Sugerido por el nombre: revisalo
                          </Typography>
                        )
                      )}
                    </TableCell>
                    <TableCell align="center">
                      <Chip size="small" label={v.cantidad} />
                    </TableCell>
                    <TableCell>
                      <TextField
                        select
                        size="small"
                        value={m.accion}
                        onChange={(e) => actualizar(v.texto, { accion: e.target.value })}
                        sx={{ minWidth: 130 }}
                      >
                        <MenuItem value="MAPEAR">Mapear</MenuItem>
                        <MenuItem value="OMITIR">Omitir</MenuItem>
                      </TextField>
                    </TableCell>
                    <TableCell>
                      {m.accion === "MAPEAR" ? (
                        <Autocomplete
                          size="small"
                          options={tiposGasto}
                          value={tiposGasto.find((t) => t.id === m.tipo_gasto_id) ?? null}
                          onChange={(_, t) => actualizar(v.texto, { tipo_gasto_id: t?.id ?? "" })}
                          getOptionLabel={(t) => t.descripcion ?? ""}
                          isOptionEqualToValue={(a, b) => a.id === b.id}
                          noOptionsText="Ningún tipo de gasto con ese nombre"
                          sx={{ minWidth: 260 }}
                          renderInput={(params) => (
                            <TextField
                              {...params}
                              placeholder="Buscar tipo de gasto…"
                              error={!m.tipo_gasto_id}
                              inputProps={{ ...params.inputProps, "aria-label": `Tipo de gasto del sistema para ${v.texto}` }}
                            />
                          )}
                        />
                      ) : (
                        <Typography variant="caption" color="text.secondary">
                          Estas filas no se importarán
                        </Typography>
                      )}
                    </TableCell>
                    <TableCell align="center">
                      <Checkbox
                        checked={Boolean(m.recordar)}
                        onChange={(e) => actualizar(v.texto, { recordar: e.target.checked })}
                        size="small"
                      />
                    </TableCell>
                  </TableRow>
                );
              })}
            </TableBody>
          </Table>
        </TableContainer>
      )}

      <Stack direction="row" spacing={2} justifyContent="flex-end">
        <Button onClick={onVolver} variant="text" disabled={guardando}>
          Volver
        </Button>
        <Button
          variant="contained"
          disabled={!camposMapeoOk || guardando}
          onClick={onGuardar}
          startIcon={<Icon icon="mdi:check" width={18} />}
        >
          {guardando ? "Guardando…" : "Guardar mapeo y continuar"}
        </Button>
      </Stack>
    </Stack>
  );
}

function PasoRevisar({ job, pagoContado, setPagoContado, onConfirmar, confirmando, onVolver }) {
  const pideMedio = Boolean(job.requiere_medio_pago) && job.filas_contado > 0 && !pagoContado.historico;
  const medios = comoLista(useMediosPagoActivosQuery().data);
  const cuentas = comoLista(useTesCuentasQuery({ soloActivas: true }).data);
  // Los gastos del Libro de Compras están en guaraníes.
  const cuentasPyg = cuentas.filter((c) => c.activo !== false && String(c.moneda || "PYG").toUpperCase() === "PYG");
  const medio = medios.find((x) => x.id === pagoContado.medio_pago_id);
  const sinCaja = medioNoMueveCaja(medio);

  return (
    <Stack spacing={2}>
      <Alert severity="info">Revisá el resumen antes de confirmar. Los gastos se crearán en segundo plano.</Alert>
      <Stack direction="row" spacing={2} flexWrap="wrap">
        <ResumenTile label="Válidas" valor={job.filas_validas} color="success.main" />
        <ResumenTile label="Inválidas" valor={job.filas_invalidas} color={job.filas_invalidas > 0 ? "error.main" : "text.primary"} />
        <ResumenTile label="Omitidas" valor={job.filas_omitidas} color="text.secondary" />
      </Stack>
      {job.filas_invalidas > 0 && (
        <Alert severity="warning">
          Hay {job.filas_invalidas} fila(s) con datos inválidos (fecha, número de comprobante, etc.) que no se importarán.
        </Alert>
      )}
      <FilasNoImportadas jobId={job.id} omitidas={job.filas_omitidas} invalidas={job.filas_invalidas} />
      <Paper variant="outlined" sx={{ p: 2 }}>
        <FormControlLabel
          control={
            <Switch
              checked={Boolean(pagoContado.historico)}
              onChange={(e) => setPagoContado((p) => ({ ...p, historico: e.target.checked }))}
            />
          }
          label={<Typography fontWeight={600}>Son comprobantes históricos</Typography>}
        />
        <Typography variant="body2" color="text.secondary">
          Para facturas viejas que ya están pagadas y contabilizadas en el sistema anterior. Sólo entran al Libro IVA y
          al archivo de Marangatu: no generan asiento contable, cuenta a pagar ni movimiento de banco.
        </Typography>
      </Paper>
      {pideMedio && (
        <Paper variant="outlined" sx={{ p: 2 }}>
          <Typography variant="subtitle2" fontWeight={700}>
            ¿Con qué se pagaron los {job.filas_contado} gasto(s) de contado?
          </Typography>
          <Typography variant="body2" color="text.secondary" sx={{ mb: 1.5 }}>
            Se registran como pagados y salen de la cuenta que elijas. Los de crédito quedan en Cuentas a Pagar. Los rendidos
            con anticipo de viático se cancelan contra el anticipo y no vuelven a salir de caja.
          </Typography>
          <Box sx={{ display: "grid", gap: 2, gridTemplateColumns: "repeat(auto-fill, minmax(240px, 1fr))", alignItems: "end" }}>
            <TextField
              select
              size="small"
              label="Medio de pago"
              value={pagoContado.medio_pago_id}
              onChange={(e) => setPagoContado((p) => ({ ...p, medio_pago_id: e.target.value, cuenta_tesoreria_id: "" }))}
              error={!pagoContado.medio_pago_id}
              helperText={!pagoContado.medio_pago_id ? "Obligatorio. Ej: Efectivo o Transferencia" : " "}
            >
              {medios.map((x) => (
                <MenuItem key={x.id} value={x.id}>
                  {x.descripcion}
                </MenuItem>
              ))}
            </TextField>
            {!sinCaja && (
              <TextField
                select
                size="small"
                label="Cuenta de tesorería"
                value={pagoContado.cuenta_tesoreria_id}
                onChange={(e) => setPagoContado((p) => ({ ...p, cuenta_tesoreria_id: e.target.value }))}
                helperText="Opcional: si la dejás vacía se usa la cuenta por defecto del medio"
              >
                <MenuItem value="">Cuenta por defecto del medio</MenuItem>
                {cuentasPyg.map((c) => (
                  <MenuItem key={c.id} value={c.id}>
                    {c.nombre}
                  </MenuItem>
                ))}
              </TextField>
            )}
          </Box>
          {sinCaja && (
            <Alert severity="info" sx={{ mt: 1.5 }}>
              {esMedioPagoAnticipo(medio)
                ? "Con este medio los gastos se cancelan contra un anticipo ya entregado: no sale plata de ninguna cuenta."
                : "Este medio no mueve dinero: los gastos se asientan contra la cuenta «Al pagar» del medio, sin salir del banco."}
            </Alert>
          )}
        </Paper>
      )}
      <Stack direction="row" spacing={2} justifyContent="flex-end">
        <Button onClick={onVolver} variant="text" disabled={confirmando}>
          Volver
        </Button>
        <Button
          variant="contained"
          disabled={confirmando || job.filas_validas === 0 || (pideMedio && !pagoContado.medio_pago_id)}
          onClick={onConfirmar}
          startIcon={<Icon icon="mdi:check-circle-outline" width={18} />}
        >
          {confirmando ? "Confirmando…" : "Confirmar e importar"}
        </Button>
      </Stack>
    </Stack>
  );
}

/** Filas que quedan afuera (omitidas a propósito o con datos inválidos), con el motivo. */
function FilasNoImportadas({ jobId, omitidas = 0, invalidas = 0 }) {
  const [abierto, setAbierto] = useState(false);
  const total = (omitidas ?? 0) + (invalidas ?? 0);
  const { data: filasOmitidas = [] } = useFilasImportacionGastosQuery(jobId, "omitida", { enabled: abierto && omitidas > 0 });
  const { data: filasInvalidas = [] } = useFilasImportacionGastosQuery(jobId, "invalida", { enabled: abierto && invalidas > 0 });
  if (!total) return null;

  const filas = [
    ...filasOmitidas.map((f) => ({ ...f, motivo: getMotivoOmisionGasto(f.motivo_omision) })),
    ...filasInvalidas.map((f) => ({
      ...f,
      motivo: { label: "Datos inválidos", descripcion: Array.isArray(f.errores) ? f.errores.join(", ") : String(f.errores ?? "") },
    })),
  ].sort((a, b) => a.fila_numero - b.fila_numero);
  const comprobante = (f) => [f.establecimiento, f.punto_expedicion, f.numero_factura].filter(Boolean).join("-") || "—";

  return (
    <Box>
      <Button
        size="small"
        onClick={() => setAbierto((v) => !v)}
        startIcon={<Icon icon={abierto ? "mdi:chevron-up" : "mdi:chevron-down"} width={18} />}
      >
        {abierto ? "Ocultar" : "Ver"} las {total} fila(s) que no se importan
      </Button>
      <Collapse in={abierto} unmountOnExit>
        <TableContainer sx={{ maxHeight: 320, mt: 1 }}>
          <Table size="small" stickyHeader aria-label="Filas que no se importan">
            <TableHead>
              <TableRow>
                <TableCell>Fila</TableCell>
                <TableCell>Proveedor</TableCell>
                <TableCell>Comprobante</TableCell>
                <TableCell>Motivo</TableCell>
              </TableRow>
            </TableHead>
            <TableBody>
              {filas.map((f) => (
                <TableRow key={f.id}>
                  <TableCell>{f.fila_numero}</TableCell>
                  <TableCell>{f.razon_social || "—"}</TableCell>
                  <TableCell>{comprobante(f)}</TableCell>
                  <TableCell>
                    <Typography variant="body2" fontWeight={600}>
                      {f.motivo.label}
                    </Typography>
                    {f.motivo.descripcion && (
                      <Typography variant="caption" color="text.secondary">
                        {f.motivo.descripcion}
                      </Typography>
                    )}
                  </TableCell>
                </TableRow>
              ))}
            </TableBody>
          </Table>
        </TableContainer>
      </Collapse>
    </Box>
  );
}

function ResumenTile({ label, valor, color }) {
  return (
    <Paper variant="outlined" sx={{ p: 2, flex: 1, minWidth: 120, textAlign: "center" }}>
      <Typography variant="caption" color="text.secondary">
        {label}
      </Typography>
      <Typography variant="h5" fontWeight={700} color={color}>
        {valor}
      </Typography>
    </Paper>
  );
}

function PasoResultado({ job, onNuevaImportacion }) {
  if (!job) {
    return (
      <Stack spacing={2} alignItems="center" sx={{ py: 4 }}>
        <LinearProgress sx={{ width: "100%" }} />
        <Typography variant="body2" color="text.secondary">
          Iniciando procesamiento…
        </Typography>
      </Stack>
    );
  }

  const procesando = !ESTADOS_FINALES.includes(job.estado);

  if (procesando) {
    return (
      <Stack spacing={2} alignItems="center" sx={{ py: 4 }}>
        <LinearProgress sx={{ width: "100%" }} />
        <Typography variant="body2" color="text.secondary">
          Procesando {job.filas_validas} gasto(s)… ({job.filas_importadas ?? 0} completados hasta ahora)
        </Typography>
      </Stack>
    );
  }

  const errorSeverity = job.estado === "error" ? "error" : job.estado === "completado_con_errores" ? "warning" : "success";
  const filasConError = job.filas_con_error ?? [];

  return (
    <Stack spacing={2}>
      <Alert severity={errorSeverity}>
        Importación finalizada: <strong>{job.filas_importadas}</strong> gasto(s) creado(s)
        {filasConError.length > 0 && <> — {filasConError.length} fila(s) con error</>}.
      </Alert>

      {filasConError.length > 0 && (
        <>
          <Typography variant="subtitle1" fontWeight={700}>
            Filas con error
          </Typography>
          <TableContainer sx={{ maxHeight: 300 }}>
            <Table size="small" stickyHeader>
              <TableHead>
                <TableRow>
                  <TableCell>Fila</TableCell>
                  <TableCell>Proveedor</TableCell>
                  <TableCell>Error</TableCell>
                </TableRow>
              </TableHead>
              <TableBody>
                {filasConError.map((f) => (
                  <TableRow key={f.id}>
                    <TableCell>{f.fila_numero}</TableCell>
                    <TableCell>{f.razon_social || "-"}</TableCell>
                    <TableCell>
                      <Typography variant="caption" color="error.main">
                        {Array.isArray(f.errores) ? f.errores.join(", ") : String(f.errores ?? "")}
                      </Typography>
                    </TableCell>
                  </TableRow>
                ))}
              </TableBody>
            </Table>
          </TableContainer>
        </>
      )}

      <Stack direction="row" spacing={2} justifyContent="flex-end">
        <Button component={Link} to="/gastos" variant="outlined" startIcon={<Icon icon="mdi:format-list-bulleted" width={18} />}>
          Ver gastos
        </Button>
        <Button onClick={onNuevaImportacion} variant="contained" startIcon={<Icon icon="mdi:refresh" width={18} />}>
          Nueva importación
        </Button>
      </Stack>
    </Stack>
  );
}
