import { ExpandMore, Save, ShoppingCart } from "@mui/icons-material";
import {
  Accordion,
  AccordionDetails,
  AccordionSummary,
  Alert,
  Box,
  Button,
  CircularProgress,
  FormControl,
  FormControlLabel,
  InputLabel,
  MenuItem,
  Paper,
  Select,
  Stack,
  Switch,
  Typography,
} from "@mui/material";
import { Icon } from "@iconify/react";
import { RequisicionAprobacionesConfigTab } from "./RequisicionAprobacionesConfigTab";
import { ComprasMonedaDecimalesConfig } from "./ComprasMonedaDecimalesConfig";
import { useMutation, useQuery } from "@tanstack/react-query";
import { useEffect, useMemo, useState } from "react";
import { toast } from "sonner";
import {
  getConfigCompras,
  updateConfigCompras,
} from "../../api/pagos-proveedor.service";
import { useEmpresa } from "../../context/EmpresaContext";
import { usePermission } from "../../hooks/usePermission";
import { useAuthStore } from "../../store/AuthStore";
import { DIAS_MES_PAGO, DIAS_SEMANA_PAGO, PERIODICIDADES_PAGO } from "../_standards/enums";
import { AccesoRestringido } from "../common/AccesoRestringido";

const DEFAULT_CONFIG = {
  habilitar_requisicion_compra: false,
  modo_flujo_compra: "directo",
  afectar_stock_en_compra_directa: true,
  habilitar_orden_compra: true,
  habilitar_recepcion_compra: true,
  habilitar_matching_3_vias: true,
  habilitar_orden_pago: true,
  requiere_aprobacion: false,
  permite_pago_sin_aprobacion: true,
  generar_cxp_automatico: true,
  permitir_edicion_cxp: true,
  permitir_pago_parcial: false,
  usar_workflow: false,
  workflow_obligatorio: false,
  aplicar_pago_al_guardar: true,
  incluir_contado_en_orden_pago: false,
  permitir_editar_gasto_pagado: false,
  plan_pagos_periodicidad: "SEMANAL",
  plan_pagos_dia_semana: 5,
  plan_pagos_dia_mes: 31,
};

const CONFIG_GROUPS = [
  {
    key: "modo_operacion",
    title: "Modo de operación",
    description:
      "Define si la empresa compra en modo directo o con requisición, y en qué momento impacta stock.",
    fields: [
      {
        key: "habilitar_requisicion_compra",
        label: "Habilitar requisición de compra",
        helper:
          "Activa el flujo Requisición → OC/Compra/Gasto. Si está desactivado, se opera en compra directa.",
      },
      {
        key: "modo_flujo_compra",
        label: "Modo de flujo de compra",
        helper:
          "Directo: sin requisición. Requisición opcional: ambos caminos. Requisición obligatoria: OC/Compra/Gasto deben originarse en requisición aprobada.",
        type: "select",
        options: [
          { value: "directo", label: "Directo" },
          { value: "requisicion_opcional", label: "Requisición opcional" },
          { value: "requisicion_obligatoria", label: "Requisición obligatoria" },
        ],
      },
      {
        key: "afectar_stock_en_compra_directa",
        label: "Afectar stock en compra directa",
        helper:
          "Si está activo, la factura de compra directa mueve stock. Si se desactiva, el stock se mueve en Recepciones.",
      },
    ],
  },
  {
    key: "documentos_formales",
    title: "Documentos formales",
    description:
      "Controla el uso de OC, Recepciones y el matching documental OC/Recepción/Factura.",
    fields: [
      {
        key: "habilitar_orden_compra",
        label: "Habilitar orden de compra",
        helper:
          "Habilita el flujo formal con OC. Si se desactiva, las recepciones habilitadas se cargan libremente por proveedor, depósito y producto.",
      },
      {
        key: "habilitar_recepcion_compra",
        label: "Habilitar recepción de compra",
        helper:
          "Habilita registrar y anular recepciones. Con OC activa controla pendientes; sin OC permite una recepción libre.",
      },
      {
        key: "habilitar_matching_3_vias",
        label: "Matching 3 vías estricto",
        helper:
          "Exige coherencia por línea entre OC, Recepción y Factura (detalle OC, cantidad recibida y precio).",
      },
    ],
  },
  {
    key: "aprobaciones",
    title: "Aprobaciones",
    description:
      "Define cuándo OC y OP requieren aprobación y si la ejecución puede saltear o no el workflow.",
    fields: [
      {
        key: "requiere_aprobacion",
        label: "Requiere aprobación",
        helper:
          "Las órdenes nuevas (OC y OP) pasan a pendiente de aprobación antes de poder completarse/ejecutarse.",
      },
      {
        key: "usar_workflow",
        label: "Usar workflow de aprobación",
        helper:
          "Activa etapas de aprobación (enviar, aprobar, rechazar) para órdenes dentro del flujo de compras/pagos.",
      },
      {
        key: "workflow_obligatorio",
        label: "Workflow obligatorio",
        helper:
          "Fuerza usar workflow completo: afecta OC y OP al impedir saltar etapas de aprobación.",
      },
      {
        key: "permite_pago_sin_aprobacion",
        label: "Permitir pago sin aprobación",
        helper:
          "Solo impacta en OP: habilita ejecutar pago aunque la política general exija aprobación.",
      },
    ],
  },
  {
    key: "cxp_pagos",
    title: "CxP y pagos",
    description:
      "Configura cómo se generan CxP y cómo se comportan las órdenes de pago en su creación/ejecución.",
    fields: [
      {
        key: "habilitar_orden_pago",
        label: "Habilitar orden de pago",
        helper:
          "Habilita crear/ejecutar OP de proveedores. Si se desactiva, se bloquean nuevas OP.",
      },
      {
        key: "generar_cxp_automatico",
        label: "Generar CxP automático",
        helper:
          "Al registrar compra/gasto a crédito, crea CxP sin intervención manual.",
      },
      {
        key: "permitir_edicion_cxp",
        label: "Permitir edición de CxP",
        helper:
          "Permite ajustes manuales en CxP. Recomendado solo para usuarios administrativos.",
      },
      {
        key: "aplicar_pago_al_guardar",
        label: "Aplicar pago al guardar orden",
        helper:
          "Si está activo, la OP impacta saldo al guardar. Si no, queda en BORRADOR para ejecutar luego.",
      },
      {
        key: "permitir_pago_parcial",
        label: "Permitir pago parcial",
        helper:
          "Permite pagar una parte del saldo pendiente de CxP desde OP.",
      },
      {
        key: "incluir_contado_en_orden_pago",
        label: "Incluir contado en orden de pago",
        helper:
          "Si está activo, las compras/gastos de CONTADO no se auto-pagan: quedan como CxP pendiente para pagarse desde una orden de pago. Útil si centralizás todos los pagos en OP.",
      },
      {
        key: "permitir_editar_gasto_pagado",
        label: "Permitir editar gastos ya pagados",
        helper:
          "Habilita el botón de editar en gastos que figuran como PAGADA. Al guardar, el asiento contable y el movimiento de Tesorería se rehacen con los datos nuevos. No se puede editar si el movimiento ya fue conciliado con el extracto bancario: hay que deshacer la conciliación primero.",
      },
    ],
  },
  {
    key: "plan_pagos",
    title: "Plan de pagos a proveedores",
    description:
      "Cada cuánto paga la empresa a sus proveedores. Arma las columnas del plan de pagos (Compras → Plan de pagos). Lo ya programado se guarda como fecha, así que cambiar esto no lo pierde.",
    fields: [
      {
        key: "plan_pagos_periodicidad",
        label: "Periodicidad de pago",
        helper: "Semanal, quincenal (el 15 y el último día del mes) o mensual.",
        type: "select",
        options: Object.entries(PERIODICIDADES_PAGO).map(([value, p]) => ({ value, label: p.label })),
      },
      {
        key: "plan_pagos_dia_semana",
        label: "Día de pago",
        helper: "Día de la semana en que se paga a proveedores. Por ejemplo, los viernes.",
        type: "select",
        options: DIAS_SEMANA_PAGO,
      },
      {
        key: "plan_pagos_dia_mes",
        label: "Día de pago del mes",
        helper: "Ejemplo: 5 para pagar el día 5. Si el mes es más corto se paga el último día.",
        type: "select",
        options: DIAS_MES_PAGO,
      },
    ],
  },
];

const FIELD_LABELS = CONFIG_GROUPS.reduce((acc, group) => {
  for (const field of group.fields) acc[field.key] = field.label;
  return acc;
}, {});

const MODO_FLUJO_LABELS = {
  directo: "Directo",
  requisicion_opcional: "Requisición opcional",
  requisicion_obligatoria: "Requisición obligatoria",
};

const CONFIG_FIELDS = CONFIG_GROUPS.flatMap((group) => group.fields);

const normalizeConfig = (rawConfig) => {
  const next = { ...rawConfig };

  if (!next.habilitar_requisicion_compra) {
    next.modo_flujo_compra = "directo";
  }
  if (next.modo_flujo_compra === "requisicion_obligatoria") {
    next.habilitar_requisicion_compra = true;
    next.habilitar_orden_compra = true;
  }
  if (!next.habilitar_recepcion_compra || !next.habilitar_orden_compra) {
    next.habilitar_matching_3_vias = false;
  }
  if (next.workflow_obligatorio) {
    next.usar_workflow = true;
    next.requiere_aprobacion = true;
  }
  if (next.usar_workflow) {
    next.requiere_aprobacion = true;
  }
  if (!next.afectar_stock_en_compra_directa && !next.habilitar_recepcion_compra) {
    next.habilitar_orden_compra = true;
    next.habilitar_recepcion_compra = true;
  }

  return next;
};

const isFieldHidden = (key, config) => {
  if (key === "plan_pagos_dia_semana") return config.plan_pagos_periodicidad !== "SEMANAL";
  if (key === "plan_pagos_dia_mes") return config.plan_pagos_periodicidad !== "MENSUAL";
  if (key === "afectar_stock_en_compra_directa") {
    return config.modo_flujo_compra === "requisicion_obligatoria";
  }
  if (key === "habilitar_matching_3_vias") {
    return !config.habilitar_recepcion_compra || !config.habilitar_orden_compra;
  }
  if (key === "permite_pago_sin_aprobacion") {
    return !config.requiere_aprobacion && !config.usar_workflow && !config.workflow_obligatorio;
  }
  return false;
};

const getFieldDisabledReason = ({ key, config, canEdit, isPending }) => {
  if (!canEdit) {
    return "No podés modificar esta opción porque tu usuario no tiene permiso de edición en Configuración de Compras.";
  }
  if (isPending) {
    return "Esta opción está temporalmente bloqueada porque se está guardando la configuración. Cuando termine el guardado, volverá a habilitarse.";
  }

  if (key === "modo_flujo_compra") {
    return !config.habilitar_requisicion_compra
      ? "No podés cambiar el modo de flujo porque la requisición está desactivada. Primero activá «Habilitar requisición de compra» para elegir entre directo, opcional u obligatorio."
      : null;
  }
  if (key === "habilitar_requisicion_compra") {
    return config.modo_flujo_compra === "requisicion_obligatoria"
      ? "No podés desactivar requisición porque el modo actual es «Requisición obligatoria». En este modo, el sistema exige requisición aprobada como origen de OC, compra y gasto."
      : null;
  }
  if (key === "habilitar_orden_compra") {
    return config.modo_flujo_compra === "requisicion_obligatoria"
      ? "No podés desactivar Orden de Compra porque en «Requisición obligatoria» la OC forma parte del flujo requerido para mantener trazabilidad y control."
      : null;
  }
  if (key === "usar_workflow" || key === "requiere_aprobacion") {
    return config.workflow_obligatorio
      ? "No podés desactivar esta opción porque «Workflow obligatorio» está activo. Esa política fuerza el uso de aprobación en el flujo de compras y pagos."
      : null;
  }

  return null;
};

const formatFieldValue = (key, value) => {
  if (key === "modo_flujo_compra") {
    return MODO_FLUJO_LABELS[value] || value;
  }
  return value ? "activado" : "desactivado";
};

const detectAutoCorrections = (tentative, normalized, triggerKey) => {
  const corrections = [];
  for (const key of Object.keys(normalized)) {
    if (key === triggerKey) continue;
    if (tentative[key] !== normalized[key]) {
      corrections.push(
        `${FIELD_LABELS[key] || key}: ${formatFieldValue(key, normalized[key])}`,
      );
    }
  }
  return corrections;
};

const getFieldOperationalImpact = (key, config) => {
  if (key === "workflow_obligatorio" && config.workflow_obligatorio) {
    return "Impacto: OC y OP deben pasar por flujo de aprobación completo (sin saltos).";
  }
  if (key === "requiere_aprobacion" && config.requiere_aprobacion) {
    return "Impacto: OC y OP nuevas quedan en pendiente de aprobación.";
  }
  if (key === "usar_workflow" && config.usar_workflow) {
    return "Impacto: OC y OP usan estados/enlaces de enviar, aprobar y rechazar; además requieren aprobación antes de ejecutar.";
  }
  if (key === "permite_pago_sin_aprobacion" && config.permite_pago_sin_aprobacion) {
    return "Impacto: OP puede ejecutarse sin aprobación previa (excepción a la política).";
  }
  if (key === "modo_flujo_compra") {
    if (config.modo_flujo_compra === "directo") {
      return "Impacto: se permite comprar/facturar sin requisición.";
    }
    if (config.modo_flujo_compra === "requisicion_opcional") {
      return "Impacto: conviven flujo directo y flujo con requisición.";
    }
    if (config.modo_flujo_compra === "requisicion_obligatoria") {
      return "Impacto: compra, gasto y OC requieren requisición aprobada como origen.";
    }
  }
  if (key === "afectar_stock_en_compra_directa") {
    return config.afectar_stock_en_compra_directa
      ? "Impacto: compra directa afecta stock al confirmar factura."
      : "Impacto: compra directa no mueve stock; el movimiento ocurre en Recepciones.";
  }
  if (key === "habilitar_matching_3_vias" && config.habilitar_matching_3_vias) {
    return "Impacto: factura con OC valida detalle, cantidad recibida y precio por línea.";
  }
  if (key === "aplicar_pago_al_guardar") {
    return config.aplicar_pago_al_guardar
      ? "Impacto: guardar OP ya aplica el pago y actualiza saldos."
      : "Impacto: OP queda en BORRADOR hasta ejecución manual.";
  }
  return null;
};

export function ComprasConfigTab() {
  const { hasAccess, can } = usePermission("ADMINISTRACION");
  const canRead = can("ADM_CCFG_CONFIG_VER");
  const canEdit = can("ADM_CCFG_CONFIG_EDITAR");
  const { empresaId } = useEmpresa();
  // El submódulo COMP_PLAN_PAGOS puede quedar fuera del plan contratado: entonces no se configura.
  const planPagosEnPlan = useAuthStore((s) => !(s.privilegiosBloqueados || []).includes("CMP_PP_PLAN_PAGOS_VER"));
  const [config, setConfig] = useState(DEFAULT_CONFIG);
  const [baseConfig, setBaseConfig] = useState(DEFAULT_CONFIG);

  const { data, isLoading, refetch } = useQuery({
    queryKey: ["config-compras-facturacion", empresaId],
    queryFn: () => getConfigCompras(),
    enabled: Boolean(empresaId) && canRead,
    staleTime: 60 * 1000,
  });

  useEffect(() => {
    setConfig(DEFAULT_CONFIG);
    setBaseConfig(DEFAULT_CONFIG);
  }, [empresaId]);

  useEffect(() => {
    if (!data) return;
    const merged = normalizeConfig({ ...DEFAULT_CONFIG, ...data });
    setConfig(merged);
    setBaseConfig(merged);
  }, [data]);

  const mutation = useMutation({
    mutationFn: (payload) => updateConfigCompras(payload),
    onSuccess: (response) => {
      const merged = normalizeConfig({ ...DEFAULT_CONFIG, ...(response || {}) });
      setConfig(merged);
      setBaseConfig(merged);
      toast.success("Configuración de compras guardada");
      refetch();
    },
    onError: (error) => {
      toast.error(
        error?.response?.data?.message ||
          "No se pudo guardar la configuración de compras",
      );
    },
  });

  const dirtyPayload = useMemo(() => {
    const diff = {};
    for (const field of CONFIG_FIELDS) {
      const key = field.key;
      if (config[key] !== baseConfig[key]) {
        diff[key] = field.type === "select" ? config[key] : Boolean(config[key]);
      }
    }
    return diff;
  }, [config, baseConfig]);

  const changeCount = Object.keys(dirtyPayload).length;
  const hasChanges = changeCount > 0;

  const handleDiscard = () => {
    if (!hasChanges) return;
    setConfig(baseConfig);
  };

  const applyChange = (key, nextValue) => {
    setConfig((prev) => {
      const tentative = { ...prev, [key]: nextValue };
      const normalized = normalizeConfig(tentative);
      const corrections = detectAutoCorrections(tentative, normalized, key);
      if (corrections.length) {
        toast.info(`Se ajustaron campos relacionados — ${corrections.join("; ")}`);
      }
      return normalized;
    });
  };

  const handleToggle = (key) => {
    applyChange(key, !config[key]);
  };

  const handleSelectChange = (key, value) => {
    applyChange(key, value);
  };

  const handleSave = () => {
    if (!hasChanges) return;
    mutation.mutate(dirtyPayload);
  };

  if (!hasAccess || !canRead) {
    return (
      <AccesoRestringido mensaje="No tienes permisos para ver la configuración de compras." />
    );
  }

  return (
    <Paper sx={{ p: 2 }}>
      <Box sx={{ mb: 2 }}>
        <Typography variant="h6" sx={{ display: "flex", alignItems: "center", gap: 1 }}>
          <ShoppingCart fontSize="small" />
          Configuración de Compras
        </Typography>
        <Typography variant="body2" color="text.secondary">
          Definí el comportamiento operativo por apartado funcional del módulo de compras.
        </Typography>
      </Box>

      {isLoading ? (
        <Box sx={{ py: 2, display: "flex", alignItems: "center", gap: 1 }}>
          <CircularProgress size={18} />
          <Typography variant="body2" color="text.secondary">
            Cargando configuración...
          </Typography>
        </Box>
      ) : (
        <Stack spacing={2}>
          {CONFIG_GROUPS.map((group) => {
            if (group.key === "plan_pagos" && !planPagosEnPlan) return null;
            const visibleFields = group.fields.filter(
              (field) => !isFieldHidden(field.key, config),
            );
            if (!visibleFields.length) return null;

            const showStockMixtoAlert =
              group.key === "modo_operacion" &&
              config.modo_flujo_compra !== "requisicion_obligatoria" &&
              Boolean(config.habilitar_recepcion_compra) &&
              Boolean(config.afectar_stock_en_compra_directa);

            return (
              <Paper key={group.key} variant="outlined" sx={{ p: 1.5 }}>
                <Box sx={{ mb: 1.5 }}>
                  <Typography variant="subtitle1" sx={{ fontWeight: 700 }}>
                    {group.title}
                  </Typography>
                  <Typography variant="caption" color="text.secondary">
                    {group.description}
                  </Typography>
                </Box>

                {showStockMixtoAlert && (
                  <Alert severity="info" sx={{ mb: 1.5 }}>
                    Configuración mixta detectada: las compras directas impactarán stock al
                    facturar y las recepciones quedarán como constancia sin volver a moverlo.
                    Si querés centralizar el ingreso al stock en recepción, desactivá «Afectar
                    stock en compra directa».
                  </Alert>
                )}

                <Stack spacing={1}>
                  {visibleFields.map((field) => {
                    const disabledReason = getFieldDisabledReason({
                      key: field.key,
                      config,
                      canEdit,
                      isPending: mutation.isPending,
                    });
                    const isDisabled = Boolean(disabledReason);

                    const showAprobacionesAccordion =
                      group.key === "modo_operacion" &&
                      field.key === "habilitar_requisicion_compra";

                    return (
                      <Box key={field.key} sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
                        <Paper
                          variant="outlined"
                          sx={{
                            p: 1.5,
                            display: "flex",
                            justifyContent: "space-between",
                            gap: 2,
                            alignItems: "center",
                          }}
                        >
                          <Box sx={{ flex: 1 }}>
                            <Typography variant="subtitle2">{field.label}</Typography>
                            <Typography variant="caption" color="text.secondary">
                              {field.helper}
                            </Typography>
                            {getFieldOperationalImpact(field.key, config) && (
                              <Typography
                                variant="caption"
                                sx={{ display: "block", mt: 0.5, color: "info.main" }}
                              >
                                {getFieldOperationalImpact(field.key, config)}
                              </Typography>
                            )}
                            {isDisabled && (
                              <Typography
                                variant="caption"
                                color="warning.main"
                                sx={{ display: "block", mt: 0.5 }}
                              >
                                {disabledReason}
                              </Typography>
                            )}
                          </Box>
                          {field.type === "select" ? (
                            <FormControl size="small" sx={{ minWidth: 220 }}>
                              <InputLabel id={`${field.key}-label`}>Seleccionar</InputLabel>
                              <Select
                                labelId={`${field.key}-label`}
                                value={config[field.key] || ""}
                                label="Seleccionar"
                                onChange={(event) =>
                                  handleSelectChange(field.key, event.target.value)
                                }
                                disabled={isDisabled}
                              >
                                {field.options.map((option) => (
                                  <MenuItem key={option.value} value={option.value}>
                                    {option.label}
                                  </MenuItem>
                                ))}
                              </Select>
                            </FormControl>
                          ) : (
                            <FormControlLabel
                              sx={{ mr: 0 }}
                              control={
                                <Switch
                                  checked={Boolean(config[field.key])}
                                  onChange={() => handleToggle(field.key)}
                                  disabled={isDisabled}
                                />
                              }
                              label=""
                            />
                          )}
                        </Paper>

                        {showAprobacionesAccordion && (
                          <Accordion
                            disabled={!config.habilitar_requisicion_compra}
                            disableGutters
                            elevation={0}
                            sx={{
                              border: 1,
                              borderColor: "divider",
                              borderRadius: 1,
                              "&:before": { display: "none" },
                            }}
                          >
                            <AccordionSummary expandIcon={<ExpandMore />}>
                              <Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
                                <Icon icon="mdi:account-check-outline" />
                                <Box>
                                  <Typography variant="subtitle2">
                                    Niveles de aprobación de requisiciones
                                  </Typography>
                                  <Typography variant="caption" color="text.secondary">
                                    Definí los perfiles que aprueban según monto y origen.
                                  </Typography>
                                </Box>
                              </Box>
                            </AccordionSummary>
                            <AccordionDetails sx={{ pt: 0 }}>
                              <RequisicionAprobacionesConfigTab embedded />
                            </AccordionDetails>
                          </Accordion>
                        )}
                      </Box>
                    );
                  })}
                </Stack>
              </Paper>
            );
          })}

          <ComprasMonedaDecimalesConfig canEdit={canEdit} />
        </Stack>
      )}

      <Box
        sx={{
          position: "sticky",
          bottom: 0,
          mx: -2,
          mb: -2,
          mt: 2,
          px: 2,
          py: 1.25,
          bgcolor: "background.paper",
          borderTop: 1,
          borderColor: hasChanges ? "warning.light" : "divider",
          display: "flex",
          justifyContent: "space-between",
          alignItems: "center",
          gap: 2,
          flexWrap: "wrap",
          zIndex: 5,
        }}
      >
        <Typography
          variant="body2"
          sx={{ display: "flex", alignItems: "center", gap: 0.75 }}
          color={hasChanges ? "warning.main" : "text.secondary"}
        >
          <Icon
            icon={hasChanges ? "mdi:alert-circle-outline" : "mdi:check-circle-outline"}
            width={18}
          />
          {hasChanges
            ? `Tenés ${changeCount} cambio${changeCount > 1 ? "s" : ""} sin guardar`
            : "No hay cambios pendientes"}
        </Typography>
        <Stack direction="row" spacing={1}>
          <Button
            variant="text"
            color="inherit"
            onClick={handleDiscard}
            disabled={!hasChanges || mutation.isPending}
          >
            Descartar
          </Button>
          <Button
            variant="contained"
            startIcon={
              mutation.isPending ? <CircularProgress size={16} color="inherit" /> : <Save />
            }
            onClick={handleSave}
            disabled={!canEdit || !hasChanges || mutation.isPending || isLoading}
          >
            Guardar cambios
          </Button>
        </Stack>
      </Box>
    </Paper>
  );
}

export default ComprasConfigTab;
