import { Icon } from "@iconify/react";
import {
  Alert,
  Box,
  Button,
  Chip,
  CircularProgress,
  Collapse,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  Divider,
  Grid,
  IconButton,
  InputAdornment,
  Link as MuiLink,
  MenuItem,
  Paper,
  Stack,
  TextField,
  ToggleButton,
  ToggleButtonGroup,
  Tooltip,
  Typography,
} from "@mui/material";
import { useEffect, useState } from "react";
import QRCode from "qrcode";
import { toast } from "sonner";
import { EmptyState, FieldHint, MonedaInput, TablePaginationBar } from "../../_standards";
import {
  useCobroSyncPolling,
  useCrearNovasisPayCobroMutation,
  useNovasisPayConfigQuery,
  useNovasisPayCobrosQuery,
  useNovasisPayPaymentMethodsQuery,
  useNovasisPayProvidersQuery,
  useSincronizarNovasisPayCobroMutation,
} from "../../../tanstack/NovasisPayStack";
import { fmtFechaHora } from "../../../utils/fecha";

// Mapeo status backend → Chip MUI. El enum vive en
// smartfactvoice-backend prisma/schema.prisma (novasis_pay_cobro_status).
const STATUS_META = Object.freeze({
  pendiente:  { label: "Pendiente",  color: "warning", icon: "lucide:clock"        },
  procesando: { label: "Procesando", color: "info",    icon: "lucide:loader"       },
  aprobado:   { label: "Aprobado",   color: "success", icon: "lucide:check-circle" },
  rechazado:  { label: "Rechazado",  color: "error",   icon: "lucide:x-circle"     },
  expirado:   { label: "Expirado",   color: "default", icon: "lucide:timer-off"    },
  cancelado:  { label: "Cancelado",  color: "default", icon: "lucide:ban"          },
});

// Devuelve { texto, tono } para mostrar cuánto le falta al link de pago.
// tono: success = mucho tiempo, warning = <1h, error = vencido, default = sin fecha.
const calcularVencimiento = (expiresAt) => {
  if (!expiresAt) return { texto: "Sin vencimiento", tono: "default" };
  const ms = new Date(expiresAt).getTime() - Date.now();
  if (ms <= 0) return { texto: "Vencido", tono: "error" };
  const minutos = Math.floor(ms / 60_000);
  if (minutos < 60) return { texto: `Vence en ${minutos} min`, tono: "warning" };
  const horas = Math.floor(minutos / 60);
  if (horas < 24) return { texto: `Vence en ${horas} h`, tono: horas <= 2 ? "warning" : "success" };
  const dias = Math.floor(horas / 24);
  return { texto: `Vence en ${dias} día${dias > 1 ? "s" : ""}`, tono: "success" };
};

const colorTono = (tono) => {
  const map = {
    success: "success.main",
    warning: "warning.main",
    error: "error.main",
    default: "text.secondary",
  };
  return map[tono] ?? "text.secondary";
};

const iniciales = (nombre, email) => {
  const fuente = (nombre || email || "?").trim();
  const partes = fuente.split(/[\s@]+/).filter(Boolean);
  if (partes.length === 0) return "?";
  if (partes.length === 1) return partes[0].slice(0, 2).toUpperCase();
  return (partes[0][0] + partes[1][0]).toUpperCase();
};

const STATUS_FILTROS = [
  { value: "",           label: "Todos" },
  { value: "pendiente",  label: "Pendientes" },
  { value: "procesando", label: "Procesando" },
  { value: "aprobado",   label: "Aprobados" },
  { value: "rechazado",  label: "Rechazados" },
  { value: "expirado",   label: "Expirados" },
];

// Mínimos por moneda de FALLBACK. El mínimo real lo define cada proveedor y
// viene en el catálogo del gateway (`minAmount`); esto se usa solo si el
// catálogo no trae el dato para la moneda. Cobros por debajo del mínimo del
// proveedor se rechazan con "Amount too low".
const MONTO_MINIMO = Object.freeze({
  PYG: 10000,
  USD: 1,
  ARS: 100,
  BRL: 1,
  CLP: 500,
  UYU: 30,
});

// Calcula el mínimo aplicable según el proveedor que rutearía el cobro.
// - Si el comercio tiene `default_provider`, usa el mínimo de ese proveedor.
// - Si no, toma el más permisivo entre los proveedores disponibles.
// - Fallback final: MONTO_MINIMO por moneda.
function minimoPorProveedor(providers, defaultProvider, moneda) {
  const list = providers ?? [];
  const fallback = MONTO_MINIMO[moneda] ?? 1;
  const minDe = (p) => (p?.minAmount ? p.minAmount[moneda] : undefined);
  if (defaultProvider) {
    const p = list.find((x) => x.id === defaultProvider);
    const m = minDe(p);
    if (typeof m === "number") return m;
  }
  const mins = list
    .filter((p) => p.available !== false)
    .map(minDe)
    .filter((m) => typeof m === "number");
  return mins.length ? Math.min(...mins) : fallback;
}

const monedaPorPais = (pais) => {
  const map = { PY: "PYG", AR: "ARS", BR: "BRL", CL: "CLP", UY: "UYU", US: "USD" };
  return map[(pais ?? "").toUpperCase()] ?? "USD";
};

const fmtMonto = (monto, currency) => {
  const n = Number(monto);
  if (!Number.isFinite(n)) return monto;
  if (currency === "PYG") {
    return `${n.toLocaleString("es-PY", { maximumFractionDigits: 0 })} Gs.`;
  }
  return `${n.toLocaleString("es-PY", { minimumFractionDigits: 2 })} ${currency}`;
};

export function Cobros({ canCrear }) {
  const { data: cfg } = useNovasisPayConfigQuery();
  const [statusFiltro, setStatusFiltro] = useState("");
  const [search, setSearch] = useState("");
  const [debouncedSearch, setDebouncedSearch] = useState("");
  const [page, setPage] = useState(1);
  const [rowsPerPage, setRowsPerPage] = useState(20);
  const [dialogOpen, setDialogOpen] = useState(false);

  // Debounce del buscador para no pegarle al backend en cada tecla.
  useEffect(() => {
    const t = setTimeout(() => setDebouncedSearch(search.trim()), 350);
    return () => clearTimeout(t);
  }, [search]);

  // Cualquier cambio de filtro/búsqueda/tamaño vuelve a la página 1.
  useEffect(() => {
    setPage(1);
  }, [debouncedSearch, statusFiltro, rowsPerPage]);

  const { data, isLoading, isFetching } = useNovasisPayCobrosQuery({
    limit: rowsPerPage,
    page,
    ...(debouncedSearch && { search: debouncedSearch }),
    ...(statusFiltro && { status: statusFiltro }),
  });

  const filas = data?.data ?? [];
  const total = data?.total ?? 0;
  const totalPages = data?.totalPages ?? 1;
  const cobrosHabilitados = !!cfg?.activo && !!cfg?.tiene_secret_key;
  const hayFiltro = !!debouncedSearch || !!statusFiltro;

  const copiarLink = async (url) => {
    try {
      await navigator.clipboard.writeText(url);
      toast.success("Link copiado al portapapeles");
    } catch {
      toast.error("No se pudo copiar el link");
    }
  };

  return (
    <Paper variant="outlined" sx={{ p: 3 }}>
      <Stack direction={{ xs: "column", sm: "row" }} alignItems={{ sm: "center" }} spacing={1.5} mb={2}>
        <Stack direction="row" alignItems="center" spacing={1.5} flex={1}>
          <Icon icon="lucide:credit-card" width={22} />
          <Typography variant="subtitle1" fontWeight={600}>
            Cobros
          </Typography>
        </Stack>
        <TextField
          size="small"
          placeholder="Buscar referencia, comprador…"
          value={search}
          onChange={(e) => setSearch(e.target.value)}
          sx={{ minWidth: { xs: "100%", sm: 240 } }}
          InputProps={{
            startAdornment: (
              <InputAdornment position="start">
                <Icon icon="lucide:search" width={16} />
              </InputAdornment>
            ),
            endAdornment: search ? (
              <InputAdornment position="end">
                <IconButton size="small" edge="end" onClick={() => setSearch("")}>
                  <Icon icon="lucide:x" width={14} />
                </IconButton>
              </InputAdornment>
            ) : null,
          }}
        />
        <TextField
          select
          size="small"
          label="Estado"
          value={statusFiltro}
          onChange={(e) => setStatusFiltro(e.target.value)}
          sx={{ minWidth: 180 }}
        >
          {STATUS_FILTROS.map((f) => (
            <MenuItem key={f.value || "todos"} value={f.value}>
              {f.label}
            </MenuItem>
          ))}
        </TextField>
        <Button
          variant="contained"
          startIcon={<Icon icon="mdi:plus" width={18} />}
          disabled={!canCrear || !cobrosHabilitados}
          onClick={() => setDialogOpen(true)}
        >
          Nuevo cobro
        </Button>
      </Stack>

      {!cobrosHabilitados && (
        <Box mb={2}>
          <Chip
            color="warning"
            variant="outlined"
            icon={<Icon icon="mdi:alert" width={16} />}
            label="Activá Novasis Pay y guardá la clave privada en Cuentas antes de cobrar."
          />
        </Box>
      )}

      {isLoading ? (
        <Box sx={{ display: "flex", justifyContent: "center", p: 6 }}>
          <CircularProgress size={28} />
        </Box>
      ) : filas.length === 0 ? (
        <EmptyState
          icon="lucide:credit-card"
          title={hayFiltro ? "Sin resultados" : "Todavía no hay cobros"}
          description={
            hayFiltro
              ? "Probá con otra búsqueda o cambiá el filtro de estado."
              : "Generá tu primer cobro: el cliente recibe un link, paga en una página segura y vas a verlo acá apenas confirme."
          }
        />
      ) : (
        <>
          <Stack spacing={1.5} sx={{ opacity: isFetching ? 0.6 : 1, transition: "opacity .15s" }}>
            {filas.map((c) => (
              <CobroItem key={c.id} cobro={c} onCopyLink={copiarLink} />
            ))}
          </Stack>
          <TablePaginationBar
            page={page}
            totalPages={totalPages}
            onPageChange={setPage}
            total={total}
            shown={filas.length}
            noun="cobros"
            rowsPerPage={rowsPerPage}
            onRowsPerPageChange={setRowsPerPage}
          />
        </>
      )}

      {dialogOpen && (
        <NuevoCobroDialog
          open={dialogOpen}
          onClose={() => setDialogOpen(false)}
          defaultCountry={cfg?.default_country ?? "PY"}
          defaultProvider={cfg?.default_provider ?? null}
        />
      )}
    </Paper>
  );
}

function CobroItem({ cobro, onCopyLink }) {
  const meta = STATUS_META[cobro.status] ?? { label: cobro.status, color: "default", icon: "lucide:circle" };
  const vencimiento = calcularVencimiento(cobro.expires_at);
  const sync = useSincronizarNovasisPayCobroMutation();
  const comprador = cobro.comprador;
  const linkActivo = !!cobro.hosted_url && cobro.status === "pendiente" && vencimiento.tono !== "error";

  return (
    <Paper
      variant="outlined"
      sx={{
        p: 2,
        borderLeft: 4,
        borderLeftColor: `${meta.color === "default" ? "grey" : meta.color}.main`,
        transition: "background-color 0.15s",
        "&:hover": { bgcolor: "action.hover" },
      }}
    >
      <Grid container spacing={2} alignItems="center">
        <Grid item xs={12} sm={4}>
          <Stack direction="row" spacing={1.5} alignItems="center">
            <Box
              sx={{
                width: 40,
                height: 40,
                borderRadius: "50%",
                bgcolor: comprador?.nombre || comprador?.email ? "primary.light" : "grey.300",
                color: "primary.contrastText",
                display: "grid",
                placeItems: "center",
                fontSize: 13,
                fontWeight: 600,
                flexShrink: 0,
              }}
            >
              {comprador?.nombre || comprador?.email
                ? iniciales(comprador.nombre, comprador.email)
                : <Icon icon="lucide:user" width={18} />}
            </Box>
            <Box sx={{ minWidth: 0, flex: 1 }}>
              <Typography variant="body2" fontWeight={600} noWrap>
                {comprador?.nombre || comprador?.email || "Sin comprador"}
              </Typography>
              <Typography variant="caption" color="text.secondary" noWrap display="block">
                {comprador?.email && comprador?.nombre
                  ? comprador.email
                  : cobro.descripcion || cobro.external_reference || "—"}
              </Typography>
            </Box>
          </Stack>
        </Grid>

        <Grid item xs={6} sm={2}>
          <Typography variant="caption" color="text.secondary" display="block">
            Monto
          </Typography>
          <Typography variant="body1" fontWeight={700}>
            {fmtMonto(cobro.monto, cobro.currency)}
          </Typography>
        </Grid>

        <Grid item xs={6} sm={2}>
          <Typography variant="caption" color="text.secondary" display="block">
            Estado
          </Typography>
          <Chip
            size="small"
            color={meta.color}
            label={meta.label}
            icon={<Icon icon={meta.icon} width={14} />}
            sx={{ "& .MuiChip-icon": { ml: 0.5 } }}
          />
        </Grid>

        <Grid item xs={6} sm={2}>
          <Typography variant="caption" color="text.secondary" display="block">
            Vencimiento
          </Typography>
          <Stack direction="row" spacing={0.5} alignItems="center">
            <Icon
              icon={vencimiento.tono === "error" ? "lucide:alert-circle" : "lucide:clock"}
              width={14}
            />
            <Typography variant="body2" sx={{ color: colorTono(vencimiento.tono), fontWeight: 500 }}>
              {vencimiento.texto}
            </Typography>
          </Stack>
        </Grid>

        <Grid item xs={6} sm={2}>
          <Stack direction="row" spacing={0.5} justifyContent="flex-end">
            <Tooltip title="Refrescar estado">
              <span>
                <IconButton
                  size="small"
                  onClick={() => sync.mutate(cobro.id)}
                  disabled={sync.isPending}
                >
                  {sync.isPending ? (
                    <CircularProgress size={16} />
                  ) : (
                    <Icon icon="lucide:refresh-cw" width={16} />
                  )}
                </IconButton>
              </span>
            </Tooltip>
            <Tooltip title={linkActivo ? "Abrir link de pago" : "Link no disponible"}>
              <span>
                <IconButton
                  size="small"
                  component="a"
                  href={cobro.hosted_url}
                  target="_blank"
                  rel="noopener noreferrer"
                  disabled={!linkActivo}
                >
                  <Icon icon="lucide:external-link" width={16} />
                </IconButton>
              </span>
            </Tooltip>
            <Tooltip title="Copiar link">
              <span>
                <IconButton
                  size="small"
                  onClick={() => onCopyLink(cobro.hosted_url)}
                  disabled={!cobro.hosted_url}
                >
                  <Icon icon="lucide:copy" width={15} />
                </IconButton>
              </span>
            </Tooltip>
          </Stack>
        </Grid>
      </Grid>

      <Divider sx={{ my: 1.5 }} />

      <Stack
        direction={{ xs: "column", sm: "row" }}
        spacing={{ xs: 0.5, sm: 2 }}
        sx={{ fontSize: 12, color: "text.secondary" }}
      >
        <Stack direction="row" spacing={0.5} alignItems="center">
          <Icon icon="lucide:calendar" width={12} />
          <span>Creado: {fmtFechaHora(cobro.created_at)}</span>
        </Stack>
        {cobro.external_reference && (
          <Stack direction="row" spacing={0.5} alignItems="center">
            <Icon icon="lucide:hash" width={12} />
            <span>Ref: {cobro.external_reference}</span>
          </Stack>
        )}
        {comprador?.documento && (
          <Stack direction="row" spacing={0.5} alignItems="center">
            <Icon icon="lucide:id-card" width={12} />
            <span>Doc: {comprador.documento}</span>
          </Stack>
        )}
        {cobro.descripcion && comprador?.email && (
          <Stack direction="row" spacing={0.5} alignItems="center" sx={{ minWidth: 0 }}>
            <Icon icon="lucide:file-text" width={12} />
            <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
              {cobro.descripcion}
            </span>
          </Stack>
        )}
      </Stack>
    </Paper>
  );
}

function NuevoCobroDialog({ open, onClose, defaultCountry, defaultProvider }) {
  const crear = useCrearNovasisPayCobroMutation();
  const { data: providersRes } = useNovasisPayProvidersQuery();
  const origen = typeof window !== "undefined" ? window.location.origin : "";
  const moneda = monedaPorPais(defaultCountry);
  const minimo = minimoPorProveedor(providersRes?.providers, defaultProvider, moneda);

  const [modo, setModo] = useState("link");
  // Provider para el cobro directo: el preferido del comercio (o el primero que
  // soporte directo). Las capacidades (min, campos requeridos, si soporta
  // directo, si exige método) las declara el gateway — no se hardcodean acá.
  const providers = providersRes?.providers ?? [];
  const providerDirecto =
    defaultProvider || providers.find((p) => p.supportsDirect)?.id || "dpago";
  const capsDirecto = providers.find((p) => p.id === providerDirecto);
  const soportaDirecto = !!capsDirecto?.supportsDirect;
  const camposRequeridosDirecto = capsDirecto?.requiredCustomerFields ?? [];

  const { data: metodosRes, isLoading: cargandoMetodos } = useNovasisPayPaymentMethodsQuery(
    providerDirecto,
    defaultCountry,
    { enabled: modo === "directo" },
  );
  const metodos = metodosRes?.methods ?? [];
  const [resultado, setResultado] = useState(null);
  const [confirmando, setConfirmando] = useState(false);

  // Si el proveedor no soporta directo, forzamos link.
  useEffect(() => {
    if (!soportaDirecto && modo === "directo") setModo("link");
  }, [soportaDirecto, modo]);

  const [form, setForm] = useState({
    monto: 0,
    platform_id: "",
    descripcion: "",
    external_reference: "",
    comprador_nombre: "",
    comprador_email: "",
    comprador_documento: "",
    comprador_telefono: "",
    return_url: `${origen}/pago-exitoso`,
    cancel_url: `${origen}/pago-cancelado`,
  });
  const [mostrarUrls, setMostrarUrls] = useState(false);
  const set = (k, v) => setForm((f) => ({ ...f, [k]: v }));

  const montoInsuficiente = !!form.monto && form.monto < minimo;
  const emailInvalido =
    !!form.comprador_email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.comprador_email);
  // Campos del comprador requeridos por el proveedor para el cobro directo
  // (nombres canónicos del gateway → campos del form). Se derivan del descriptor.
  const CAMPO_COMPRADOR = {
    email: "comprador_email",
    name: "comprador_nombre",
    docNumber: "comprador_documento",
    phone: "comprador_telefono",
  };
  const camposFaltantesDirecto =
    modo === "directo"
      ? camposRequeridosDirecto.filter((f) => !form[CAMPO_COMPRADOR[f]]?.trim())
      : [];
  const compradorIncompletoDirecto = camposFaltantesDirecto.length > 0;
  // ¿El campo del comprador es requerido por el provider en modo directo?
  const reqComprador = (f) => modo === "directo" && camposRequeridosDirecto.includes(f);

  const handleSubmit = () => {
    if (!form.monto || form.monto < minimo) {
      toast.error(`El monto mínimo para ${moneda} es ${fmtMonto(minimo, moneda)}`);
      return;
    }
    if (emailInvalido) {
      toast.error("El email del comprador no tiene un formato válido");
      return;
    }
    if (modo === "directo" && !form.platform_id) {
      toast.error("Elegí el medio de pago (ej. QR) para el cobro directo");
      return;
    }
    if (compradorIncompletoDirecto) {
      const etiquetas = { email: "email", name: "nombre", docNumber: "documento", phone: "teléfono" };
      const faltan = camposFaltantesDirecto.map((f) => etiquetas[f] ?? f).join(", ");
      toast.error(`Para el cobro directo, completá del comprador: ${faltan}`);
      return;
    }
    // Validado: pedimos confirmación antes de generar (evita cobros por error).
    setConfirmando(true);
  };

  const ejecutarCobro = () => {
    const comprador =
      form.comprador_nombre || form.comprador_email || form.comprador_documento || form.comprador_telefono
        ? {
            nombre: form.comprador_nombre || undefined,
            email: form.comprador_email || undefined,
            documento: form.comprador_documento || undefined,
            telefono: form.comprador_telefono || undefined,
          }
        : undefined;

    crear.mutate(
      {
        monto: form.monto,
        modo,
        platform_id: modo === "directo" ? form.platform_id : undefined,
        descripcion: form.descripcion || undefined,
        external_reference: form.external_reference || undefined,
        comprador,
        return_url: form.return_url || undefined,
        cancel_url: form.cancel_url || undefined,
      },
      {
        // Mostramos el resultado en el modal: el link para compartir (modo link)
        // o el QR/redirect (modo directo). Así el cajero lo copia/escanea al toque.
        onSuccess: (data) => {
          setConfirmando(false);
          setResultado(data);
        },
        onError: () => setConfirmando(false),
      },
    );
  };

  const submitDeshabilitado =
    crear.isPending ||
    !form.monto ||
    montoInsuficiente ||
    emailInvalido ||
    (modo === "directo" && !form.platform_id);

  // Pantalla de resultado: link para compartir (modo link) o QR/redirect (directo).
  if (resultado) {
    return (
      <ResultadoCobro data={resultado} moneda={moneda} monto={form.monto} open={open} onClose={onClose} />
    );
  }

  // Confirmación antes de generar el cobro (evita cobros por error).
  if (confirmando) {
    const metodoNombre = metodos.find((m) => m.platformId === form.platform_id)?.name;
    const compradorTxt =
      form.comprador_nombre || form.comprador_email || "Sin comprador";
    return (
      <Dialog open={open} onClose={crear.isPending ? undefined : onClose} maxWidth="xs" fullWidth>
        <DialogTitle sx={{ pb: 1 }}>Confirmar cobro</DialogTitle>
        <DialogContent dividers>
          <Stack spacing={1.5}>
            <Typography variant="body2" color="text.secondary">
              Revisá antes de generar:
            </Typography>
            <FilaConfirm etiqueta="Monto" valor={fmtMonto(form.monto, moneda)} fuerte />
            <FilaConfirm
              etiqueta="Modalidad"
              valor={modo === "directo" ? "QR / pago directo" : "Link de pago"}
            />
            {modo === "directo" && metodoNombre && (
              <FilaConfirm etiqueta="Medio" valor={metodoNombre} />
            )}
            <FilaConfirm etiqueta="Comprador" valor={compradorTxt} />
            {form.external_reference && (
              <FilaConfirm etiqueta="Referencia" valor={form.external_reference} />
            )}
          </Stack>
        </DialogContent>
        <DialogActions sx={{ px: 3, py: 2 }}>
          <Button onClick={() => setConfirmando(false)} disabled={crear.isPending}>
            Volver
          </Button>
          <Button
            variant="contained"
            onClick={ejecutarCobro}
            disabled={crear.isPending}
            startIcon={
              crear.isPending ? <CircularProgress size={16} color="inherit" /> : undefined
            }
          >
            {crear.isPending ? "Generando…" : "Confirmar y generar"}
          </Button>
        </DialogActions>
      </Dialog>
    );
  }

  return (
    <Dialog open={open} onClose={onClose} maxWidth="sm" fullWidth>
      <DialogTitle sx={{ pb: 1 }}>
        <Stack direction="row" alignItems="center" spacing={1.5}>
          <Box
            sx={{
              width: 36,
              height: 36,
              borderRadius: 1.5,
              bgcolor: "primary.main",
              color: "primary.contrastText",
              display: "grid",
              placeItems: "center",
            }}
          >
            <Icon icon="lucide:credit-card" width={20} />
          </Box>
          <Box>
            <Typography variant="subtitle1" fontWeight={600} lineHeight={1.2}>
              Nuevo cobro
            </Typography>
            <Typography variant="caption" color="text.secondary">
              Genera un link de pago que podés enviar al cliente.
            </Typography>
          </Box>
        </Stack>
      </DialogTitle>

      <DialogContent dividers>
        <Stack spacing={3}>
          {soportaDirecto && (
          <SeccionForm
            icon="lucide:wallet"
            titulo="Modalidad"
            descripcion="Cómo va a pagar el cliente."
          >
            <ToggleButtonGroup
              exclusive
              size="small"
              color="primary"
              value={modo}
              onChange={(_e, v) => v && setModo(v)}
              sx={{ mb: modo === "directo" ? 2 : 0 }}
            >
              <ToggleButton value="link">
                <Icon icon="lucide:link" width={16} style={{ marginRight: 6 }} />
                Link de pago
              </ToggleButton>
              <ToggleButton value="directo">
                <Icon icon="lucide:qr-code" width={16} style={{ marginRight: 6 }} />
                QR / pago directo
              </ToggleButton>
            </ToggleButtonGroup>
            {modo === "directo" && (
              <>
                <TextField
                  select
                  fullWidth
                  size="small"
                  label="Medio de pago"
                  value={form.platform_id}
                  onChange={(e) => set("platform_id", e.target.value)}
                  disabled={cargandoMetodos}
                  helperText={
                    cargandoMetodos
                      ? "Cargando medios de pago…"
                      : `Medios de ${providerDirecto}. Para QR embebido elegí una opción QR.`
                  }
                >
                  {metodos.map((m) => (
                    <MenuItem key={m.platformId} value={m.platformId}>
                      {m.name}
                    </MenuItem>
                  ))}
                </TextField>
                <Alert severity="info" variant="outlined" sx={{ mt: 1.5 }}>
                  El pago directo (QR embebido) requiere el proveedor en producción. En pruebas puede
                  devolver un link a la página del proveedor en lugar del QR.
                </Alert>
              </>
            )}
          </SeccionForm>
          )}

          <SeccionForm
            icon="lucide:dollar-sign"
            titulo="Monto y referencia"
            descripcion="Cuánto cobrar y cómo identificás este cobro en tu sistema."
          >
            <Grid container spacing={2}>
              <Grid item xs={12} sm={6}>
                <MonedaInput
                  label="Monto"
                  moneda={moneda}
                  value={form.monto}
                  onChange={(v) => set("monto", v)}
                  error={montoInsuficiente}
                  helperText={
                    montoInsuficiente
                      ? `Mínimo permitido: ${fmtMonto(minimo, moneda)}`
                      : `Mínimo: ${fmtMonto(minimo, moneda)}`
                  }
                />
              </Grid>
              <Grid item xs={12} sm={6}>
                <FieldHint
                  fullWidth
                  label="Referencia interna"
                  value={form.external_reference}
                  onChange={(e) => set("external_reference", e.target.value)}
                  hint="Tu nro de factura o pedido. Evita cobros duplicados si reintentás."
                  placeholder="FAC-001"
                />
              </Grid>
              <Grid item xs={12}>
                <FieldHint
                  fullWidth
                  label="Descripción"
                  value={form.descripcion}
                  onChange={(e) => set("descripcion", e.target.value)}
                  hint="Lo que ve el cliente en la página de pago."
                  placeholder="Pago de pedido #1234"
                />
              </Grid>
            </Grid>
          </SeccionForm>

          <SeccionForm
            icon="lucide:user"
            titulo="Comprador"
            descripcion="Opcional. Si lo completás, el checkout viene prellenado y agilizás el pago."
          >
            <Grid container spacing={2}>
              <Grid item xs={12} sm={6}>
                <FieldHint
                  fullWidth
                  label={`Nombre${reqComprador("name") ? " *" : ""}`}
                  value={form.comprador_nombre}
                  onChange={(e) => set("comprador_nombre", e.target.value)}
                  hint="Nombre y apellido del cliente."
                  placeholder="Juan Pérez"
                />
              </Grid>
              <Grid item xs={12} sm={6}>
                <FieldHint
                  fullWidth
                  type="email"
                  label={`Email${reqComprador("email") ? " *" : ""}`}
                  value={form.comprador_email}
                  onChange={(e) => set("comprador_email", e.target.value)}
                  error={emailInvalido}
                  hint={emailInvalido ? "Formato de email inválido." : "Para enviarle el comprobante."}
                  placeholder="cliente@empresa.com"
                />
              </Grid>
              <Grid item xs={12} sm={6}>
                <FieldHint
                  fullWidth
                  label={`Documento${reqComprador("docNumber") ? " *" : ""}`}
                  value={form.comprador_documento}
                  onChange={(e) => set("comprador_documento", e.target.value)}
                  hint="CI o RUC (con guión: 80012345-6)."
                  placeholder="80012345-6"
                />
              </Grid>
              <Grid item xs={12} sm={6}>
                <FieldHint
                  fullWidth
                  label={`Teléfono${reqComprador("phone") ? " *" : ""}`}
                  value={form.comprador_telefono}
                  onChange={(e) => set("comprador_telefono", e.target.value)}
                  hint="Con código de país (+595...)."
                  placeholder="+595981000000"
                />
              </Grid>
            </Grid>
          </SeccionForm>

          <Box>
            <MuiLink
              component="button"
              type="button"
              underline="hover"
              onClick={() => setMostrarUrls((v) => !v)}
              sx={{
                display: "inline-flex",
                alignItems: "center",
                gap: 0.5,
                fontSize: 13,
                fontWeight: 500,
              }}
            >
              <Icon
                icon={mostrarUrls ? "lucide:chevron-down" : "lucide:chevron-right"}
                width={16}
              />
              Configuración avanzada (URLs de retorno)
            </MuiLink>
            <Collapse in={mostrarUrls}>
              <Box mt={2}>
                <Grid container spacing={2}>
                  <Grid item xs={12} sm={6}>
                    <FieldHint
                      fullWidth
                      label="URL al confirmar"
                      value={form.return_url}
                      onChange={(e) => set("return_url", e.target.value)}
                      hint="A dónde vuelve el cliente después de pagar."
                    />
                  </Grid>
                  <Grid item xs={12} sm={6}>
                    <FieldHint
                      fullWidth
                      label="URL al cancelar"
                      value={form.cancel_url}
                      onChange={(e) => set("cancel_url", e.target.value)}
                      hint="A dónde vuelve si cancela el pago."
                    />
                  </Grid>
                </Grid>
              </Box>
            </Collapse>
          </Box>

          {crear.isError && (
            <Alert severity="error" variant="outlined">
              {crear.error?.response?.data?.message ?? "No se pudo crear el cobro. Probá nuevamente."}
            </Alert>
          )}
        </Stack>
      </DialogContent>

      <DialogActions sx={{ px: 3, py: 2 }}>
        <Button onClick={onClose} disabled={crear.isPending}>
          Cancelar
        </Button>
        <Button
          variant="contained"
          onClick={handleSubmit}
          disabled={submitDeshabilitado}
          startIcon={
            crear.isPending ? (
              <CircularProgress size={16} color="inherit" />
            ) : (
              <Icon icon={modo === "directo" ? "lucide:qr-code" : "lucide:link"} width={16} />
            )
          }
        >
          {crear.isPending
            ? "Generando…"
            : modo === "directo"
              ? "Cobrar con QR / directo"
              : "Generar link de pago"}
        </Button>
      </DialogActions>
    </Dialog>
  );
}

// Pantalla de resultado de un cobro (QR/link) con AUTO-SYNC: mientras está
// pendiente, consulta el estado cada 4s y cuando se acredita muestra "¡Pago
// recibido!" sin depender del webhook.
function ResultadoCobro({ data, moneda, monto, open, onClose }) {
  const [estado, setEstado] = useState(data.status ?? "pendiente");
  const finalizado = ["aprobado", "rechazado", "expirado", "cancelado"].includes(estado);
  const { data: synced } = useCobroSyncPolling(data.id, !finalizado);

  useEffect(() => {
    if (synced?.status && synced.status !== estado) setEstado(synced.status);
  }, [synced, estado]);

  const esDirecto = data.modo === "directo";
  const aprobado = estado === "aprobado";
  const fallido = estado === "rechazado" || estado === "expirado" || estado === "cancelado";

  return (
    <Dialog open={open} onClose={onClose} maxWidth="sm" fullWidth>
      <DialogTitle sx={{ pb: 1 }}>
        {aprobado
          ? "¡Pago recibido!"
          : fallido
            ? "El cobro no se completó"
            : esDirecto
              ? "Cobro directo generado"
              : "Link de pago generado"}
      </DialogTitle>
      <DialogContent dividers>
        {aprobado ? (
          <Stack spacing={1.5} alignItems="center" py={3}>
            <Icon icon="lucide:check-circle" width={56} style={{ color: "#16A34A" }} />
            <Typography variant="h5" fontWeight={700}>
              {fmtMonto(monto, moneda)}
            </Typography>
            <Typography variant="body2" color="text.secondary">
              El pago se acreditó correctamente.
            </Typography>
          </Stack>
        ) : fallido ? (
          <Stack spacing={1.5} alignItems="center" py={3}>
            <Icon icon="lucide:x-circle" width={56} style={{ color: "#DC2626" }} />
            <Typography variant="body2" color="text.secondary">
              El cobro quedó <strong>{estado}</strong>.
            </Typography>
          </Stack>
        ) : (
          <>
            {esDirecto ? (
              <QrDirectoResult data={data} moneda={moneda} monto={monto} />
            ) : (
              <LinkResult data={data} moneda={moneda} monto={monto} />
            )}
            <Stack direction="row" alignItems="center" justifyContent="center" spacing={1} mt={2}>
              <CircularProgress size={14} />
              <Typography variant="caption" color="text.secondary">
                Esperando la confirmación del pago…
              </Typography>
            </Stack>
          </>
        )}
      </DialogContent>
      <DialogActions sx={{ px: 3, py: 2 }}>
        <Button variant="contained" onClick={onClose}>
          {aprobado || fallido ? "Cerrar" : "Listo"}
        </Button>
      </DialogActions>
    </Dialog>
  );
}

// Extrae el payload EMV del QR (string suelto o anidado en un objeto).
function extraerEmv(qr) {
  if (typeof qr === "string" && qr.trim()) return qr.trim();
  if (qr && typeof qr === "object") {
    for (const k of ["emv", "payload", "qrString", "qrData", "code"]) {
      const v = qr[k];
      if (typeof v === "string" && v.trim()) return v.trim();
    }
  }
  return null;
}

// Resultado de un cobro directo: dibuja el QR si el proveedor devolvió el EMV,
// o un botón a la página del proveedor como respaldo (típico en pruebas).
function QrDirectoResult({ data, moneda, monto }) {
  const emv = extraerEmv(data?.qr);
  const redirectUrl = data?.redirect_url ?? null;
  const [qrImg, setQrImg] = useState(null);

  useEffect(() => {
    let cancelado = false;
    if (emv) {
      QRCode.toDataURL(emv, { width: 260, margin: 1 })
        .then((url) => !cancelado && setQrImg(url))
        .catch(() => !cancelado && setQrImg(null));
    } else {
      setQrImg(null);
    }
    return () => {
      cancelado = true;
    };
  }, [emv]);

  return (
    <Stack spacing={2} alignItems="center" py={1}>
      <Typography variant="h6" fontWeight={700}>
        {fmtMonto(monto, moneda)}
      </Typography>
      {qrImg ? (
        <>
          <Box
            component="img"
            src={qrImg}
            alt="QR de pago"
            sx={{ width: 260, height: 260, borderRadius: 1 }}
          />
          <Typography variant="caption" color="text.secondary" textAlign="center">
            Pedile al cliente que escanee el QR con su app bancaria. El estado del cobro se
            actualiza solo cuando confirma el pago.
          </Typography>
        </>
      ) : redirectUrl ? (
        <Stack spacing={1.5} alignItems="center" width="100%">
          <Alert severity="info" variant="outlined">
            El proveedor no devolvió un QR para mostrar acá con este medio. Podés completar el pago
            en la página del proveedor:
          </Alert>
          <Button
            variant="contained"
            href={redirectUrl}
            target="_blank"
            rel="noopener noreferrer"
            startIcon={<Icon icon="lucide:external-link" width={16} />}
          >
            Abrir página de pago
          </Button>
        </Stack>
      ) : (
        <Alert severity="info" variant="outlined">
          Cobro creado. El estado se actualizará cuando el cliente complete el pago.
        </Alert>
      )}
    </Stack>
  );
}

// Resultado de un cobro por link: muestra la URL para compartir con copiar/abrir.
function LinkResult({ data, moneda, monto }) {
  // Link nativo del provider (redirect_url, ej. Dpago /links) o checkout hospedado.
  const url = data?.redirect_url || data?.hosted_url || "";
  const copiar = async () => {
    try {
      await navigator.clipboard.writeText(url);
      toast.success("Link copiado");
    } catch {
      toast.error("No se pudo copiar; seleccionalo y copialo manualmente");
    }
  };
  return (
    <Stack spacing={2} py={1}>
      <Typography variant="h6" fontWeight={700} textAlign="center">
        {fmtMonto(monto, moneda)}
      </Typography>
      <Typography variant="body2" color="text.secondary" textAlign="center">
        Compartí este link con el cliente para que pague en una página segura. El estado del cobro
        se actualiza solo cuando paga.
      </Typography>
      <TextField
        fullWidth
        size="small"
        value={url}
        InputProps={{ readOnly: true }}
        onFocus={(e) => e.target.select()}
      />
      <Stack direction="row" spacing={1.5} justifyContent="center">
        <Button
          variant="contained"
          startIcon={<Icon icon="lucide:copy" width={16} />}
          onClick={copiar}
          disabled={!url}
        >
          Copiar link
        </Button>
        <Button
          variant="outlined"
          href={url || undefined}
          target="_blank"
          rel="noopener noreferrer"
          startIcon={<Icon icon="lucide:external-link" width={16} />}
          disabled={!url}
        >
          Abrir
        </Button>
      </Stack>
    </Stack>
  );
}

function FilaConfirm({ etiqueta, valor, fuerte }) {
  return (
    <Stack direction="row" justifyContent="space-between" spacing={2}>
      <Typography variant="body2" color="text.secondary">
        {etiqueta}
      </Typography>
      <Typography variant="body2" fontWeight={fuerte ? 700 : 500} textAlign="right">
        {valor}
      </Typography>
    </Stack>
  );
}

function SeccionForm({ icon, titulo, descripcion, children }) {
  return (
    <Box>
      <Stack direction="row" alignItems="center" spacing={1} mb={0.5}>
        <Icon icon={icon} width={16} />
        <Typography variant="subtitle2" fontWeight={600}>
          {titulo}
        </Typography>
      </Stack>
      {descripcion && (
        <Typography variant="caption" color="text.secondary" display="block" mb={1.5}>
          {descripcion}
        </Typography>
      )}
      <Divider sx={{ mb: 2 }} />
      {children}
    </Box>
  );
}
