import { Icon } from "@iconify/react";
import {
  Alert, Box, Button, Chip, CircularProgress, Link, MenuItem, Paper, Stack, TextField, Tooltip, Typography,
} from "@mui/material";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useEffect, useMemo, useState } from "react";
import { Link as RouterLink, useNavigate, useParams } from "react-router-dom";
import { toast } from "sonner";
import {
  aprobarLegajoClienteInm, getLegajoClienteInm, guardarLegajoClienteInm, observarLegajoClienteInm,
} from "../../api/inmobiliario.service";
import {
  EmptyState, FieldHint, InlineValidationBanner, MonedaInput, PrereqChecklist, ScreenGuia, SwitchConAyuda,
} from "../../components/_standards";
import {
  chipDe, INM_OPERACION_ESTADOS, INUSUAL_ESTADO, INUSUAL_REGLA, LEGAJO_CLIENTE_ESTADO, NIVEL_RIESGO, TIPO_PERSONA,
} from "../../components/_standards/enums/inmobiliario";
import { BeneficiariosEditor } from "../../components/organismos/inmobiliario/cumplimiento/BeneficiariosEditor";
import {
  CAMPOS_DE_FONDO, CLAVE_CUMPLIMIENTO, claveLegajoCliente, diasHasta, riesgosPosibles,
} from "../../components/organismos/inmobiliario/cumplimiento/cumplimientoUtils";
import { DocumentosLegajo } from "../../components/organismos/inmobiliario/cumplimiento/DocumentosLegajo";
import { RegistrarInusualDialog } from "../../components/organismos/inmobiliario/cumplimiento/InusualDialogs";
import { mensajeError } from "../../components/organismos/inmobiliario/inmUtils";
import { useParametrosInm } from "../../components/organismos/inmobiliario/obra/useObra";
import { Dato, Seccion } from "../../components/organismos/inmobiliario/operaciones/OperacionUi";
import { useConfirmDialog } from "../../hooks/useConfirmDialog";
import { usePermission } from "../../hooks/usePermission";
import { fmtFechaCalendario, fmtFechaHora } from "../../utils/fecha";

const GUIA_PASOS = [
  {
    icon: "mdi:account-details-outline",
    color: "#60a5fa",
    titulo: "1. Datos y origen de fondos",
    desc: "Tipo de persona, actividad, ingreso aproximado y de dónde salen los fondos de la compra.",
  },
  {
    icon: "mdi:account-tie-outline",
    color: "#f472b6",
    titulo: "2. PEP y beneficiarios",
    desc: "Si es persona expuesta políticamente (o pariente o allegado de una) y, si es una sociedad, quiénes son sus dueños reales.",
  },
  {
    icon: "mdi:paperclip",
    color: "#fbbf24",
    titulo: "3. Documentos",
    desc: "Copia de la cédula o el RUC, y lo que corresponda: estatuto, declaración jurada de PEP, constancia de ingresos.",
  },
  {
    icon: "mdi:check-decagram-outline",
    color: "#34d399",
    titulo: "4. Aprobación",
    desc: "El oficial de cumplimiento lo aprueba cuando no falta nada. Vale 24 meses (12 si el riesgo es alto).",
  },
];

const GUIA_NOTAS = [
  { icon: "mdi:file-sign", text: "Sin el legajo aprobado y vigente de cada comprador y cotitular, el boleto no se firma." },
  { icon: "mdi:refresh", text: "Si cambiás un dato de fondo de un legajo aprobado, vuelve a pendiente y hay que aprobarlo de nuevo." },
  { icon: "mdi:archive-lock-outline", text: "Nada se borra: los documentos se anulan y todo se conserva 5 años desde la última operación." },
];

const GRILLA = {
  display: "grid",
  gridTemplateColumns: "repeat(auto-fill, minmax(min(100%, 200px), 1fr))",
  gap: 1.5,
  alignItems: "start",
};

const pctTexto = (v) => (v == null || v === "" ? "" : String(Number(v)).replace(".", ","));
const aPct = (v) => Number(String(v ?? "").replace(",", "."));
const texto = (v) => (typeof v === "string" ? v.trim() : "") || null;

const formDesde = (l) => ({
  tipo_persona: l?.tipo_persona ?? "FISICA",
  actividad: l?.actividad ?? "",
  ingreso_mensual: l?.ingreso_mensual != null ? Number(l.ingreso_mensual) : 0,
  ingreso_moneda: l?.ingreso_moneda ?? "PYG",
  origen_fondos: l?.origen_fondos ?? "",
  pep: Boolean(l?.pep),
  pep_cargo: l?.pep_cargo ?? "",
  pep_vinculo: l?.pep_vinculo ?? "",
  beneficiarios_finales: (l?.beneficiarios_finales ?? []).map((b) => ({
    nombre: b.nombre ?? "",
    documento: b.documento ?? "",
    pct: pctTexto(b.pct),
    pep: Boolean(b.pep),
  })),
  nivel_riesgo_manual: l?.nivel_riesgo_manual ?? "",
  observaciones: l?.observaciones ?? "",
});

/** El form llevado a lo que espera el backend (para comparar con lo guardado y para enviar). */
const normalizar = (f) => {
  const ingreso = Number(f.ingreso_mensual) > 0 ? Number(f.ingreso_mensual) : null;
  return {
    tipo_persona: f.tipo_persona,
    actividad: texto(f.actividad),
    ingreso_mensual: ingreso,
    ingreso_moneda: ingreso ? f.ingreso_moneda : null,
    origen_fondos: texto(f.origen_fondos),
    pep: Boolean(f.pep),
    pep_cargo: f.pep ? texto(f.pep_cargo) : null,
    pep_vinculo: f.pep ? texto(f.pep_vinculo) : null,
    beneficiarios_finales:
      f.tipo_persona === "JURIDICA"
        ? f.beneficiarios_finales.map((b) => ({
            nombre: b.nombre.trim(),
            ...(b.documento?.trim() && { documento: b.documento.trim() }),
            pct: Math.round(aPct(b.pct) * 100) / 100,
            pep: Boolean(b.pep),
          }))
        : [],
    observaciones: texto(f.observaciones),
  };
};

const igual = (a, b) => JSON.stringify(a ?? null) === JSON.stringify(b ?? null);

/** Primer documento que le falta al legajo, para proponerlo al subir. */
const tipoSugerido = (legajo) => {
  const f = (legajo?.faltantes ?? []).join(" ");
  if (/cédula|RUC/.test(f)) return legajo?.tipo_persona === "JURIDICA" ? "RUC" : "CEDULA";
  if (/estatuto/.test(f)) return "ESTATUTO";
  if (/PEP/.test(f)) return "DECLARACION_PEP";
  return "OTRO";
};

const OPERACIONES_VISIBLES = 8;

const capitalizar = (s) => (s ? s.charAt(0).toUpperCase() + s.slice(1) : s);

export function InmLegajoCliente() {
  const { clienteId } = useParams();
  const navigate = useNavigate();
  const queryClient = useQueryClient();
  const { confirm, prompt, dialogs } = useConfirmDialog();
  const { can } = usePermission("INMOBILIARIO");
  const canVer = can("INM_CUM_LEGAJO_VER");
  const canEditar = can("INM_CUM_LEGAJO_EDITAR");
  const canAprobar = can("INM_CUM_LEGAJO_APROBAR");
  const canCrearInusual = can("INM_CUM_INUSUAL_CREAR");
  const canVerInusuales = can("INM_CUM_INUSUAL_VER");
  const { data: parametros } = useParametrosInm(can("INM_CFG_PARAMETROS_VER"));

  const queryKey = claveLegajoCliente(clienteId);
  const { data, isLoading, isError, error } = useQuery({
    queryKey,
    queryFn: () => getLegajoClienteInm(clienteId),
    enabled: canVer && Boolean(clienteId),
    refetchOnWindowFocus: false,
  });
  const legajo = data?.legajo ?? null;

  const [form, setForm] = useState(() => formDesde(null));
  const [errores, setErrores] = useState([]);
  const [guardando, setGuardando] = useState(false);
  const [inusualAbierta, setInusualAbierta] = useState(false);
  const [todasLasOperaciones, setTodasLasOperaciones] = useState(false);

  useEffect(() => {
    if (data) setForm(formDesde(data.legajo));
  }, [data]);

  const set = (campo, valor) => setForm((f) => ({ ...f, [campo]: valor }));

  // Sólo se envía lo que cambió: el backend compara cada campo contra lo guardado para
  // decidir si un aprobado vuelve a pendiente, y un "" contra un null cuenta como cambio.
  const cambios = useMemo(() => {
    const ahora = normalizar(form);
    const antes = legajo ? normalizar(formDesde(legajo)) : null;
    const c = Object.fromEntries(Object.entries(ahora).filter(([k, v]) => !antes || !igual(v, antes[k])));
    if (!legajo) {
      // Legajo nuevo: los vacíos no hace falta mandarlos.
      Object.keys(c).forEach((k) => {
        if (k !== "tipo_persona" && (c[k] == null || (Array.isArray(c[k]) && !c[k].length) || c[k] === false)) delete c[k];
      });
    }
    if (legajo && form.nivel_riesgo_manual !== (legajo.nivel_riesgo_manual ?? "")) c.nivel_riesgo = form.nivel_riesgo_manual || null;
    return c;
  }, [form, legajo]);
  const hayCambios = !legajo || Object.keys(cambios).length > 0;
  const sucio = legajo ? Object.keys(cambios).length > 0 : Object.keys(cambios).length > 1;
  const vuelveAPendiente = legajo?.estado === "APROBADO" && CAMPOS_DE_FONDO.filter((k) => !k.startsWith("ingreso")).some((k) => k in cambios);

  const refrescar = () => {
    queryClient.invalidateQueries({ queryKey: CLAVE_CUMPLIMIENTO });
  };
  const aplicar = (r) => {
    queryClient.setQueryData(queryKey, r);
    refrescar();
  };

  if (!canVer) return null;
  if (isLoading) {
    return (
      <Box sx={{ p: 4, display: "flex", justifyContent: "center" }}>
        <CircularProgress />
      </Box>
    );
  }
  if (isError || !data) {
    return (
      <Box sx={{ p: 3 }}>
        <EmptyState
          icon="mdi:account-question-outline"
          title="No encontramos al cliente"
          description={mensajeError(error, "Puede que pertenezca a otra empresa o que el enlace esté mal.")}
          ctaLabel="Volver a legajos"
          ctaIcon="mdi:arrow-left"
          onCta={() => navigate("/inmobiliario/cumplimiento?tab=legajos")}
        />
      </Box>
    );
  }

  const cliente = data.cliente ?? {};
  const estado = legajo ? chipDe(LEGAJO_CLIENTE_ESTADO, legajo.estado) : { label: "Sin legajo", color: "default" };
  const riesgoActual = legajo?.nivel_riesgo ?? null;
  const juridica = form.tipo_persona === "JURIDICA";
  const faltantes = legajo?.faltantes ?? [];
  const diasVence = legajo?.vence ? diasHasta(legajo.vence) : null;
  const vigencia = parametros
    ? `${parametros.meses_vigencia_legajo} meses (${parametros.meses_vigencia_legajo_alto} si el riesgo es alto)`
    : "24 meses (12 si el riesgo es alto)";
  const mesesAprobar =
    riesgoActual === "ALTO" ? (parametros?.meses_vigencia_legajo_alto ?? 12) : (parametros?.meses_vigencia_legajo ?? 24);

  const motivoNoAprobar = !legajo
    ? "Primero guardá el legajo"
    : sucio
      ? "Guardá los cambios antes de aprobar"
      : faltantes.length
        ? "Falta completar lo que indica la lista de la derecha"
        : null;

  const validar = () => {
    const errs = [];
    const n = normalizar(form);
    if (n.pep && !n.pep_cargo && !n.pep_vinculo)
      errs.push({ campo: "PEP", mensaje: "indicá el cargo o el vínculo con la persona expuesta" });
    if (juridica) {
      form.beneficiarios_finales.forEach((b, i) => {
        if (!b.nombre.trim()) errs.push({ campo: `Beneficiario ${i + 1}`, mensaje: "falta el nombre" });
        const p = aPct(b.pct);
        if (!(p >= 0 && p <= 100) || b.pct === "") errs.push({ campo: `Beneficiario ${i + 1}`, mensaje: "la participación va de 0 a 100 %" });
      });
      const total = n.beneficiarios_finales.reduce((a, b) => a + (b.pct || 0), 0);
      if (total > 100.0001) errs.push({ campo: "Beneficiarios finales", mensaje: "no pueden sumar más del 100 %" });
    }
    return errs;
  };

  const guardar = async () => {
    const errs = validar();
    setErrores(errs);
    if (errs.length) return;
    if (vuelveAPendiente) {
      const ok = await confirm({
        title: "El legajo vuelve a pendiente",
        message:
          "Cambiaste un dato de fondo (tipo de persona, actividad, origen de fondos, PEP o beneficiarios) de un legajo aprobado. Al guardar vuelve a pendiente y hay que aprobarlo de nuevo; mientras tanto el cliente no puede firmar boletos. ¿Continuás?",
        confirmText: "Guardar igual",
        confirmColor: "warning",
      });
      if (!ok) return;
    }
    setGuardando(true);
    try {
      const r = await guardarLegajoClienteInm(clienteId, cambios);
      aplicar(r);
      toast.success(legajo ? "Legajo guardado" : "Legajo creado");
      if (vuelveAPendiente) toast.warning("El legajo volvió a pendiente: hay que aprobarlo de nuevo.", { duration: 8000 });
    } catch (e) {
      setErrores([mensajeError(e, "No se pudo guardar el legajo")]);
    } finally {
      setGuardando(false);
    }
  };

  const aprobar = async () => {
    const ok = await confirm({
      title: `Aprobar el legajo de ${cliente.nombre ?? "el cliente"}`,
      message: `Queda vigente por ${mesesAprobar} meses (riesgo ${chipDe(NIVEL_RIESGO, riesgoActual).label.replace("Riesgo ", "")}) y habilita la firma de boletos.${
        form.pep || form.beneficiarios_finales.some((b) => b.pep)
          ? " Como es PEP, además se registra una operación inusual para su seguimiento reforzado."
          : ""
      } ¿Confirmás?`,
      confirmText: "Aprobar legajo",
      confirmColor: "success",
    });
    if (!ok) return;
    try {
      aplicar(await aprobarLegajoClienteInm(clienteId));
      toast.success("Legajo aprobado");
    } catch (e) {
      toast.error(mensajeError(e, "No se pudo aprobar el legajo"));
    }
  };

  const observar = async () => {
    const motivo = await prompt({
      title: "Observar el legajo",
      message: "El legajo queda observado (no vigente) hasta que se corrija y se vuelva a aprobar. El motivo queda en las observaciones.",
      label: "Motivo",
      placeholder: "Ej: el origen de fondos no coincide con la actividad declarada",
      required: true,
      maxLength: 255,
      confirmText: "Observar legajo",
      confirmColor: "warning",
    });
    if (motivo == null) return;
    try {
      aplicar(await observarLegajoClienteInm(clienteId, motivo.trim()));
      toast.success("Legajo observado");
    } catch (e) {
      toast.error(mensajeError(e, "No se pudo observar el legajo"));
    }
  };

  const riesgo = chipDe(NIVEL_RIESGO, legajo?.nivel_riesgo ?? "BAJO");

  return (
    <Box sx={{ p: { xs: 2, md: 3 }, pb: 0 }}>
      <Stack spacing={2}>
        <Box>
          <Button size="small" startIcon={<Icon icon="mdi:arrow-left" />} onClick={() => navigate("/inmobiliario/cumplimiento?tab=legajos")}>
            Volver a legajos
          </Button>
        </Box>

        <ScreenGuia
          moduloPadre="Inmobiliario"
          titulo="¿Qué lleva el legajo de debida diligencia?"
          intro="La Ley 1015/97 y la Res. SEPRELAD 201/2020 obligan a conocer a cada comprador: quién es, de dónde vienen sus fondos, si es PEP y, si es una sociedad, quiénes son sus beneficiarios finales."
          pasos={GUIA_PASOS}
          notas={GUIA_NOTAS}
        />

        {/* ── Cabecera ── */}
        <Paper variant="outlined" sx={{ p: 2 }}>
          <Stack direction="row" spacing={1} alignItems="center" flexWrap="wrap" useFlexGap>
            <Icon icon={chipDe(TIPO_PERSONA, form.tipo_persona).icon ?? "mdi:account-outline"} width={26} />
            <Box sx={{ mr: 0.5, minWidth: 0 }}>
              <Typography variant="h5" sx={{ overflowWrap: "anywhere" }}>
                {cliente.nombre ?? "Cliente"}
              </Typography>
              <Typography variant="caption" color="text.secondary">
                {[cliente.documento, cliente.telefono, cliente.email].filter(Boolean).join(" · ") || "Sin datos de contacto"}
              </Typography>
            </Box>
            <Chip size="small" color={estado.color} label={estado.label} data-testid="legajo-estado" />
            {riesgoActual && (
              <Chip size="small" variant="outlined" color={chipDe(NIVEL_RIESGO, riesgoActual).color} label={chipDe(NIVEL_RIESGO, riesgoActual).label} />
            )}
            {legajo && (
              <Chip
                size="small"
                variant="outlined"
                color={data.vigente ? (diasVence != null && diasVence <= 30 ? "warning" : "success") : "error"}
                icon={<Icon icon={data.vigente ? "mdi:shield-check-outline" : "mdi:shield-alert-outline"} width={14} />}
                label={data.vigente ? `Vigente hasta ${fmtFechaCalendario(legajo.vence)}` : "No vigente"}
              />
            )}
            {legajo?.pep && <Chip size="small" color="error" variant="outlined" label="PEP" />}
            <Box sx={{ flex: 1 }} />
            {canAprobar && legajo && legajo.estado !== "OBSERVADO" && (
              <Button variant="outlined" color="warning" startIcon={<Icon icon="mdi:alert-outline" />} onClick={observar}>
                Observar
              </Button>
            )}
            {canAprobar && (
              <Tooltip title={motivoNoAprobar ?? ""} enterDelay={300}>
                <span>
                  <Button
                    variant="contained"
                    color="success"
                    startIcon={<Icon icon="mdi:check-decagram-outline" />}
                    onClick={aprobar}
                    disabled={Boolean(motivoNoAprobar)}
                  >
                    {legajo?.estado === "APROBADO" ? "Aprobar legajo de nuevo" : "Aprobar legajo"}
                  </Button>
                </span>
              </Tooltip>
            )}
          </Stack>
          {legajo?.estado === "APROBADO" && legajo.aprobado_at && (
            <Typography variant="caption" color="text.secondary" component="div" sx={{ mt: 1 }}>
              Aprobado el {fmtFechaHora(legajo.aprobado_at)}. Aprobarlo de nuevo renueva la vigencia desde hoy.
            </Typography>
          )}
        </Paper>

        {!data.vigente && data.motivo && (
          <Alert severity={legajo?.estado === "OBSERVADO" ? "error" : "warning"} icon={<Icon icon="mdi:file-sign" />}>
            {capitalizar(data.motivo)}: no puede firmar boletos hasta que el legajo esté aprobado y vigente.
            {legajo?.estado === "OBSERVADO" && legajo.observaciones && (
              <>
                {" "}
                Observación: <strong>{legajo.observaciones}</strong>
              </>
            )}
          </Alert>
        )}

        <Box sx={{ display: "flex", flexWrap: "wrap", gap: 2, alignItems: "flex-start" }}>
          {/* ── Columna principal: el formulario ── */}
          <Stack spacing={2} sx={{ flex: "2 1 520px", minWidth: 0 }}>
            <InlineValidationBanner errors={errores} />
            {vuelveAPendiente && (
              <Alert severity="warning" icon={<Icon icon="mdi:refresh" />}>
                Cambiaste un dato de fondo de un legajo aprobado: al guardar vuelve a pendiente y hay que aprobarlo de nuevo.
              </Alert>
            )}

            <Seccion titulo="Datos del cliente" icon="mdi:account-details-outline">
              <Stack spacing={1.5}>
                <Box sx={GRILLA}>
                  <TextField
                    select
                    size="small"
                    label="Tipo de persona"
                    value={form.tipo_persona}
                    onChange={(ev) => set("tipo_persona", ev.target.value)}
                    disabled={!canEditar}
                    fullWidth
                  >
                    {Object.entries(TIPO_PERSONA).map(([k, v]) => (
                      <MenuItem key={k} value={k}>
                        {v.label}
                      </MenuItem>
                    ))}
                  </TextField>
                  <FieldHint
                    label="Actividad o profesión"
                    value={form.actividad}
                    onChange={(ev) => set("actividad", ev.target.value.slice(0, 150))}
                    hint={juridica ? "Ej: comercialización de insumos agrícolas" : "Ej: médico, comerciante, empleado público"}
                    disabled={!canEditar}
                    fullWidth
                  />
                  <TextField
                    select
                    size="small"
                    label="Moneda del ingreso"
                    value={form.ingreso_moneda}
                    onChange={(ev) => set("ingreso_moneda", ev.target.value)}
                    disabled={!canEditar}
                    fullWidth
                  >
                    <MenuItem value="PYG">PYG</MenuItem>
                    <MenuItem value="USD">USD</MenuItem>
                  </TextField>
                  <MonedaInput
                    label={juridica ? "Facturación mensual aprox." : "Ingreso mensual aprox."}
                    moneda={form.ingreso_moneda}
                    value={form.ingreso_mensual}
                    onChange={(v) => set("ingreso_mensual", v)}
                    helperText={form.ingreso_moneda === "PYG" ? "Opcional. Ej: 25.000.000" : "Opcional. Ej: 4.000"}
                    disabled={!canEditar}
                    fullWidth
                  />
                </Box>
                <FieldHint
                  label="Origen de los fondos"
                  value={form.origen_fondos}
                  onChange={(ev) => set("origen_fondos", ev.target.value.slice(0, 1000))}
                  hint="De dónde sale el dinero de la compra. Ej: ahorros de honorarios profesionales y venta de un vehículo"
                  multiline
                  minRows={2}
                  disabled={!canEditar}
                  fullWidth
                />
              </Stack>
            </Seccion>

            <Seccion
              titulo="Persona expuesta políticamente (PEP)"
              icon="mdi:account-tie-outline"
              acciones={form.pep && <Chip size="small" color="error" variant="outlined" label="Riesgo alto" />}
            >
              <Stack spacing={1.5}>
                <SwitchConAyuda
                  label="Es PEP, o pariente o allegado de una"
                  checked={form.pep}
                  onChange={(v) => set("pep", v)}
                  disabled={!canEditar}
                  ayuda="Funcionarios con cargos públicos relevantes (actuales o de los últimos 5 años), sus familiares hasta el segundo grado y sus colaboradores cercanos."
                  sx={{ ml: 0 }}
                />
                {form.pep && (
                  <Box sx={GRILLA}>
                    <FieldHint
                      label="Cargo"
                      value={form.pep_cargo}
                      onChange={(ev) => set("pep_cargo", ev.target.value.slice(0, 150))}
                      hint="Si es el PEP. Ej: concejal municipal"
                      disabled={!canEditar}
                      fullWidth
                    />
                    <FieldHint
                      label="Vínculo con el PEP"
                      value={form.pep_vinculo}
                      onChange={(ev) => set("pep_vinculo", ev.target.value.slice(0, 150))}
                      hint="Si es pariente o allegado. Ej: hermano de un viceministro"
                      disabled={!canEditar}
                      fullWidth
                    />
                  </Box>
                )}
                {form.pep && (
                  <Typography variant="caption" color="text.secondary">
                    Indicá el cargo o el vínculo (al menos uno). Para aprobar hace falta la declaración jurada de PEP, y queda con riesgo
                    alto: vigencia más corta y seguimiento reforzado.
                  </Typography>
                )}
              </Stack>
            </Seccion>

            {juridica && (
              <Seccion titulo="Beneficiarios finales" icon="mdi:account-multiple-outline">
                <Typography variant="body2" color="text.secondary" sx={{ mb: 1.5 }}>
                  Las personas físicas que, directa o indirectamente, tienen el 10 % o más de la sociedad o la controlan.
                </Typography>
                <BeneficiariosEditor
                  value={form.beneficiarios_finales}
                  onChange={(v) => set("beneficiarios_finales", v)}
                  disabled={!canEditar}
                />
              </Seccion>
            )}

            <Seccion
              titulo="Riesgo y observaciones"
              icon="mdi:gauge"
              acciones={<Chip size="small" variant="outlined" color={riesgo.color} label={riesgo.label} />}
            >
              <Stack spacing={1.5}>
                <Typography variant="body2" color="text.secondary">
                  El sistema lo calcula al guardar: PEP (o beneficiario PEP) o un ROS previo → alto; persona jurídica u operación
                  inusual abierta → medio; si no, bajo. Si ves algo que el cálculo no contempla, pedí un riesgo mayor: queda el más
                  alto de los dos. El pedido a mano se mantiene aunque se corrijan los datos, hasta que lo vuelvas a «Según el cálculo».
                </Typography>
                <Box sx={GRILLA}>
                  <TextField
                    select
                    size="small"
                    label="Riesgo pedido a mano"
                    value={form.nivel_riesgo_manual}
                    onChange={(ev) => set("nivel_riesgo_manual", ev.target.value)}
                    disabled={!canEditar || !legajo}
                    helperText={legajo ? `Riesgo final: ${riesgo.label}` : "Se calcula al guardar"}
                    fullWidth
                    SelectProps={{ displayEmpty: true }}
                    InputLabelProps={{ shrink: true }}
                  >
                    <MenuItem value="">Según el cálculo</MenuItem>
                    {riesgosPosibles("BAJO").map(([k, v]) => (
                      <MenuItem key={k} value={k}>
                        {v.label}
                      </MenuItem>
                    ))}
                  </TextField>
                </Box>
                <FieldHint
                  label="Observaciones"
                  value={form.observaciones}
                  onChange={(ev) => set("observaciones", ev.target.value.slice(0, 1000))}
                  hint="Notas internas del análisis. Ej: se verificó el origen con la escritura de venta del inmueble anterior"
                  multiline
                  minRows={2}
                  disabled={!canEditar}
                  fullWidth
                />
              </Stack>
            </Seccion>

            <DocumentosLegajo
              clienteId={clienteId}
              documentos={legajo?.documentos}
              tipoSugerido={tipoSugerido(legajo)}
              puedeEditar={canEditar}
              onCambio={() => queryClient.invalidateQueries({ queryKey: CLAVE_CUMPLIMIENTO })}
            />
          </Stack>

          {/* ── Columna lateral: qué falta, operaciones, inusuales y archivo ── */}
          <Stack spacing={2} sx={{ flex: "1 1 320px", minWidth: 0 }}>
            {!legajo ? (
              <Alert severity="info" icon={<Icon icon="mdi:folder-plus-outline" />}>
                Este cliente todavía no tiene legajo. Completá los datos y guardalo (o subí un documento) para crearlo.
              </Alert>
            ) : faltantes.length ? (
              <Box data-testid="legajo-faltantes">
                <PrereqChecklist
                  title="Para aprobar falta"
                  items={faltantes.map((f, i) => ({ key: `f${i}`, label: capitalizar(f), ok: false }))}
                />
                {sucio && (
                  <Typography variant="caption" color="text.secondary" component="div" sx={{ mt: 0.5 }}>
                    La lista se actualiza al guardar.
                  </Typography>
                )}
              </Box>
            ) : (
              <Alert severity="success" icon={<Icon icon="mdi:check-circle-outline" />} data-testid="legajo-faltantes">
                {legajo.estado === "APROBADO" ? "Tiene todo lo que pide la norma." : "Tiene todo lo necesario: ya se puede aprobar."}
              </Alert>
            )}

            <Seccion titulo="Operaciones del cliente" icon="mdi:file-sign">
              {(data.operaciones ?? []).length ? (
                <Stack spacing={0.75}>
                  {(todasLasOperaciones ? data.operaciones : data.operaciones.slice(0, OPERACIONES_VISIBLES)).map((o) => {
                    const e = chipDe(INM_OPERACION_ESTADOS, o.estado);
                    return (
                      <Stack key={o.id} direction="row" spacing={1} alignItems="center" flexWrap="wrap" useFlexGap>
                        <Link component={RouterLink} to={`/inmobiliario/operaciones/${o.id}`} underline="hover" fontWeight={600}>
                          {o.numero}
                        </Link>
                        <Chip size="small" color={e.color} label={e.label} />
                        <Typography variant="caption" color="text.secondary" sx={{ ml: "auto" }}>
                          {o.fecha_boleto ? `Boleto ${fmtFechaCalendario(o.fecha_boleto)}` : `Reserva ${fmtFechaCalendario(o.fecha_reserva)}`}
                        </Typography>
                      </Stack>
                    );
                  })}
                  {data.operaciones.length > OPERACIONES_VISIBLES && (
                    <Box>
                      <Button size="small" onClick={() => setTodasLasOperaciones((v) => !v)}>
                        {todasLasOperaciones ? "Ver menos" : `Ver las ${data.operaciones.length} operaciones`}
                      </Button>
                    </Box>
                  )}
                </Stack>
              ) : (
                <Typography variant="body2" color="text.secondary">
                  Sin operaciones inmobiliarias.
                </Typography>
              )}
            </Seccion>

            <Seccion
              titulo="Operaciones inusuales"
              icon="mdi:alert-decagram-outline"
              acciones={
                canCrearInusual && (
                  <Tooltip title="Registrar una operación inusual de este cliente" enterDelay={300}>
                    <Button size="small" startIcon={<Icon icon="mdi:alert-plus-outline" />} onClick={() => setInusualAbierta(true)}>
                      Registrar
                    </Button>
                  </Tooltip>
                )
              }
            >
              {(data.inusuales ?? []).length ? (
                <Stack spacing={0.75}>
                  {data.inusuales.map((i) => {
                    const r = chipDe(INUSUAL_REGLA, i.regla);
                    const e = chipDe(INUSUAL_ESTADO, i.estado);
                    return (
                      <Stack key={i.id} direction="row" spacing={1} alignItems="center" flexWrap="wrap" useFlexGap>
                        <Typography variant="body2" fontWeight={600}>
                          {i.numero}
                        </Typography>
                        <Chip size="small" variant="outlined" color={r.color} label={r.label} />
                        <Chip size="small" color={e.color} label={e.label} />
                        <Typography variant="caption" color="text.secondary" sx={{ ml: "auto" }}>
                          {fmtFechaCalendario(i.fecha)}
                        </Typography>
                      </Stack>
                    );
                  })}
                  {canVerInusuales && (
                    <Link component={RouterLink} to="/inmobiliario/cumplimiento?tab=inusuales&abiertas=no" underline="hover" variant="caption">
                      Ver el registro de operaciones inusuales
                    </Link>
                  )}
                </Stack>
              ) : (
                <Typography variant="body2" color="text.secondary">
                  Ninguna registrada.
                </Typography>
              )}
            </Seccion>

            <Seccion titulo="Archivo" icon="mdi:archive-lock-outline">
              <Box sx={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(min(100%, 140px), 1fr))", gap: 1.5 }}>
                <Dato label="Última actividad">{data.ultima_actividad ? fmtFechaCalendario(data.ultima_actividad) : null}</Dato>
                <Dato label="Conservar hasta">{data.conservar_hasta ? fmtFechaCalendario(data.conservar_hasta) : null}</Dato>
                <Dato label="Vigencia al aprobar">{vigencia}</Dato>
              </Box>
              <Typography variant="caption" color="text.secondary" component="div" sx={{ mt: 1 }}>
                El legajo y sus documentos se conservan 5 años desde la última operación o cobro del cliente.
              </Typography>
            </Seccion>
          </Stack>
        </Box>

        {/* ── Barra de acciones pegada al pie ── */}
        {canEditar && (
          <Paper
            elevation={6}
            square
            sx={{
              position: "sticky",
              bottom: 0,
              zIndex: 5,
              mx: { xs: -2, md: -3 },
              px: { xs: 2, md: 3 },
              py: 1.25,
              borderTop: 1,
              borderColor: "divider",
              display: "flex",
              alignItems: "center",
              gap: 1,
              flexWrap: "wrap",
            }}
          >
            <Typography variant="body2" color={sucio ? "warning.main" : "text.secondary"} sx={{ flex: "1 1 200px" }}>
              {sucio ? "Tenés cambios sin guardar." : legajo ? "Sin cambios." : "Todavía no se guardó."}
            </Typography>
            {legajo && (
              <Button onClick={() => setForm(formDesde(legajo))} disabled={!sucio || guardando}>
                Descartar cambios
              </Button>
            )}
            <Button
              variant="contained"
              startIcon={<Icon icon="mdi:content-save-outline" />}
              onClick={guardar}
              disabled={guardando || !hayCambios}
            >
              {guardando ? "Guardando…" : "Guardar legajo"}
            </Button>
          </Paper>
        )}
      </Stack>

      <RegistrarInusualDialog
        open={inusualAbierta}
        onClose={() => setInusualAbierta(false)}
        clienteInicial={cliente.id ? { id: cliente.id, nombre: cliente.nombre, documento: cliente.documento } : null}
        onGuardado={() => queryClient.invalidateQueries({ queryKey: CLAVE_CUMPLIMIENTO })}
      />
      {dialogs}
    </Box>
  );
}

export default InmLegajoCliente;
