import {
    Box,
    Button,
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
    FormControl,
    InputLabel,
    MenuItem,
    Select,
    Skeleton,
    Stack,
    Tab,
    Tabs,
    Typography,
} from "@mui/material";
import { useQuery } from "@tanstack/react-query";
import { useMemo, useState } from "react";
import { useSearchParams } from "react-router-dom";
import { toast } from "sonner";
import { getEmpresaMonedas } from "../api/monedas.service";
import { AccesoRestringido } from "../components/common/AccesoRestringido";
import {
    FieldHint,
    InlineValidationBanner,
    ScreenGuia,
} from "../components/_standards";
import { usePermission } from "../hooks/usePermission";
import { toFechaCalendarioISO } from "../utils/fecha";
import {
    AsignacionesListaDialog,
    ListasPreciosTemplate,
    ProductosListaDialog,
    useEmpresaStore,
    useListasPreciosStore,
    WizardCrearLista,
} from "../index";
import { ReglasPrecio } from "./ReglasPrecio";

const GUIA_PASOS = [
  {
    icon: "mdi:format-list-bulleted-type",
    color: "#60a5fa",
    titulo: "1. Crear lista",
    desc: "Definí código, nombre, moneda y tipo (general, cliente, zona o canal).",
  },
  {
    icon: "mdi:tag-multiple",
    color: "#34d399",
    titulo: "2. Cargar precios",
    desc: "Asigná precios a productos puntuales o aplicá un ajuste general.",
  },
  {
    icon: "mdi:account-group",
    color: "#fbbf24",
    titulo: "3. Asignar destinatarios",
    desc: "Vinculá la lista a clientes, zonas o canales según el tipo.",
  },
  {
    icon: "mdi:check-decagram",
    color: "#a78bfa",
    titulo: "4. Activar",
    desc: "Las listas activas se aplican automáticamente en el POS y facturación.",
  },
];

const GUIA_NOTAS = [
  {
    icon: "mdi:priority-high",
    text: "Cuando un cliente coincide con varias listas, se usa la de prioridad más alta (1 = mayor).",
  },
  {
    icon: "mdi:calendar-range",
    text: "Si definís fecha de inicio/fin, la lista solo se aplica dentro de ese rango.",
  },
  {
    icon: "mdi:currency-usd",
    text: "Cambiar la moneda de una lista no convierte los precios cargados; revisalos manualmente.",
  },
];

const SUBTABS = [
  { key: "listas", label: "Listas de precios", permission: "INV_LP_LISTA_VER" },
  { key: "reglas", label: "Reglas de precio", permission: "INV_RGP_REGLA_VER" },
];

export function ListasPrecios() {
  const { can } = usePermission("INVENTARIO");
  const canRead = can("INV_LP_LISTA_VER");
  const canCreate = can("INV_LP_LISTA_CREAR");
  const canEdit = can("INV_LP_LISTA_EDITAR");

  const [searchParams, setSearchParams] = useSearchParams();
  const visibleSubtabs = useMemo(
    () => SUBTABS.filter((t) => !t.permission || can(t.permission)),
    [can],
  );
  const requestedSubtab = searchParams.get("vista");
  const subtab =
    visibleSubtabs.find((t) => t.key === requestedSubtab)?.key ??
    visibleSubtabs[0]?.key ??
    "listas";
  const handleSubtabChange = (_e, newKey) => {
    const next = new URLSearchParams(searchParams);
    next.set("vista", newKey);
    setSearchParams(next, { replace: true });
  };

  const [mostrarWizard, setMostrarWizard] = useState(false);
  const [mostrarEditarLista, setMostrarEditarLista] = useState(false);
  const [listaEdicion, setListaEdicion] = useState(null);
  const [datosEdicion, setDatosEdicion] = useState({
    codigo: "",
    nombre: "",
    descripcion: "",
    tipoAplicacion: "general",
    prioridad: 1,
    fechaInicio: "",
    fechaFin: "",
  });
  const [erroresEdicion, setErroresEdicion] = useState([]);
  const [mostrarCambioMoneda, setMostrarCambioMoneda] = useState(false);
  const [listaMonedaSeleccionada, setListaMonedaSeleccionada] = useState(null);
  const [monedaSeleccionada, setMonedaSeleccionada] = useState("");
  const [mostrarAsignaciones, setMostrarAsignaciones] = useState(false);
  const [listaAsignaciones, setListaAsignaciones] = useState(null);
  const [mostrarProductos, setMostrarProductos] = useState(false);
  const [listaProductos, setListaProductos] = useState(null);
  const { dataempresa } = useEmpresaStore();
  const {
    mostrarListasPrecios,
    buscarListasPrecios,
    filtros,
    setFiltros,
    buscador,
    setBuscador,
    page,
    limit,
    total,
    totalPages,
    setPage,
    setLimit,
    insertarListaPrecios,
    actualizarPreciosProductosLista,
    editarListaPrecios,
    duplicarListaPrecios,
    cambiarEstadoListaPrecios,
    cambiarMonedaListaPrecios,
    loading,
    error,
  } = useListasPreciosStore();

  const {
    data: listasResponse,
    isLoading: isLoadingListas,
    refetch: refetchListas,
  } = useQuery({
    queryKey: ["mostrar listas precios", dataempresa?.id, filtros, page, limit],
    queryFn: () =>
      mostrarListasPrecios({ id_empresa: dataempresa?.id, page, limit }),
    enabled: !buscador,
    refetchOnWindowFocus: false,
  });

  const {
    data: listasBusqueda,
    isLoading: isLoadingBuscar,
    refetch: refetchBuscar,
  } = useQuery({
    queryKey: [
      "buscar listas precios",
      dataempresa?.id,
      buscador,
      filtros,
      page,
      limit,
    ],
    queryFn: () =>
      buscarListasPrecios({ id_empresa: dataempresa?.id, page, limit }),
    enabled: !!buscador,
    refetchOnWindowFocus: false,
  });

  const { data: monedasDisponibles, isLoading: isLoadingMonedas } = useQuery({
    queryKey: ["empresa-monedas"],
    queryFn: getEmpresaMonedas,
    refetchOnWindowFocus: false,
  });

  const isLoading =
    isLoadingListas || isLoadingBuscar || isLoadingMonedas || loading;
  const errorState = error;

  const handleFiltrosChange = (nuevosFiltros) => {
    setFiltros(nuevosFiltros);
    if (nuevosFiltros.buscador !== filtros.buscador) {
      setBuscador(nuevosFiltros.buscador || "");
    }
    setPage(1);
  };

  const handleCrearLista = () => {
    setMostrarWizard(true);
  };

  const handleCerrarWizard = () => {
    setMostrarWizard(false);
  };

  const handleSubmitWizard = async (datosLista) => {
    if (!datosLista.codigo?.trim() || !datosLista.nombre?.trim()) {
      toast.error("Completa el código y el nombre de la lista");
      return;
    }

    if (datosLista.tipoAjuste === "monto") {
      toast.error("Por ahora solo se admite ajuste por porcentaje");
      return;
    }

    const valorAjuste = Math.max(0, Number(datosLista.valorAjuste) || 0);
    const aplicaDescuento = datosLista.esDescuento && valorAjuste > 0;
    const aplicaRecargo = !datosLista.esDescuento && valorAjuste > 0;

    const payload = {
      codigo: datosLista.codigo.trim(),
      nombre: datosLista.nombre.trim(),
      descripcion: datosLista.descripcion?.trim() || undefined,
      tipoAplicacion: datosLista.tipo,
      moneda: datosLista.moneda,
      prioridad: datosLista.prioridad,
      fechaInicio: toFechaCalendarioISO(datosLista.fechaInicio) || undefined,
      fechaFin: toFechaCalendarioISO(datosLista.fechaFin) || undefined,
      aplicaDescuentoGeneral: aplicaDescuento,
      descuentoPorcentaje: aplicaDescuento ? valorAjuste : 0,
      aplicaRecargoGeneral: aplicaRecargo,
      recargoPorcentaje: aplicaRecargo ? valorAjuste : 0,
    };

    try {
      const response = await insertarListaPrecios(payload);
      const nuevaListaId =
        response?.data?.id || response?.data?.data?.id || response?.id;

      if (
        !datosLista.aplicarATodos &&
        datosLista.productosSeleccionados.length > 0 &&
        nuevaListaId
      ) {
        const productosPayload = datosLista.productosSeleccionados.map(
          (producto) => ({
            productoId: producto.id,
            precioBase: Number(producto.precio) || 0,
            descuentoPorcentaje: aplicaDescuento ? valorAjuste : 0,
            recargoPorcentaje: aplicaRecargo ? valorAjuste : 0,
          }),
        );
        await actualizarPreciosProductosLista(nuevaListaId, productosPayload);
      }
      toast.success("Lista de precios creada correctamente");
      setMostrarWizard(false);
      await (buscador ? refetchBuscar() : refetchListas());
    } catch (error) {
      toast.error(
        error?.response?.data?.message || "Error al crear la lista de precios",
      );
    }
  };

  const handleEditarLista = (lista) => {
    setListaEdicion(lista);
    setDatosEdicion({
      codigo: lista?.codigo || "",
      nombre: lista?.nombre || "",
      descripcion: lista?.descripcion || "",
      tipoAplicacion: lista?.tipo_aplicacion || "general",
      prioridad: lista?.prioridad || 1,
      fechaInicio: toFechaCalendarioISO(lista?.fecha_inicio) || "",
      fechaFin: toFechaCalendarioISO(lista?.fecha_fin) || "",
    });
    setErroresEdicion([]);
    setMostrarEditarLista(true);
  };

  const handleCerrarEditar = () => {
    setMostrarEditarLista(false);
    setListaEdicion(null);
    setErroresEdicion([]);
  };

  const validarEdicion = () => {
    const errs = [];
    if (!datosEdicion.codigo.trim()) {
      errs.push({ campo: "Código", mensaje: "es obligatorio", anchorId: "edit-lp-codigo" });
    }
    if (!datosEdicion.nombre.trim()) {
      errs.push({ campo: "Nombre", mensaje: "es obligatorio", anchorId: "edit-lp-nombre" });
    }
    if (
      datosEdicion.fechaFin &&
      datosEdicion.fechaInicio &&
      datosEdicion.fechaFin < datosEdicion.fechaInicio
    ) {
      errs.push({
        campo: "Fecha de fin",
        mensaje: "no puede ser menor a la fecha de inicio",
        anchorId: "edit-lp-fecha-fin",
      });
    }
    return errs;
  };

  const handleGuardarEdicion = async () => {
    if (!listaEdicion?.id) {
      return;
    }

    const errs = validarEdicion();
    if (errs.length > 0) {
      setErroresEdicion(errs);
      return;
    }
    setErroresEdicion([]);

    const payload = {
      codigo: datosEdicion.codigo.trim(),
      nombre: datosEdicion.nombre.trim(),
      descripcion: datosEdicion.descripcion?.trim() || undefined,
      tipoAplicacion: datosEdicion.tipoAplicacion,
      prioridad: Number(datosEdicion.prioridad) || 1,
      fechaInicio: toFechaCalendarioISO(datosEdicion.fechaInicio) || undefined,
      fechaFin: toFechaCalendarioISO(datosEdicion.fechaFin) || undefined,
    };

    try {
      await editarListaPrecios(listaEdicion.id, payload);
      toast.success("Lista actualizada correctamente");
      setMostrarEditarLista(false);
      await (buscador ? refetchBuscar() : refetchListas());
    } catch (error) {
      toast.error(
        error?.response?.data?.message || "Error al actualizar la lista",
      );
    }
  };

  const handleDuplicarLista = async (lista) => {
    try {
      const nuevosDatos = {
        codigo: `${lista.codigo}_COPY`,
        nombre: `${lista.nombre} (Copia)`,
        descripcion: `Copia de: ${lista.descripcion || lista.nombre}`,
        moneda: lista.moneda,
      };

      await duplicarListaPrecios(lista.id, nuevosDatos);
      toast.success("Lista duplicada correctamente");
      await (buscador ? refetchBuscar() : refetchListas());
    } catch (error) {
      toast.error(
        error?.response?.data?.message || "Error al duplicar la lista",
      );
    }
  };

  const handleCambiarEstado = async (listaId, nuevoEstado) => {
    try {
      await cambiarEstadoListaPrecios(listaId, nuevoEstado);
      toast.success(nuevoEstado ? "Lista activada" : "Lista desactivada");
      await (buscador ? refetchBuscar() : refetchListas());
    } catch (error) {
      toast.error(
        error?.response?.data?.message || "Error al cambiar el estado",
      );
    }
  };

  const handleVerProductos = (lista) => {
    setListaProductos(lista);
    setMostrarProductos(true);
  };

  const handleCerrarProductos = () => {
    setMostrarProductos(false);
    setListaProductos(null);
  };

  const handleCambiarMoneda = (listaId, monedaActual) => {
    const listaActual = (listas || []).find((item) => item.id === listaId);
    setListaMonedaSeleccionada(
      listaActual || { id: listaId, nombre: "Lista", moneda: monedaActual },
    );
    setMonedaSeleccionada(monedaActual || "");
    setMostrarCambioMoneda(true);
  };

  const handleAbrirAsignaciones = (lista) => {
    setListaAsignaciones(lista);
    setMostrarAsignaciones(true);
  };

  const handleCerrarAsignaciones = () => {
    setMostrarAsignaciones(false);
    setListaAsignaciones(null);
  };

  const handleCerrarCambioMoneda = () => {
    setMostrarCambioMoneda(false);
    setListaMonedaSeleccionada(null);
    setMonedaSeleccionada("");
  };

  const handleConfirmarCambioMoneda = async () => {
    if (!listaMonedaSeleccionada?.id) {
      return;
    }

    if (!monedaSeleccionada) {
      toast.error("Selecciona una moneda válida");
      return;
    }

    if (monedaSeleccionada === listaMonedaSeleccionada.moneda) {
      toast.info("La lista ya usa esa moneda");
      return;
    }

    try {
      await cambiarMonedaListaPrecios(
        listaMonedaSeleccionada.id,
        monedaSeleccionada,
      );
      toast.success("Moneda actualizada correctamente");
      setMostrarCambioMoneda(false);
      await (buscador ? refetchBuscar() : refetchListas());
    } catch (error) {
      toast.error(
        error?.response?.data?.message || "Error al cambiar la moneda",
      );
    }
  };

  const monedasNormalizadas = useMemo(
    () =>
      (monedasDisponibles || [])
        .map((item) => {
          const moneda = item?.moneda || item;
          const codigo = moneda?.codigo || item?.codigo;
          if (!codigo) return null;
          return {
            codigo,
            descripcion: moneda?.descripcion || moneda?.nombre || codigo,
          };
        })
        .filter(Boolean),
    [monedasDisponibles],
  );
  const monedasCodigos = useMemo(
    () =>
      Array.from(
        new Map(
          monedasNormalizadas.map((moneda) => [moneda.codigo, moneda]),
        ).values(),
      ).map((moneda) => moneda.codigo),
    [monedasNormalizadas],
  );

  if (visibleSubtabs.length === 0) {
    return (
      <AccesoRestringido mensaje="No tienes permisos para ver las listas o reglas de precio." />
    );
  }

  const subtabsNav = visibleSubtabs.length > 1 && (
    <Tabs
      value={subtab}
      onChange={handleSubtabChange}
      sx={{ borderBottom: 1, borderColor: "divider", mb: 2 }}
    >
      {visibleSubtabs.map((t) => (
        <Tab key={t.key} value={t.key} label={t.label} />
      ))}
    </Tabs>
  );

  if (subtab === "reglas") {
    return (
      <>
        {subtabsNav}
        <ReglasPrecio />
      </>
    );
  }

  if (!canRead) {
    return (
      <>
        {subtabsNav}
        <AccesoRestringido mensaje="No tienes permisos para ver las listas de precios." />
      </>
    );
  }

  const guia = (
    <Box sx={{ mb: 2 }}>
      <ScreenGuia
        moduloPadre="Inventario"
        titulo="Listas de precios"
        intro="Gestioná esquemas de precios diferenciados por cliente, zona o canal, con vigencia y prioridad."
        pasos={GUIA_PASOS}
        notas={GUIA_NOTAS}
      />
    </Box>
  );

  if (isLoading && !listasResponse && !listasBusqueda) {
    return (
      <>
        {subtabsNav}
        {guia}
        <Stack spacing={1}>
          <Skeleton variant="rounded" height={56} />
          <Skeleton variant="rounded" height={120} />
          <Skeleton variant="rounded" height={120} />
          <Skeleton variant="rounded" height={120} />
        </Stack>
      </>
    );
  }

  if (errorState) {
    return (
      <>
        {subtabsNav}
        {guia}
        <Typography color="error">Error: {errorState}</Typography>
      </>
    );
  }

  const listasPayload = buscador ? listasBusqueda : listasResponse;
  const listas = listasPayload?.data || [];
  const totalRegistros = Number.isFinite(listasPayload?.total)
    ? listasPayload.total
    : total;
  const totalPaginas = listasPayload?.totalPages ?? totalPages;
  const paginaActual = listasPayload?.page ?? page;
  const limiteActual = listasPayload?.limit ?? limit;

  const handlePageChange = (nuevaPagina) => {
    if (nuevaPagina === paginaActual) {
      return;
    }
    setPage(nuevaPagina);
  };

  const handleLimitChange = (nuevoLimite) => {
    if (nuevoLimite === limiteActual) {
      return;
    }
    setLimit(nuevoLimite);
    setPage(1);
  };

  return (
    <>
      {subtabsNav}
      {guia}
      <ListasPreciosTemplate
        listas={listas}
        monedasDisponibles={monedasCodigos}
        filtros={filtros}
        onFiltrosChange={handleFiltrosChange}
        onCrearLista={canCreate ? handleCrearLista : null}
        onEditarLista={canEdit ? handleEditarLista : null}
        onDuplicarLista={canCreate ? handleDuplicarLista : null}
        onCambiarEstado={canEdit ? handleCambiarEstado : null}
        onVerProductos={handleVerProductos}
        onManageAssignments={canEdit ? handleAbrirAsignaciones : null}
        onCambiarMoneda={canEdit ? handleCambiarMoneda : null}
        page={paginaActual}
        limit={limiteActual}
        total={totalRegistros}
        totalPages={totalPaginas}
        onPageChange={handlePageChange}
        onLimitChange={handleLimitChange}
        loading={isLoading}
      />
      <WizardCrearLista
        isOpen={mostrarWizard}
        onClose={handleCerrarWizard}
        onSubmit={handleSubmitWizard}
        monedasDisponibles={monedasNormalizadas}
        loading={loading}
      />
      <Dialog
        open={mostrarEditarLista}
        onClose={handleCerrarEditar}
        maxWidth="sm"
        fullWidth
      >
        <DialogTitle>Editar lista de precios</DialogTitle>
        <DialogContent>
          <Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
            Ajusta los datos principales. Para cambiar la moneda utiliza el
            botón de moneda en la tarjeta de la lista.
          </Typography>
          {erroresEdicion.length > 0 && (
            <Box sx={{ mb: 2 }}>
              <InlineValidationBanner errors={erroresEdicion} />
            </Box>
          )}
          <Box sx={{ display: "grid", gap: 2 }}>
            <FieldHint
              id="edit-lp-codigo"
              label="Código *"
              value={datosEdicion.codigo}
              onChange={(event) =>
                setDatosEdicion((prev) => ({
                  ...prev,
                  codigo: event.target.value,
                }))
              }
              hint="Ej: LP001"
              fullWidth
            />
            <FieldHint
              id="edit-lp-nombre"
              label="Nombre *"
              value={datosEdicion.nombre}
              onChange={(event) =>
                setDatosEdicion((prev) => ({
                  ...prev,
                  nombre: event.target.value,
                }))
              }
              hint="Ej: Lista Mayorista"
              fullWidth
            />
            <FieldHint
              label="Descripción"
              value={datosEdicion.descripcion}
              onChange={(event) =>
                setDatosEdicion((prev) => ({
                  ...prev,
                  descripcion: event.target.value,
                }))
              }
              hint="Describe el uso de esta lista"
              multiline
              rows={3}
              fullWidth
            />
            <FormControl fullWidth size="small">
              <InputLabel>Tipo de lista</InputLabel>
              <Select
                label="Tipo de lista"
                value={datosEdicion.tipoAplicacion}
                onChange={(event) =>
                  setDatosEdicion((prev) => ({
                    ...prev,
                    tipoAplicacion: event.target.value,
                  }))
                }
              >
                <MenuItem value="general">General</MenuItem>
                <MenuItem value="cliente">Por Cliente</MenuItem>
                <MenuItem value="zona">Por Zona</MenuItem>
                <MenuItem value="canal">Por Canal</MenuItem>
              </Select>
            </FormControl>
            <FieldHint
              label="Prioridad"
              type="number"
              inputProps={{ min: 1, max: 10 }}
              value={datosEdicion.prioridad}
              onChange={(event) =>
                setDatosEdicion((prev) => ({
                  ...prev,
                  prioridad: event.target.value,
                }))
              }
              hint="1 es la prioridad más alta"
              fullWidth
            />
            <Box
              sx={{ display: "grid", gap: 2, gridTemplateColumns: "1fr 1fr" }}
            >
              <FieldHint
                label="Fecha de inicio"
                type="date"
                value={datosEdicion.fechaInicio}
                onChange={(event) =>
                  setDatosEdicion((prev) => ({
                    ...prev,
                    fechaInicio: event.target.value,
                  }))
                }
                InputLabelProps={{ shrink: true }}
                fullWidth
              />
              <FieldHint
                id="edit-lp-fecha-fin"
                label="Fecha de fin"
                type="date"
                value={datosEdicion.fechaFin}
                onChange={(event) =>
                  setDatosEdicion((prev) => ({
                    ...prev,
                    fechaFin: event.target.value,
                  }))
                }
                InputLabelProps={{ shrink: true }}
                fullWidth
              />
            </Box>
          </Box>
        </DialogContent>
        <DialogActions sx={{ px: 3, pb: 2 }}>
          <Button onClick={handleCerrarEditar} variant="outlined">
            Cancelar
          </Button>
          <Button
            onClick={handleGuardarEdicion}
            variant="contained"
            disabled={loading}
          >
            {loading ? "Guardando..." : "Guardar cambios"}
          </Button>
        </DialogActions>
      </Dialog>
      <Dialog
        open={mostrarCambioMoneda}
        onClose={handleCerrarCambioMoneda}
        maxWidth="xs"
        fullWidth
      >
        <DialogTitle>Cambiar moneda de la lista</DialogTitle>
        <DialogContent sx={{ pt: 1 }}>
          <Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
            Selecciona la moneda base en la que se expresarán los precios de
            esta lista. Útil cuando necesitas mantener listas en monedas
            diferentes para clientes internacionales.
          </Typography>
          <Typography variant="subtitle2" sx={{ mb: 1 }}>
            Lista: {listaMonedaSeleccionada?.nombre || "-"}
          </Typography>
          <FormControl fullWidth size="small">
            <InputLabel>Moneda</InputLabel>
            <Select
              value={monedaSeleccionada}
              label="Moneda"
              onChange={(event) => setMonedaSeleccionada(event.target.value)}
            >
              {monedasCodigos.length === 0 ? (
                <MenuItem value="PYG">PYG</MenuItem>
              ) : (
                monedasCodigos.map((moneda) => (
                  <MenuItem key={moneda} value={moneda}>
                    {moneda}
                  </MenuItem>
                ))
              )}
            </Select>
          </FormControl>
        </DialogContent>
        <DialogActions sx={{ px: 3, pb: 2 }}>
          <Button onClick={handleCerrarCambioMoneda} variant="outlined">
            Cancelar
          </Button>
          <Button
            onClick={handleConfirmarCambioMoneda}
            variant="contained"
            disabled={loading}
          >
            {loading ? "Actualizando..." : "Confirmar"}
          </Button>
        </DialogActions>
      </Dialog>
      <AsignacionesListaDialog
        open={mostrarAsignaciones}
        onClose={handleCerrarAsignaciones}
        lista={listaAsignaciones}
      />
      <ProductosListaDialog
        open={mostrarProductos}
        onClose={handleCerrarProductos}
        lista={listaProductos}
      />
    </>
  );
}
