import { Icon } from "@iconify/react";
import {
  Alert,
  Box,
  Button,
  CircularProgress,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  Divider,
  Paper,
  Stack,
  Typography,
} from "@mui/material";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useNavigate } from "react-router-dom";
import { toast } from "sonner";
import {
  actualizarConsumoFuncionarioConfig,
  cambiarExclusionFacturaConsumo,
  getConsumoFuncionarioConfig,
  getFacturasExcluidasConsumo,
  vincularFichasFuncionarios,
} from "../../api/rrhh.service";
import { fmtFechaCalendario } from "../../utils/fecha";
import { MonedaInput, PrereqChecklist, SwitchConAyuda } from "../_standards";
import { fmtMoneda } from "../_standards/enums/monedas";

// Por qué no se puede contabilizar el descuento, según lo que devuelve el backend.
const PROBLEMA_CUENTA_PUENTE = {
  SIN_MAPEO: "todavía no está mapeada",
  CUENTA_INACTIVA: "está mapeada a una cuenta dada de baja",
  CUENTA_NO_IMPUTABLE: "está mapeada a una cuenta de agrupación, que no acepta movimientos",
};

const RUTA_MAPEO_CUENTAS = "/contabilidad?tab=mapeo";

const formDesde = (cfg) => ({
  habilitado: Boolean(cfg?.habilitado),
  crear_cliente: Boolean(cfg?.crear_cliente),
  tope_mensual: Number(cfg?.tope_mensual ?? 0),
});

/**
 * RRHH → Configuración → Consumo de funcionarios.
 *
 * Activa el cobro por planilla de lo que los funcionarios compran en la
 * empresa. Muestra arriba los requisitos porque, si falta alguno, el switch
 * queda prendido pero no pasa nada: sin ficha de cliente no hay facturas que
 * proponer, y sin cuenta puente el recibo del cierre no se contabiliza.
 */
export function ConsumoFuncionarioTab() {
  const navigate = useNavigate();
  const [config, setConfig] = useState(null);
  const [form, setForm] = useState(formDesde(null));
  const [loading, setLoading] = useState(true);
  const [guardando, setGuardando] = useState(false);
  const [dialogoVincular, setDialogoVincular] = useState(false);
  const [crearFichas, setCrearFichas] = useState(false);
  const [vinculando, setVinculando] = useState(false);
  const [excluidas, setExcluidas] = useState([]);
  const [reincluyendo, setReincluyendo] = useState(null);

  const cargar = useCallback(async () => {
    setLoading(true);
    try {
      const [data, ex] = await Promise.all([getConsumoFuncionarioConfig(), getFacturasExcluidasConsumo()]);
      setConfig(data);
      setForm(formDesde(data));
      setExcluidas(ex);
    } catch (error) {
      toast.error(error?.response?.data?.message || "No se pudo cargar la configuración");
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    cargar();
  }, [cargar]);

  const req = config?.requisitos;
  const sinFicha = req?.empleados_sin_ficha ?? 0;
  const activos = req?.empleados_activos ?? 0;

  const cambios = useMemo(() => {
    const original = formDesde(config);
    return Object.fromEntries(Object.entries(form).filter(([k, v]) => original[k] !== v));
  }, [config, form]);
  const hayCambios = Object.keys(cambios).length > 0;

  const guardar = async () => {
    setGuardando(true);
    try {
      const data = await actualizarConsumoFuncionarioConfig(cambios);
      setConfig(data);
      setForm(formDesde(data));
      toast.success(
        cambios.habilitado === true
          ? "Consumo de funcionarios activado. La próxima liquidación propone las facturas pendientes."
          : "Configuración guardada",
      );
    } catch (error) {
      toast.error(error?.response?.data?.message || "No se pudo guardar", {
        action: { label: "Reintentar", onClick: guardar },
      });
    } finally {
      setGuardando(false);
    }
  };

  const vincular = async () => {
    setVinculando(true);
    try {
      const r = await vincularFichasFuncionarios({ crear: crearFichas });
      setConfig((prev) => ({ ...prev, requisitos: r.requisitos }));
      setDialogoVincular(false);
      const detalle = r.salteados ? ` · ${r.salteados} sin vincular` : "";
      toast.success(`${r.vinculados} funcionarios vinculados${detalle}`);
    } catch (error) {
      toast.error(error?.response?.data?.message || "No se pudieron vincular las fichas");
    } finally {
      setVinculando(false);
    }
  };

  const reincluir = async (f) => {
    setReincluyendo(f.cuenta_cobrar_id);
    try {
      await cambiarExclusionFacturaConsumo(f.cuenta_cobrar_id, false);
      setExcluidas((prev) => prev.filter((x) => x.cuenta_cobrar_id !== f.cuenta_cobrar_id));
      toast.success(`La factura ${f.numero ?? ""} se vuelve a proponer en la próxima liquidación`);
    } catch (error) {
      toast.error(error?.response?.data?.message || "No se pudo volver a incluir");
    } finally {
      setReincluyendo(null);
    }
  };

  if (loading) {
    return (
      <Box sx={{ display: "flex", justifyContent: "center", py: 6 }}>
        <CircularProgress size={28} />
      </Box>
    );
  }

  if (!config) {
    return (
      <Alert severity="error" action={<Button onClick={cargar}>Reintentar</Button>}>
        No se pudo cargar la configuración del consumo de funcionarios.
      </Alert>
    );
  }

  const cuenta = req.cuenta_puente;
  const conceptoOk = req.concepto.existe && req.concepto.activo;
  const requisitos = [
    {
      key: "concepto",
      label: "Concepto de liquidación «Consumo de funcionario»",
      ok: conceptoOk,
      hint: conceptoOk
        ? null
        : req.concepto.existe
          ? "está desactivado: activalo en Conceptos de liquidación"
          : "se crea solo al activar el consumo de funcionarios",
    },
    {
      key: "cuenta",
      label: cuenta.ok
        ? `Cuenta puente contable: ${cuenta.codigo} ${cuenta.descripcion ?? ""}`
        : "Cuenta puente contable (CONSUMO_FUNCIONARIO_PUENTE)",
      ok: cuenta.ok,
      hint: cuenta.ok
        ? null
        : `${PROBLEMA_CUENTA_PUENTE[cuenta.problema] ?? "no está lista"}. Sin ella el descuento no se contabiliza al cerrar la liquidación.`,
      ctaLabel: "Mapear cuenta",
      onGoTo: () => navigate(RUTA_MAPEO_CUENTAS),
    },
    {
      key: "fichas",
      label: `Funcionarios con ficha de cliente: ${activos - sinFicha} de ${activos}`,
      ok: sinFicha === 0,
      hint: sinFicha ? "a los que no tienen ficha no se les pueden proponer facturas" : null,
      ctaLabel: "Vincular fichas",
      onGoTo: () => setDialogoVincular(true),
    },
  ];

  return (
    <Stack spacing={2} sx={{ maxWidth: 880 }}>
      <Alert severity="info" icon={<Icon icon="lucide:shopping-bag" width={20} />}>
        Para empresas que venden a sus funcionarios y se lo cobran por planilla. Se le factura al
        funcionario como a cualquier cliente, con cobro diferido; en la liquidación del mes siguiente se
        proponen sus facturas pendientes como descuento, y al cerrarla se emite el recibo que las cancela.
        RRHH puede quitar cualquier línea antes de cerrar.
      </Alert>

      <PrereqChecklist title="Requisitos" items={requisitos} collapseWhenDone />

      <Paper variant="outlined" sx={{ p: 2 }}>
        <Typography variant="subtitle2" fontWeight={600} sx={{ mb: 1 }}>
          Opciones
        </Typography>
        <Stack spacing={1.5}>
          <SwitchConAyuda
            checked={form.habilitado}
            onChange={(v) => setForm((f) => ({ ...f, habilitado: v }))}
            label="Activar consumo de funcionarios"
            ayuda="La liquidación propone como descuento las facturas pendientes de cada funcionario. Si se apaga, deja de proponerlas; lo ya descontado no cambia."
          />
          {form.habilitado && !cuenta.ok && (
            <Alert severity="warning" sx={{ ml: 1 }}>
              Se puede activar, pero mientras la cuenta puente no esté lista los recibos del cierre no se van
              a contabilizar.
            </Alert>
          )}
          <SwitchConAyuda
            checked={form.crear_cliente}
            onChange={(v) => setForm((f) => ({ ...f, crear_cliente: v }))}
            label="Crear la ficha de cliente al dar de alta un funcionario"
            ayuda="Si el funcionario ya es cliente se usa su ficha existente (se busca por cédula). Apagado, la ficha se vincula a mano desde «Vincular fichas». Con muchos funcionarios que no compran, llena el padrón de clientes."
          />
          <Box sx={{ ml: 1, maxWidth: 320 }}>
            <MonedaInput
              label="Tope mensual por funcionario"
              fullWidth
              value={form.tope_mensual}
              onChange={(v) => setForm((f) => ({ ...f, tope_mensual: Number(v) || 0 }))}
              helperText="0 = sin tope. Ej: 500.000. El tope legal del 30% del salario se aplica siempre."
            />
          </Box>
        </Stack>
        <Box sx={{ display: "flex", justifyContent: "flex-end", gap: 1, mt: 2 }}>
          <Button disabled={!hayCambios || guardando} onClick={() => setForm(formDesde(config))}>
            Descartar
          </Button>
          <Button
            variant="contained"
            disabled={!hayCambios || guardando}
            onClick={guardar}
            startIcon={guardando ? <CircularProgress size={16} color="inherit" /> : <Icon icon="mdi:content-save" />}
          >
            Guardar
          </Button>
        </Box>
      </Paper>

      <Paper variant="outlined" sx={{ p: 2 }}>
        <Typography variant="subtitle2" fontWeight={600}>
          Facturas que no se descuentan por planilla
        </Typography>
        <Typography variant="caption" color="text.secondary" component="p" sx={{ mb: 1.5 }}>
          Se excluyen desde la liquidación, al quitar la línea con «No volver a proponerla». Siguen pendientes en
          Cuentas por cobrar.
        </Typography>
        {excluidas.length === 0 ? (
          <Typography variant="body2" color="text.secondary">
            Ninguna: todas las facturas pendientes de los funcionarios se proponen como descuento.
          </Typography>
        ) : (
          <Stack divider={<Divider flexItem />} spacing={1}>
            {excluidas.map((f) => (
              <Box
                key={f.cuenta_cobrar_id}
                sx={{ display: "flex", alignItems: "center", gap: 1.5, flexWrap: "wrap" }}
              >
                <Box sx={{ flex: "1 1 240px", minWidth: 0 }}>
                  <Typography variant="body2" fontWeight={500}>
                    {f.empleado ?? "—"}
                  </Typography>
                  <Typography variant="caption" color="text.secondary">
                    Factura {f.numero ?? "—"}
                    {f.fecha_emision ? ` · ${fmtFechaCalendario(f.fecha_emision)}` : ""} · saldo{" "}
                    {fmtMoneda(f.saldo_pendiente)}
                  </Typography>
                </Box>
                <Button
                  size="small"
                  onClick={() => reincluir(f)}
                  disabled={reincluyendo === f.cuenta_cobrar_id}
                  startIcon={
                    reincluyendo === f.cuenta_cobrar_id ? (
                      <CircularProgress size={14} color="inherit" />
                    ) : (
                      <Icon icon="mdi:undo-variant" />
                    )
                  }
                  sx={{ flexShrink: 0, ml: "auto" }}
                >
                  Volver a incluir
                </Button>
              </Box>
            ))}
          </Stack>
        )}
      </Paper>

      <Dialog open={dialogoVincular} onClose={() => !vinculando && setDialogoVincular(false)} maxWidth="sm" fullWidth>
        <DialogTitle>Vincular funcionarios con su ficha de cliente</DialogTitle>
        <DialogContent>
          <Typography variant="body2" sx={{ mb: 2 }}>
            Se busca la ficha de cada funcionario activo sin vincular ({sinFicha}) por su número de cédula. Los
            que tienen cédula de prueba o vacía se saltean.
          </Typography>
          <SwitchConAyuda
            checked={crearFichas}
            onChange={setCrearFichas}
            label="Crear ficha para los que todavía no son clientes"
            ayuda="Apagado, solo se vinculan los que ya tienen ficha. Encendido, a los demás se les crea una nueva con sus datos."
          />
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setDialogoVincular(false)} disabled={vinculando}>
            Cancelar
          </Button>
          <Button
            variant="contained"
            onClick={vincular}
            disabled={vinculando}
            startIcon={vinculando ? <CircularProgress size={16} color="inherit" /> : <Icon icon="mdi:link-variant" />}
          >
            Vincular
          </Button>
        </DialogActions>
      </Dialog>
    </Stack>
  );
}
