import {
  Alert,
  Autocomplete,
  Box,
  Button,
  Chip,
  CircularProgress,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  FormControl,
  InputLabel,
  MenuItem,
  Select,
  Stack,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  TextField,
  Typography,
} from "@mui/material";
import { useEffect, useMemo, useState } from "react";
import { IMaskInput } from "react-imask";
import { toast } from "sonner";
import { getCentrosCosto } from "../../../api/contabilidad.service";
import { getEmpresaMonedas } from "../../../api/monedas.service";
import {
  generarOrdenesCompraDistribuidas,
  getRequisicion,
} from "../../../api/requisiciones.service";
import { useAuthStore } from "../../../store/AuthStore";
import { formatMoney } from "../../../utils/formatMoney";
import { ProveedorSelector } from "../ProveedoresDesign/ProveedorSelector";
import { hoyISO } from "../../../utils/fecha";

const todayYmd = () => hoyISO();

const parseNumber = (value, fallback = 0) => {
  const n = Number(value);
  return Number.isFinite(n) ? n : fallback;
};

const round = (value, decimals = 4) => {
  const factor = 10 ** decimals;
  return Math.round((parseNumber(value, 0) + Number.EPSILON) * factor) / factor;
};

const formatCantidad = (value) =>
  Number(value || 0).toLocaleString("es-PY", { maximumFractionDigits: 4 });

export function CrearOCDesdeRequisicionDialog({
  open,
  requisicion,
  sucursales = [],
  onClose,
  onSuccess,
}) {
  const hasModulePlan = useAuthStore((state) => state.hasModulePlan);
  const hasContabilidadModule = hasModulePlan("CONTABILIDAD");
  const [sucursalId, setSucursalId] = useState("");
  const [monedaId, setMonedaId] = useState("");
  const [fechaEmision, setFechaEmision] = useState(todayYmd());
  const [fechaEntrega, setFechaEntrega] = useState("");
  const [observaciones, setObservaciones] = useState("");
  const [monedas, setMonedas] = useState([]);
  const [centrosCosto, setCentrosCosto] = useState([]);
  const [detalle, setDetalle] = useState(null);
  const [loadingDetalle, setLoadingDetalle] = useState(false);
  const [saving, setSaving] = useState(false);
  const [lineas, setLineas] = useState([]);

  useEffect(() => {
    if (!open) return;
    setSucursalId(requisicion?.sucursal_id || sucursales?.[0]?.id || "");
    setMonedaId("");
    setFechaEmision(todayYmd());
    setFechaEntrega("");
    setObservaciones(requisicion?.descripcion || "");
    setDetalle(null);
    setLineas([]);

    if (requisicion?.id) {
      setLoadingDetalle(true);
      getRequisicion(requisicion.id)
        .then((resp) => {
          setDetalle(resp);
          const pendientes = (resp?.requisicion_det || [])
            .map((det) => {
              const solicitada = parseNumber(det.cantidad_solicitada, 0);
              const ejecutada = parseNumber(det.cantidad_ejecutada, 0);
              return { det, pendiente: round(solicitada - ejecutada, 4) };
            })
            .filter(({ pendiente }) => pendiente > 0.0001)
            .map(({ det, pendiente }) => ({
              requisicion_det_id: det.id,
              centro_costo_id: det.centro_costo_id || det?.cont_centros_costo?.id || "",
              descripcion: det.descripcion || "Ítem",
              producto_id: det.producto_id || null,
              producto_descripcion: det.productos?.descripcion || null,
              cantidad_pendiente: pendiente,
              cantidad: pendiente,
              proveedor: null,
              precio_unitario: parseNumber(det.precio_unitario, 0),
              porcentaje_iva: parseNumber(det.porcentaje_iva, 10),
            }));
          setLineas(pendientes);
        })
        .catch(() => setDetalle(null))
        .finally(() => setLoadingDetalle(false));
    }

    getEmpresaMonedas()
      .then((data) => {
        const list = Array.isArray(data) ? data : data?.data || [];
        setMonedas(list);
        const principal = list.find((m) => m.es_principal) || list[0];
        if (principal?.moneda_id || principal?.id) {
          setMonedaId(principal.moneda_id || principal.id);
        }
      })
      .catch(() => setMonedas([]));

    if (hasContabilidadModule) {
      getCentrosCosto()
        .then((resp) => {
          const list = Array.isArray(resp) ? resp : resp?.data || [];
          setCentrosCosto(list.filter((cc) => cc?.activo !== false));
        })
        .catch(() => setCentrosCosto([]));
    } else {
      setCentrosCosto([]);
    }
  }, [open, requisicion?.id, hasContabilidadModule]);

  const updateLinea = (index, patch) => {
    setLineas((prev) => {
      const next = [...prev];
      next[index] = { ...next[index], ...patch };
      return next;
    });
  };

  const gruposPorProveedor = useMemo(() => {
    const map = new Map();
    for (const linea of lineas) {
      if (!linea.proveedor?.id) continue;
      const key = linea.proveedor.id;
      const list = map.get(key) ?? { proveedor: linea.proveedor, lineas: [] };
      list.lineas.push(linea);
      map.set(key, list);
    }
    return Array.from(map.values());
  }, [lineas]);

  const totalSinAsignar = lineas.filter((l) => !l.proveedor?.id).length;

  const canSubmit =
    !saving &&
    !!sucursalId &&
    gruposPorProveedor.length > 0 &&
    lineas
      .filter((l) => l.proveedor?.id)
      .every(
        (l) =>
          parseNumber(l.cantidad, 0) > 0 &&
          (!hasContabilidadModule || String(l.centro_costo_id || "").trim().length > 0),
      );

  const handleSubmit = async () => {
    if (!sucursalId) {
      toast.error("Seleccioná una sucursal");
      return;
    }
    const asignaciones = lineas
      .filter((l) => l.proveedor?.id)
      .map((l) => ({
        requisicion_det_id: l.requisicion_det_id,
        centro_costo_id: l.centro_costo_id || undefined,
        proveedor_id: l.proveedor.id,
        cantidad: parseNumber(l.cantidad, 0),
        precio_unitario: parseNumber(l.precio_unitario, 0),
        porcentaje_iva: parseNumber(l.porcentaje_iva, 10),
      }));
    if (!asignaciones.length) {
      toast.error("Asigná al menos una línea a un proveedor");
      return;
    }
    try {
      setSaving(true);
      const result = await generarOrdenesCompraDistribuidas(requisicion.id, {
        sucursal_id: sucursalId,
        moneda_id: monedaId || undefined,
        fecha_emision: fechaEmision || undefined,
        fecha_entrega: fechaEntrega || undefined,
        observaciones: observaciones || undefined,
        asignaciones,
      });
      onSuccess?.(result);
    } catch (error) {
      console.error(error);
      toast.error(
        error?.response?.data?.message || "No se pudo generar la(s) orden(es) de compra",
      );
    } finally {
      setSaving(false);
    }
  };

  return (
    <Dialog
      open={open}
      onClose={saving ? undefined : onClose}
      fullWidth
      maxWidth="lg"
      PaperProps={{ id: "crear-oc-req-dialog" }}
    >
      <DialogTitle>Generar órdenes de compra desde requisición</DialogTitle>
      <DialogContent dividers>
        <Stack spacing={2}>
          {requisicion?.numero_requisicion && (
            <Alert severity="info">
              Requisición {requisicion.numero_requisicion} — asigná un proveedor por línea. El
              sistema agrupará las líneas y creará una OC por proveedor en la misma transacción.
            </Alert>
          )}

          <Stack id="crear-oc-req-cabecera" direction={{ xs: "column", sm: "row" }} spacing={2}>
            <FormControl size="small" fullWidth required>
              <InputLabel>Sucursal</InputLabel>
              <Select
                value={sucursalId}
                label="Sucursal"
                onChange={(e) => setSucursalId(e.target.value)}
              >
                {sucursales.map((s) => (
                  <MenuItem key={s.id} value={s.id}>
                    {s.descripcion || s.codigo || "Sin nombre"}
                  </MenuItem>
                ))}
              </Select>
            </FormControl>

            <FormControl size="small" fullWidth>
              <InputLabel>Moneda</InputLabel>
              <Select
                value={monedaId}
                label="Moneda"
                onChange={(e) => setMonedaId(e.target.value)}
              >
                {monedas.map((m) => {
                  const id = m.moneda_id || m.id;
                  const codigo = m.moneda?.codigo || m.codigo || id;
                  return (
                    <MenuItem key={id} value={id}>
                      {codigo}
                    </MenuItem>
                  );
                })}
              </Select>
            </FormControl>
          </Stack>

          <Stack direction={{ xs: "column", sm: "row" }} spacing={2}>
            <TextField
              size="small"
              fullWidth
              type="date"
              label="Fecha emisión"
              value={fechaEmision}
              onChange={(e) => setFechaEmision(e.target.value)}
              InputLabelProps={{ shrink: true }}
            />
            <TextField
              size="small"
              fullWidth
              type="date"
              label="Fecha entrega (opcional)"
              value={fechaEntrega}
              onChange={(e) => setFechaEntrega(e.target.value)}
              InputLabelProps={{ shrink: true }}
            />
          </Stack>

          <TextField
            size="small"
            fullWidth
            multiline
            minRows={2}
            label="Observaciones"
            value={observaciones}
            onChange={(e) => setObservaciones(e.target.value)}
          />

          <Box id="crear-oc-req-items">
            <Typography variant="subtitle2" sx={{ mb: 1 }}>
              Líneas pendientes — asigná proveedor a cada una
            </Typography>
            {loadingDetalle ? (
              <Box sx={{ display: "flex", alignItems: "center", gap: 1, py: 2 }}>
                <CircularProgress size={18} />
                <Typography variant="body2" color="text.secondary">
                  Cargando líneas…
                </Typography>
              </Box>
            ) : lineas.length === 0 ? (
              <Alert severity="warning">
                La requisición no tiene líneas pendientes para generar OC.
              </Alert>
            ) : (
              <TableContainer>
                <Table size="small">
                  <TableHead>
                    <TableRow>
                      <TableCell>Descripción</TableCell>
                      <TableCell sx={{ minWidth: 240 }}>Proveedor</TableCell>
                      {hasContabilidadModule && (
                        <TableCell sx={{ minWidth: 260 }}>Centro de costo</TableCell>
                      )}
                      <TableCell align="right">Pendiente</TableCell>
                      <TableCell align="right" sx={{ width: 120 }}>
                        Cantidad
                      </TableCell>
                      <TableCell align="right" sx={{ width: 140 }}>
                        Costo unit.
                      </TableCell>
                      <TableCell align="right">Subtotal</TableCell>
                    </TableRow>
                  </TableHead>
                  <TableBody>
                    {lineas.map((linea, idx) => {
                      const subtotal = round(
                        parseNumber(linea.cantidad, 0) * parseNumber(linea.precio_unitario, 0),
                        2,
                      );
                      return (
                        <TableRow key={linea.requisicion_det_id}>
                          <TableCell>
                            <Box>
                              <Typography variant="body2">
                                {linea.descripcion}
                              </Typography>
                              {linea.producto_descripcion && (
                                <Typography variant="caption" color="text.secondary">
                                  {linea.producto_descripcion}
                                </Typography>
                              )}
                            </Box>
                          </TableCell>
                          <TableCell sx={{ minWidth: 240 }}>
                            <ProveedorSelector
                              value={linea.proveedor}
                              onChange={(prov) => updateLinea(idx, { proveedor: prov || null })}
                              label=""
                              size="small"
                              minWidth={220}
                            />
                          </TableCell>
                          {hasContabilidadModule && (
                            <TableCell sx={{ minWidth: 260 }}>
                              <Autocomplete
                                size="small"
                                options={centrosCosto}
                                value={centrosCosto.find((cc) => cc.id === linea.centro_costo_id) || null}
                                isOptionEqualToValue={(opt, val) => opt?.id === val?.id}
                                getOptionLabel={(opt) =>
                                  `${opt?.codigo ? `${opt.codigo} - ` : ""}${opt?.descripcion || ""}`
                                }
                                onChange={(_, option) =>
                                  updateLinea(idx, { centro_costo_id: option?.id || "" })
                                }
                                renderInput={(params) => (
                                  <TextField {...params} placeholder="Buscar centro" required />
                                )}
                              />
                            </TableCell>
                          )}
                          <TableCell align="right">
                            {formatCantidad(linea.cantidad_pendiente)}
                          </TableCell>
                          <TableCell align="right" sx={{ width: 120 }}>
                            <IMaskInput
                              mask={Number}
                              scale={4}
                              signed={false}
                              thousandsSeparator="."
                              radix=","
                              mapToRadix={["."]}
                              min={0}
                              max={linea.cantidad_pendiente}
                              unmask
                              value={String(linea.cantidad ?? 0)}
                              onAccept={(val) =>
                                updateLinea(idx, { cantidad: parseNumber(val, 0) })
                              }
                              style={{
                                width: "100%",
                                padding: "6px 8px",
                                textAlign: "right",
                              }}
                            />
                          </TableCell>
                          <TableCell align="right" sx={{ width: 140 }}>
                            <IMaskInput
                              mask={Number}
                              scale={0}
                              signed={false}
                              thousandsSeparator="."
                              radix=","
                              mapToRadix={["."]}
                              min={0}
                              unmask
                              value={String(linea.precio_unitario ?? 0)}
                              onAccept={(val) =>
                                updateLinea(idx, { precio_unitario: parseNumber(val, 0) })
                              }
                              style={{
                                width: "100%",
                                padding: "6px 8px",
                                textAlign: "right",
                              }}
                            />
                          </TableCell>
                          <TableCell align="right">{formatMoney(subtotal, "PYG")}</TableCell>
                        </TableRow>
                      );
                    })}
                  </TableBody>
                </Table>
              </TableContainer>
            )}
          </Box>

          {gruposPorProveedor.length > 0 && (
            <Box sx={{ display: "flex", flexWrap: "wrap", gap: 1, alignItems: "center" }}>
              <Typography variant="body2" sx={{ fontWeight: 600 }}>
                Se generarán {gruposPorProveedor.length} OC{gruposPorProveedor.length > 1 ? "s" : ""}:
              </Typography>
              {gruposPorProveedor.map((g) => (
                <Chip
                  key={g.proveedor.id}
                  size="small"
                  label={`${g.proveedor?.personas?.razon_social || g.proveedor?.razon_social || "Proveedor"} · ${g.lineas.length} línea${g.lineas.length > 1 ? "s" : ""}`}
                />
              ))}
              {totalSinAsignar > 0 && (
                <Chip
                  size="small"
                  color="warning"
                  variant="outlined"
                  label={`${totalSinAsignar} sin asignar`}
                />
              )}
            </Box>
          )}
        </Stack>
      </DialogContent>
      <DialogActions id="crear-oc-req-footer">
        <Button onClick={onClose} disabled={saving}>
          Cancelar
        </Button>
        <Button variant="contained" onClick={handleSubmit} disabled={!canSubmit}>
          {saving
            ? "Generando…"
            : `Generar OC${gruposPorProveedor.length > 1 ? "s" : ""}${gruposPorProveedor.length ? ` (${gruposPorProveedor.length})` : ""}`}
        </Button>
      </DialogActions>
    </Dialog>
  );
}

export default CrearOCDesdeRequisicionDialog;
