import { Icon } from "@iconify/react";
import {
  Box,
  Button,
  Card,
  CardContent,
  Chip,
  CircularProgress,
  Grid,
  IconButton,
  MenuItem,
  Pagination,
  Paper,
  Skeleton,
  Stack,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  TextField,
  Tooltip,
  Typography,
} from "@mui/material";
import { useMemo, useState } from "react";
import { useNavigate, useSearchParams } from "react-router-dom";
import { toast } from "sonner";
import * as XLSX from "xlsx";
import { getRendicionPDF, listarRendiciones } from "../api/rendicion-viaticos.service";
import { useDebouncedValue } from "../hooks/useDebouncedValue";
import { usePermission } from "../hooks/usePermission";
import { EmptyState, PDFPreviewDialog, ScreenGuia } from "../components/_standards";
import {
  ESTADO_RENDICION,
  ESTADO_RENDICION_LIST,
  getEstadoRendicion,
} from "../components/_standards/enums/estadosRendicionViatico";
import { fmtMoneda } from "../components/_standards/enums/monedas";
import { useConfigViaticosQuery, useRendicionesQuery } from "../tanstack/RendicionViaticosStack";
import { fmtFechaCalendario, hoyISO } from "../utils/fecha";
import { ConfigViaticosDialog } from "../components/organismos/RendicionViaticosDesign/ConfigViaticosDialog";
import { NuevaRendicionDialog } from "../components/organismos/RendicionViaticosDesign/NuevaRendicionDialog";
import { sanitizeRows } from "../components/_standards";
import { saldoRendicion } from "../components/organismos/RendicionViaticosDesign/saldoRendicion";

const PAGE_SIZE = 20;

const GUIA_PASOS = [
  {
    icon: "mdi:hand-coin",
    color: "#3b82f6",
    titulo: "1. Anticipar al empleado",
    desc: "Se registra el pago del adelanto en concepto de viáticos. Genera asiento contable + movimiento de tesorería.",
  },
  {
    icon: "mdi:receipt-text",
    color: "#f59e0b",
    titulo: "2. Cargar gastos rendidos",
    desc: "Al volver el empleado, el administrativo registra los gastos con o sin factura, vinculados a esta rendición.",
  },
  {
    icon: "mdi:check-circle",
    color: "#22c55e",
    titulo: "3. Cerrar y balancear",
    desc: "Al cerrar, si sobra plata se registra la devolución. Si faltó, se paga el reintegro (ahora o queda como CxP al empleado).",
  },
];

const GUIA_NOTAS = [
  {
    icon: "mdi:information-outline",
    text: "Una rendición admite múltiples adelantos si el viaje se alarga o hay imprevistos.",
  },
  {
    icon: "mdi:alert-outline",
    text: "Los gastos sin factura no generan IVA crédito ni aparecen en Libro IVA Compras.",
  },
  {
    icon: "mdi:lock-outline",
    text: "Una rendición cerrada es inmutable. Para corregirla hay que anularla completa.",
  },
];

export function RendicionViaticosPage() {
  const navigate = useNavigate();
  const [searchParams, setSearchParams] = useSearchParams();

  const filtroEstado = searchParams.get("estado") ?? "todos";
  const filtroPendientesDias = searchParams.get("pendientes") ?? "todos";
  const search = searchParams.get("q") ?? "";
  const page = Number(searchParams.get("page") ?? "1");

  const updateParams = (patch) => {
    const next = new URLSearchParams(searchParams);
    Object.entries(patch).forEach(([k, v]) => {
      if (v === undefined || v === null || v === "" || v === "todos") next.delete(k);
      else next.set(k, String(v));
    });
    setSearchParams(next, { replace: true });
  };

  const { can } = usePermission("RRHH");
  const canCreate = can("RH_VIA_RENDICION_CREAR");
  const canConfig = can("RH_VIA_CONFIG_EDITAR");

  const [dialogAlta, setDialogAlta] = useState(false);
  const [dialogConfig, setDialogConfig] = useState(false);
  const [exportando, setExportando] = useState(false);
  const [pdfRendicion, setPdfRendicion] = useState(null);
  const fetchPDF = useMemo(
    () => (pdfRendicion ? () => getRendicionPDF(pdfRendicion.id) : null),
    [pdfRendicion],
  );

  const { data: config } = useConfigViaticosQuery();
  const diasAlerta = config?.viatico_dias_alerta ?? 15;

  const searchDebounced = useDebouncedValue(search, 400);

  const filtros = useMemo(() => {
    const f = {
      page: String(page),
      limit: String(PAGE_SIZE),
    };
    if (filtroEstado !== "todos") f.estado = filtroEstado;
    if (searchDebounced.trim()) f.search = searchDebounced.trim();
    if (filtroPendientesDias === "atrasadas") f.dias_sin_rendir_min = String(diasAlerta);
    return f;
  }, [filtroEstado, searchDebounced, page, filtroPendientesDias, diasAlerta]);

  const { data, isLoading, isFetching } = useRendicionesQuery(filtros);

  const items = data?.items ?? [];
  const totalPages = data?.lastPage ?? 1;
  const total = data?.total ?? 0;

  // KPIs — se calculan del conjunto visible.
  const kpis = useMemo(() => {
    const abiertas = items.filter((r) =>
      ["ADELANTO_PAGADO", "SIN_ADELANTO", "PENDIENTE_APROBACION", "BORRADOR"].includes(r.estado),
    );
    const montoPendientePorMoneda = {};
    // Lo que el empleado todavía tiene que devolver, abierta o cerrada con devolución diferida.
    items.forEach((r) => {
      const code = r.moneda?.codigo || "PYG";
      const monto = Number(r.liquidacion?.pendiente ?? r.saldo ?? 0);
      if (monto > 0) montoPendientePorMoneda[code] = (montoPendientePorMoneda[code] || 0) + monto;
    });
    // Días promedio sin rendir (solo abiertas post-viaje).
    const hoy = new Date();
    const diasArr = abiertas
      .filter((r) => r.fecha_fin && new Date(r.fecha_fin) < hoy)
      .map((r) => Math.floor((hoy - new Date(r.fecha_fin)) / (1000 * 60 * 60 * 24)));
    const diasPromedio = diasArr.length
      ? Math.round(diasArr.reduce((a, b) => a + b, 0) / diasArr.length)
      : 0;
    return {
      total,
      abiertas: abiertas.length,
      montoPendientePorMoneda,
      diasPromedio,
    };
  }, [items, total]);

  const handleExportar = async () => {
    if (exportando) return;
    setExportando(true);
    try {
      // Traigo todo lo que matchea los filtros actuales (sin paginar).
      const params = { ...filtros, page: "1", limit: "200" };
      let all = [];
      let pag = 1;
      // Iterar mientras el backend devuelva más páginas (máx 20 pases = 4k regs).
      for (let i = 0; i < 20; i++) {
        params.page = String(pag);
        const resp = await listarRendiciones(params);
        const items = resp?.items ?? [];
        all = all.concat(items);
        if (pag >= (resp?.lastPage ?? 1)) break;
        pag += 1;
      }
      if (!all.length) {
        toast.info("No hay rendiciones para exportar con el filtro actual");
        return;
      }

      const rows = [
        [
          "Número",
          "Empleado",
          "Cédula",
          "Concepto",
          "Fecha inicio",
          "Fecha fin",
          "Moneda",
          "Adelantado",
          "Rendido",
          "Saldo pendiente",
          "Estado",
        ],
      ];
      for (const r of all) {
        rows.push([
          r.numero_rendicion,
          `${r.empleado?.nombres ?? ""} ${r.empleado?.apellidos ?? ""}`.trim(),
          r.empleado?.cedula_identidad ?? "",
          r.concepto,
          r.fecha_inicio ? new Date(r.fecha_inicio).toLocaleDateString("es-PY") : "",
          r.fecha_fin ? new Date(r.fecha_fin).toLocaleDateString("es-PY") : "",
          r.moneda?.codigo ?? "PYG",
          Number(r.monto_adelanto_total || 0),
          Number(r.monto_rendido_total || 0),
          Number(r.liquidacion?.pendiente ?? r.saldo ?? 0),
          r.estado,
        ]);
      }

      const wb = XLSX.utils.book_new();
      const ws = XLSX.utils.aoa_to_sheet(sanitizeRows(rows));
      // Anchos de columna aproximados.
      ws["!cols"] = [
        { wch: 16 }, { wch: 28 }, { wch: 12 }, { wch: 32 },
        { wch: 12 }, { wch: 12 }, { wch: 8 }, { wch: 14 },
        { wch: 14 }, { wch: 14 }, { wch: 18 },
      ];
      XLSX.utils.book_append_sheet(wb, ws, "Rendiciones");

      const hoy = hoyISO();
      XLSX.writeFile(wb, `rendiciones-viaticos-${hoy}.xlsx`);
      toast.success("Reporte exportado correctamente");
    } catch (err) {
      toast.error(err?.response?.data?.message || "Error al exportar");
    } finally {
      setExportando(false);
    }
  };

  const diasSinRendir = (r) => {
    if (!r.fecha_fin) return null;
    const dias = Math.floor((new Date() - new Date(r.fecha_fin)) / (1000 * 60 * 60 * 24));
    return dias < 0 ? 0 : dias;
  };

  return (
    <Box p={2}>
      <ScreenGuia
        titulo="Rendición de viáticos"
        moduloPadre="RRHH · Finanzas"
        intro="Ciclo completo de anticipos, gastos y cierre de rendiciones de viaje por empleado."
        pasos={GUIA_PASOS}
        notas={GUIA_NOTAS}
      />

      <Stack direction="row" alignItems="center" justifyContent="space-between" mb={2} sx={{ flexWrap: "wrap", gap: 1 }}>
        <Typography variant="h6" sx={{ display: "flex", alignItems: "center", gap: 1 }}>
          <Icon icon="mdi:briefcase-account" />
          Anticipos y Rendiciones
        </Typography>
        <Stack direction="row" spacing={1}>
          {canConfig && (
            <Button
              variant="outlined"
              startIcon={<Icon icon="mdi:cog-outline" />}
              onClick={() => setDialogConfig(true)}
            >
              Configuración
            </Button>
          )}
          <Button
            variant="outlined"
            startIcon={<Icon icon="mdi:file-excel-box" />}
            onClick={handleExportar}
            disabled={exportando}
          >
            {exportando ? "Exportando..." : "Exportar Excel"}
          </Button>
          {canCreate && (
            <Button
              variant="contained"
              startIcon={<Icon icon="mdi:plus" />}
              onClick={() => setDialogAlta(true)}
            >
              Nueva rendición
            </Button>
          )}
        </Stack>
      </Stack>

      {/* Filtros */}
      <Paper variant="outlined" sx={{ p: 2, mb: 2, borderRadius: 2 }}>
        <Stack direction={{ xs: "column", md: "row" }} spacing={2} alignItems={{ md: "center" }}>
          <TextField
            select
            size="small"
            label="Estado"
            value={filtroEstado}
            onChange={(e) => {
              updateParams({ estado: e.target.value, page: 1 });
            }}
            sx={{ minWidth: 220 }}
          >
            <MenuItem value="todos">Todos los estados</MenuItem>
            {ESTADO_RENDICION_LIST.map((e) => (
              <MenuItem key={e.value} value={e.value}>
                <Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
                  <Icon icon={e.icon} width={16} />
                  <span>{e.label}</span>
                </Box>
              </MenuItem>
            ))}
          </TextField>
          <TextField
            select
            size="small"
            label="Pendientes"
            value={filtroPendientesDias}
            onChange={(e) => {
              updateParams({ pendientes: e.target.value, page: 1 });
            }}
            sx={{ minWidth: 220 }}
          >
            <MenuItem value="todos">Todas</MenuItem>
            <MenuItem value="atrasadas">Atrasadas más de {diasAlerta} días</MenuItem>
          </TextField>
          <TextField
            size="small"
            label="Buscar (número o concepto)"
            value={search}
            onChange={(e) => {
              updateParams({ q: e.target.value, page: 1 });
            }}
            sx={{ flex: 1, minWidth: 240 }}
            InputProps={{
              startAdornment: (
                <Icon icon="mdi:magnify" width={18} style={{ marginRight: 6, opacity: 0.6 }} />
              ),
            }}
          />
        </Stack>
      </Paper>

      {/* KPIs */}
      <Grid container spacing={{ xs: 1, sm: 2 }} sx={{ mb: 2 }}>
        <Grid size={{ xs: 6, sm: 3 }}>
          <Card variant="outlined" sx={{ height: "100%" }}>
            <CardContent sx={{ p: { xs: 1, sm: 1.5 } }}>
              <Typography color="text.secondary" variant="caption" sx={{ display: "flex", alignItems: "center", gap: 0.5 }}>
                <Icon icon="mdi:sigma" width={16} /> Total
              </Typography>
              <Typography variant="h5" fontWeight={700}>
                {isLoading ? <Skeleton width={40} /> : kpis.total}
              </Typography>
            </CardContent>
          </Card>
        </Grid>
        <Grid size={{ xs: 6, sm: 3 }}>
          <Card variant="outlined" sx={{ height: "100%" }}>
            <CardContent sx={{ p: { xs: 1, sm: 1.5 } }}>
              <Typography color="text.secondary" variant="caption" sx={{ display: "flex", alignItems: "center", gap: 0.5 }}>
                <Icon icon="mdi:clock-outline" width={16} /> Abiertas
              </Typography>
              <Typography variant="h5" fontWeight={700} color="warning.main">
                {isLoading ? <Skeleton width={40} /> : kpis.abiertas}
              </Typography>
            </CardContent>
          </Card>
        </Grid>
        <Grid size={{ xs: 12, sm: 3 }}>
          <Card variant="outlined" sx={{ height: "100%" }}>
            <CardContent sx={{ p: { xs: 1, sm: 1.5 } }}>
              <Typography color="text.secondary" variant="caption" sx={{ display: "flex", alignItems: "center", gap: 0.5 }}>
                <Icon icon="mdi:cash" width={16} /> Saldo pendiente
              </Typography>
              <Box sx={{ display: "flex", flexDirection: "column", gap: 0.25 }}>
                {isLoading ? (
                  <Skeleton width={100} />
                ) : Object.keys(kpis.montoPendientePorMoneda).length === 0 ? (
                  <Typography variant="body1" fontWeight={700} color="text.secondary">
                    Sin pendiente
                  </Typography>
                ) : (
                  Object.entries(kpis.montoPendientePorMoneda).map(([code, m]) => (
                    <Typography key={code} variant="body1" fontWeight={700} color="success.main">
                      {fmtMoneda(m, code)}
                    </Typography>
                  ))
                )}
              </Box>
            </CardContent>
          </Card>
        </Grid>
        <Grid size={{ xs: 6, sm: 3 }}>
          <Card variant="outlined" sx={{ height: "100%", borderColor: kpis.diasPromedio > diasAlerta ? "warning.light" : "divider" }}>
            <CardContent sx={{ p: { xs: 1, sm: 1.5 } }}>
              <Typography color="text.secondary" variant="caption" sx={{ display: "flex", alignItems: "center", gap: 0.5 }}>
                <Icon icon="mdi:calendar-clock" width={16} /> Promedio días sin rendir
              </Typography>
              <Typography variant="h5" fontWeight={700} color={kpis.diasPromedio > diasAlerta ? "warning.main" : "text.primary"}>
                {isLoading ? <Skeleton width={40} /> : `${kpis.diasPromedio}d`}
              </Typography>
            </CardContent>
          </Card>
        </Grid>
      </Grid>

      {/* Tabla */}
      <Paper variant="outlined" sx={{ overflow: "hidden", borderRadius: 2 }}>
        {isLoading ? (
          <Box sx={{ p: 2 }}>
            <Skeleton height={44} />
            <Skeleton height={44} />
            <Skeleton height={44} />
          </Box>
        ) : items.length === 0 ? (
          <Box sx={{ p: 3 }}>
            <EmptyState
              icon="mdi:briefcase-account"
              title="Sin rendiciones en el filtro actual"
              description="Ajustá los filtros o creá una nueva rendición con el botón de arriba."
              actionLabel="Nueva rendición"
              onAction={() => setDialogAlta(true)}
            />
          </Box>
        ) : (
          <TableContainer>
            <Table size="small">
              <TableHead>
                <TableRow>
                  <TableCell sx={{ fontWeight: 600 }}>Número</TableCell>
                  <TableCell sx={{ fontWeight: 600 }}>Empleado</TableCell>
                  <TableCell sx={{ fontWeight: 600 }}>Concepto</TableCell>
                  <TableCell sx={{ fontWeight: 600 }}>Fecha inicio</TableCell>
                  <TableCell sx={{ fontWeight: 600 }} align="center">Días sin rendir</TableCell>
                  <TableCell sx={{ fontWeight: 600 }} align="right">Adelanto</TableCell>
                  <TableCell sx={{ fontWeight: 600 }} align="right">Rendido</TableCell>
                  <TableCell sx={{ fontWeight: 600 }} align="right">Saldo pendiente</TableCell>
                  <TableCell sx={{ fontWeight: 600 }}>Estado</TableCell>
                  <TableCell sx={{ fontWeight: 600 }} align="center">Acciones</TableCell>
                </TableRow>
              </TableHead>
              <TableBody>
                {items.map((r) => {
                  const estadoInfo = getEstadoRendicion(r.estado);
                  const isCerrada = r.estado === "CERRADA" || r.estado === "ANULADA";
                  const anuladoSx = r.estado === "ANULADA"
                    ? { color: "text.disabled", textDecoration: "line-through" }
                    : {};
                  const dias = diasSinRendir(r);
                  const alerta = dias !== null && dias > diasAlerta && !isCerrada;
                  const monedaCodigo = r.moneda?.codigo || "PYG";
                  return (
                    <TableRow
                      key={r.id}
                      hover
                      sx={{
                        cursor: "pointer",
                        ...(alerta ? { bgcolor: "rgba(239,68,68,0.05)" } : {}),
                      }}
                      onClick={() => navigate(`/rendicion-viaticos/${r.id}`)}
                    >
                      <TableCell>
                        <Typography sx={{ fontFamily: "monospace", fontWeight: 600, ...anuladoSx }}>
                          {r.numero_rendicion}
                        </Typography>
                      </TableCell>
                      <TableCell sx={anuladoSx}>
                        <Typography variant="body2" fontWeight={600}>
                          {r.empleado?.nombres} {r.empleado?.apellidos}
                        </Typography>
                        {r.empleado?.numero_empleado && (
                          <Typography variant="caption" color="text.secondary">
                            #{r.empleado.numero_empleado}
                          </Typography>
                        )}
                      </TableCell>
                      <TableCell sx={anuladoSx}>{r.concepto}</TableCell>
                      <TableCell sx={anuladoSx}>{fmtFechaCalendario(r.fecha_inicio)}</TableCell>
                      <TableCell align="center">
                        {dias === null ? (
                          "—"
                        ) : isCerrada ? (
                          <Typography variant="caption" color="text.secondary">
                            —
                          </Typography>
                        ) : alerta ? (
                          <Chip
                            size="small"
                            label={`${dias}d`}
                            color="warning"
                            icon={<Icon icon="mdi:alert-outline" />}
                          />
                        ) : (
                          `${dias}d`
                        )}
                      </TableCell>
                      <TableCell align="right" sx={anuladoSx}>
                        {fmtMoneda(Number(r.monto_adelanto_total || 0), monedaCodigo)}
                      </TableCell>
                      <TableCell align="right" sx={anuladoSx}>
                        {fmtMoneda(Number(r.monto_rendido_total || 0), monedaCodigo)}
                      </TableCell>
                      <TableCell align="right">
                        {(() => {
                          // Lo que falta saldar: 0 si la devolución o el reintegro ya se hicieron.
                          const sv = saldoRendicion(r, monedaCodigo);
                          return (
                            <Tooltip title={sv.texto}>
                              <Typography
                                sx={{
                                  fontWeight: 700,
                                  color: r.estado === "ANULADA" ? "text.disabled" : sv.color,
                                  textDecoration: r.estado === "ANULADA" ? "line-through" : undefined,
                                }}
                              >
                                {fmtMoneda(Math.abs(sv.pendiente), monedaCodigo)}
                              </Typography>
                            </Tooltip>
                          );
                        })()}
                      </TableCell>
                      <TableCell>
                        <Chip
                          size="small"
                          label={estadoInfo.label}
                          color={estadoInfo.color}
                          variant="outlined"
                          icon={<Icon icon={estadoInfo.icon} />}
                        />
                      </TableCell>
                      <TableCell align="center">
                        <Stack direction="row" spacing={0.5} justifyContent="center">
                          <Tooltip title="Ver detalle" enterDelay={300}>
                            <IconButton
                              size="small"
                              onClick={(e) => {
                                e.stopPropagation();
                                navigate(`/rendicion-viaticos/${r.id}`);
                              }}
                            >
                              <Icon icon="lucide:eye" width={16} />
                            </IconButton>
                          </Tooltip>
                          <Tooltip title="Ver PDF" enterDelay={300}>
                            <IconButton
                              size="small"
                              onClick={(e) => {
                                e.stopPropagation();
                                setPdfRendicion(r);
                              }}
                            >
                              <Icon icon="mdi:file-pdf-box" width={16} />
                            </IconButton>
                          </Tooltip>
                        </Stack>
                      </TableCell>
                    </TableRow>
                  );
                })}
              </TableBody>
            </Table>
          </TableContainer>
        )}

        {isFetching && !isLoading && (
          <Box sx={{ p: 1, display: "flex", alignItems: "center", gap: 1 }}>
            <CircularProgress size={14} />
            <Typography variant="caption" color="text.secondary">
              Actualizando…
            </Typography>
          </Box>
        )}
      </Paper>

      {/* Paginación patrón estándar */}
      <Box
        sx={{
          display: "grid",
          gridTemplateColumns: { xs: "1fr", sm: "1fr auto 1fr" },
          alignItems: "center",
          mt: 2,
          gap: 1,
        }}
      >
        <Typography
          variant="caption"
          color="text.secondary"
          sx={{ justifySelf: { xs: "center", sm: "start" } }}
        >
          {total > 0 ? `Mostrando ${items.length} de ${total} rendiciones` : ""}
        </Typography>
        <Box sx={{ justifySelf: "center" }}>
          {total > 0 && (
            <Pagination
              count={Math.max(1, totalPages)}
              page={page}
              onChange={(_, v) => updateParams({ page: v })}
              size="small"
              color="primary"
            />
          )}
        </Box>
        <Box />
      </Box>

      <NuevaRendicionDialog open={dialogAlta} onClose={() => setDialogAlta(false)} />

      <ConfigViaticosDialog open={dialogConfig} onClose={() => setDialogConfig(false)} />

      <PDFPreviewDialog
        open={!!pdfRendicion}
        onClose={() => setPdfRendicion(null)}
        title={`Comprobante ${pdfRendicion?.numero_rendicion || ""}`}
        fetchBlob={fetchPDF}
        downloadFilename={`rendicion-viatico-${pdfRendicion?.numero_rendicion || ""}.pdf`}
      />
    </Box>
  );
}

export default RendicionViaticosPage;
