import {
  Add, ArrowDownward, ArrowUpward, WarningAmber,
} from "@mui/icons-material";
import { Icon } from "@iconify/react";
import {
  Button,
  Checkbox,
  CircularProgress,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  FormControl,
  FormHelperText,
  InputLabel,
  ListItemText,
  MenuItem,
  Select,
  TextField,
  ToggleButton,
  ToggleButtonGroup,
  Typography,
} from "@mui/material";
import PropTypes from "prop-types";
import { useEffect, useRef, useState } from "react";
import * as XLSX from "xlsx";
import styled from "styled-components";
import { MonedaInput } from "../common/MonedaInput";
import {
  useAnularChequeMutation,
  useCreateTesChequeMutation,
  useDebitarChequeMutation,
  useDeleteChequeMutation,
  useDeshacerDepositoChequeMutation,
  useDepositarChequeMutation,
  useDevolverChequeMutation,
  useRechazarChequeMutation,
  useTesChequeQuery,
  useTesBancosQuery,
  useTesCuentasQuery,
  useUpdateTesChequeMutation,
} from "../../tanstack/TesoreriaStack";
import { fmtFechaCalendario, hoyISO } from "../../utils/fecha";
import {
  BancoSelect,
  EmptyState,
  EstadoChip,
  ScreenGuia,
  TES_CHEQUE_ESTADO,
  TES_CHEQUE_ESTADO_META,
  fmtMoneda,
  sanitizeRecords,
} from "../_standards";

// ── helpers ──────────────────────────────────────────────────────────────────

const fmtMonto = (n, moneda) => fmtMoneda(n, moneda || "PYG");

const monedaDe = (c) => c.cuenta?.moneda || c.moneda || "PYG";

/**
 * Los totales se agrupan por moneda. Sumarlo todo en un solo número daba un
 * importe que no existe: un cheque en dólares se sumaba como si fueran
 * guaraníes y el resultado se rotulaba "Gs.".
 */
const totalesPorMoneda = (lista) => {
  const acc = {};
  for (const c of lista) {
    const m = monedaDe(c);
    acc[m] = (acc[m] ?? 0) + Number(c.monto || 0);
  }
  return acc;
};

const fmtTotales = (totales) => {
  const entradas = Object.entries(totales);
  if (entradas.length === 0) return fmtMoneda(0);
  return entradas.map(([m, v]) => fmtMoneda(v, m)).join(" · ");
};

const fmtFecha = (val) => fmtFechaCalendario(val);

const diasHastaVencer = (fecha) => {
  if (!fecha) return null;
  const hoy = new Date(); hoy.setHours(0, 0, 0, 0);
  const venc = new Date(fecha); venc.setHours(0, 0, 0, 0);
  return Math.ceil((venc - hoy) / (1000 * 60 * 60 * 24));
};

const ESTADO_CHEQUE_MAP = TES_CHEQUE_ESTADO_META;

// Estados que se pueden filtrar en cada vista. Por defecto se excluye el estado
// "cerrado sin efecto" (devuelto al cliente / anulado): no aporta en el día a día
// y ensuciaba el Excel. Se puede volver a tildar desde el filtro.
const ESTADOS_FILTRO = {
  RECIBIDO: [
    TES_CHEQUE_ESTADO.EN_CARTERA,
    TES_CHEQUE_ESTADO.DIFERIDO,
    TES_CHEQUE_ESTADO.DEPOSITADO,
    TES_CHEQUE_ESTADO.RECHAZADO,
    TES_CHEQUE_ESTADO.DEVUELTO,
    TES_CHEQUE_ESTADO.ANULADO,
  ],
  EMITIDO: [
    TES_CHEQUE_ESTADO.EN_CARTERA,
    TES_CHEQUE_ESTADO.DIFERIDO,
    TES_CHEQUE_ESTADO.DEBITADO,
    TES_CHEQUE_ESTADO.RECHAZADO,
    TES_CHEQUE_ESTADO.DEVUELTO,
    TES_CHEQUE_ESTADO.ANULADO,
  ],
};
const ESTADOS_OCULTOS_POR_DEFECTO = [TES_CHEQUE_ESTADO.DEVUELTO, TES_CHEQUE_ESTADO.ANULADO];
const estadosPorDefecto = (tipo) => ESTADOS_FILTRO[tipo].filter((e) => !ESTADOS_OCULTOS_POR_DEFECTO.includes(e));

const todayStr = () => hoyISO();

const FORM_VACIO = {
  tipo: "RECIBIDO",
  numero_cheque: "",
  banco_emisor: "",
  cuenta_bancaria_origen: "",
  titular: "",
  monto: 0,
  moneda: "PYG",
  fecha_emision: todayStr(),
  fecha_vencimiento: "",
  cuenta_id: "",
  referencia: "",
};

const exportarExcel = (datos, tipoVista) => {
  const rows = datos.map(c => ({
    "Nº Cheque": c.numero_cheque || "",
    "Banco": c.banco_emisor || "",
    [tipoVista === "RECIBIDO" ? "Titular / Emisor" : "Beneficiario"]: c.titular || "",
    "Monto": Number(c.monto || 0),
    "Moneda": c.moneda || "PYG",
    "Fecha Emisión": fmtFecha(c.fecha_emision),
    "Fecha Vencimiento": fmtFecha(c.fecha_vencimiento),
    "Estado": ESTADO_CHEQUE_MAP[c.estado]?.label || c.estado,
    "Cuenta": c.cuenta?.nombre || "",
    "Referencia": c.referencia || "",
    "Motivo": c.motivo || "",
  }));
  const ws = XLSX.utils.json_to_sheet(sanitizeRecords(rows));
  const wb = XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(wb, ws, "Cheques");
  XLSX.writeFile(wb, `cheques_${tipoVista.toLowerCase()}_${hoyISO()}.xlsx`);
};

// ── componente principal ──────────────────────────────────────────────────────

export const TesChequesTab = () => {
  const [tipoVista, setTipoVista] = useState("RECIBIDO");
  const [filtroEstados, setFiltroEstados] = useState(() => estadosPorDefecto("RECIBIDO"));
  const [filtroCuenta, setFiltroCuenta] = useState("");
  const [busqueda, setBusqueda] = useState("");
  const [campoFecha, setCampoFecha] = useState("fecha_emision");
  const [fechaDesde, setFechaDesde] = useState("");
  const [fechaHasta, setFechaHasta] = useState("");
  const [page, setPage] = useState(1);
  const PAGE_SIZE = 20;

  const [modalRegistrar, setModalRegistrar] = useState(false);
  const [form, setForm] = useState(FORM_VACIO);

  const [modalAccion, setModalAccion] = useState(null);
  const [accionData, setAccionData] = useState({ cuenta_id: "", motivo: "", referencia: "", fecha_movimiento: "" });

  const [modalEditar, setModalEditar] = useState(null);
  const [editForm, setEditForm] = useState(null);

  const params = {
    tipo: tipoVista,
    ...(filtroCuenta && { cuenta_id: filtroCuenta }),
  };
  const { data: chequesRawAll = [], isLoading } = useTesChequeQuery(params);

  const campoFechaKey = campoFecha === "recepcion" ? "created_at" : campoFecha;
  const inRange = (val) => {
    if (!fechaDesde && !fechaHasta) return true;
    if (!val) return false;
    const d = String(val).slice(0, 10);
    if (fechaDesde && d < fechaDesde) return false;
    if (fechaHasta && d > fechaHasta) return false;
    return true;
  };
  const q = busqueda.trim().toLowerCase();
  // Por si llega un estado que no está en la lista: que se pueda tildar igual.
  const opcionesEstado = [...new Set([...ESTADOS_FILTRO[tipoVista], ...chequesRawAll.map(c => c.estado).filter(Boolean)])];
  const chequesRaw = chequesRawAll.filter(c =>
    filtroEstados.includes(c.estado) &&
    inRange(c[campoFechaKey]) &&
    (!q ||
      (c.titular || "").toLowerCase().includes(q) ||
      (c.numero_cheque || "").toLowerCase().includes(q) ||
      (c.banco_emisor || "").toLowerCase().includes(q))
  );
  const totalPages = Math.max(1, Math.ceil(chequesRaw.length / PAGE_SIZE));
  const pageSafe = Math.min(page, totalPages);
  const chequesPagina = chequesRaw.slice((pageSafe - 1) * PAGE_SIZE, pageSafe * PAGE_SIZE);
  const { data: cuentasData } = useTesCuentasQuery();
  const cuentas = Array.isArray(cuentasData) ? cuentasData : (cuentasData?.data || []);
  const cuentasActivas = cuentas.filter(c => c.activo !== false);
  const { data: bancosData } = useTesBancosQuery();
  const bancos = Array.isArray(bancosData) ? bancosData : (bancosData?.data || []);

  // Un cheque emitido se libra contra una cuenta propia, así que el banco y el
  // número de cuenta salen de ahí: no tiene sentido volver a tipearlos. Sólo en
  // los recibidos el banco es un dato externo (el del cliente).
  const cuentaSeleccionada = cuentas.find(c => c.id === form.cuenta_id) || null;
  const bancoDeCuenta = cuentaSeleccionada
    ? bancos.find(b => b.id === cuentaSeleccionada.banco_id)?.descripcion || null
    : null;
  const esEmitido = tipoVista === "EMITIDO";

  // ── KPIs ──
  const porEstado = (estado) => chequesRaw.filter(c => c.estado === estado);

  const enCartera = porEstado("EN_CARTERA");
  const diferidos = porEstado("DIFERIDO");
  const depositados = porEstado("DEPOSITADO");
  const debitados = porEstado("DEBITADO");

  // EN_CARTERA con fecha pasada = ya se podía cobrar y sigue sin acreditarse.
  // Es el caso que hay que mirar; un DIFERIDO con fecha futura está bien así.
  const vencidosSinAcreditar = enCartera.filter(c => {
    const dias = diasHastaVencer(c.fecha_vencimiento);
    return dias !== null && dias < 0;
  });
  const proxVencer = enCartera.filter(c => {
    const dias = diasHastaVencer(c.fecha_vencimiento);
    return dias !== null && dias >= 0 && dias <= 3;
  });
  // Diferidos que el sistema habilita solo en los próximos días.
  const proxHabilitar = diferidos
    .filter(c => {
      const dias = diasHastaVencer(c.fecha_vencimiento);
      return dias !== null && dias >= 0 && dias <= 7;
    })
    .sort((a, b) => String(a.fecha_vencimiento).localeCompare(String(b.fecha_vencimiento)));

  // ── Mutaciones ──
  const createCheque = useCreateTesChequeMutation();
  // Cheque que el backend marcó como posible duplicado, para confirmar o corregir.
  const [duplicado, setDuplicado] = useState(null);
  const depositar = useDepositarChequeMutation();
  const debitar = useDebitarChequeMutation();
  const rechazar = useRechazarChequeMutation();
  const devolver = useDevolverChequeMutation();
  const anular = useAnularChequeMutation();
  const eliminar = useDeleteChequeMutation();
  const deshacerDeposito = useDeshacerDepositoChequeMutation();
  const editarCheque = useUpdateTesChequeMutation();

  const setF = (k, v) => setForm(f => ({ ...f, [k]: v }));

  const handleRegistrar = async () => {
    if (!form.numero_cheque.trim() || !form.monto || !form.fecha_emision) return;
    if (esEmitido && !form.cuenta_id) return;
    const payload = {
      ...form,
      tipo: tipoVista,
      monto: Number(form.monto),
      cuenta_id: form.cuenta_id || undefined,
      fecha_vencimiento: form.fecha_vencimiento || undefined,
      banco_emisor: form.banco_emisor || undefined,
      cuenta_bancaria_origen: form.cuenta_bancaria_origen || undefined,
      titular: form.titular || undefined,
      referencia: form.referencia || undefined,
    };
    try {
      await createCheque.mutateAsync(payload);
    } catch (e) {
      // 409 = ya hay un cheque vivo con ese número y banco. No se bloquea: se
      // muestra cuál es y el usuario decide, porque dos bancos distintos pueden
      // repetir número.
      if (e?.response?.status === 409 && e.response.data?.codigo === "CHEQUE_DUPLICADO") {
        setDuplicado({ mensaje: e.response.data.message, cheque: e.response.data.cheque_existente, payload });
        return;
      }
      return;
    }
    setModalRegistrar(false);
    setForm(FORM_VACIO);
  };

  /** El usuario confirmó que es otro cheque distinto: se crea igual. */
  const handleConfirmarDuplicado = async () => {
    try {
      await createCheque.mutateAsync({ ...duplicado.payload, confirmar_duplicado: true });
      setDuplicado(null);
      setModalRegistrar(false);
      setForm(FORM_VACIO);
    } catch {
      setDuplicado(null);
    }
  };

  const handleAccion = async () => {
    const { tipo, cheque } = modalAccion;
    const id = cheque.id;
    if (tipo === "depositar") await depositar.mutateAsync({ id, data: { cuenta_id: accionData.cuenta_id, fecha_movimiento: accionData.fecha_movimiento || undefined, referencia: accionData.referencia || undefined } });
    else if (tipo === "debitar") await debitar.mutateAsync({ id, data: { cuenta_id: accionData.cuenta_id, fecha_movimiento: accionData.fecha_movimiento || undefined, referencia: accionData.referencia || undefined } });
    else if (tipo === "rechazar") await rechazar.mutateAsync({ id, data: { motivo: accionData.motivo } });
    else if (tipo === "devolver") await devolver.mutateAsync({ id, data: { motivo: accionData.motivo } });
    else if (tipo === "anular") await anular.mutateAsync({ id, data: { motivo: accionData.motivo } });
    else if (tipo === "eliminar") await eliminar.mutateAsync(id);
      else if (tipo === "deshacer") await deshacerDeposito.mutateAsync(id);
    setModalAccion(null);
    setAccionData({ cuenta_id: "", motivo: "", referencia: "", fecha_movimiento: "" });
  };

  const toDateInput = (v) => (v ? String(v).slice(0, 10) : "");

  // Fecha de hoy en YYYY-MM-DD según el calendario LOCAL del usuario, no
  // toISOString() (que es UTC): en Paraguay (UTC-3), toISOString() ya cruzó
  // al día siguiente antes de medianoche local, y correría "hoy" un día para
  // adelante en el límite `max` del input de fecha.
  const hoyInput = () => {
    const d = new Date();
    return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
  };

  const openAccion = (tipo, cheque) => {
    setAccionData({
      cuenta_id: cheque.cuenta_id || "",
      motivo: "",
      referencia: "",
      fecha_movimiento: hoyInput(),
    });
    setModalAccion({ tipo, cheque });
  };

  const openEditar = (cheque) => {
    setEditForm({
      numero_cheque: cheque.numero_cheque || "",
      banco_emisor: cheque.banco_emisor || "",
      cuenta_bancaria_origen: cheque.cuenta_bancaria_origen || "",
      titular: cheque.titular || "",
      fecha_emision: toDateInput(cheque.fecha_emision),
      fecha_vencimiento: toDateInput(cheque.fecha_vencimiento),
      referencia: cheque.referencia || "",
      monto: Number(cheque.monto) || 0,
      motivo: "",
    });
    setModalEditar(cheque);
  };

  const handleGuardarEdicion = async () => {
    if (!editForm?.motivo?.trim()) return;
    const original = modalEditar;
    const payload = { motivo: editForm.motivo.trim() };
    const campos = [
      "numero_cheque", "banco_emisor", "cuenta_bancaria_origen",
      "titular", "fecha_emision", "fecha_vencimiento", "referencia",
    ];
    for (const k of campos) {
      const nuevo = editForm[k];
      const viejo = k === "fecha_emision" || k === "fecha_vencimiento"
        ? toDateInput(original[k])
        : (original[k] || "");
      if ((nuevo || "") !== (viejo || "")) {
        payload[k] = nuevo === "" ? null : nuevo;
      }
    }
    if (!original.origen_tipo && Number(editForm.monto) !== Number(original.monto)) {
      payload.monto = Number(editForm.monto);
    }
    if (Object.keys(payload).length === 1) {
      // sólo motivo → nada cambió
      setModalEditar(null);
      setEditForm(null);
      return;
    }
    await editarCheque.mutateAsync({ id: original.id, data: payload });
    setModalEditar(null);
    setEditForm(null);
  };

  const isPendingAccion = depositar.isPending || debitar.isPending || rechazar.isPending || devolver.isPending || anular.isPending || eliminar.isPending;

  const isActiva = (c) => c.estado === "EN_CARTERA" || c.estado === "DIFERIDO";

  // Un cheque diferido no se puede presentar al banco antes de su fecha: el
  // backend lo rechaza. Ofrecer igual la acción y que falle después es peor que
  // no ofrecerla, así que el menú replica exactamente esa regla.
  const esOperable = (c) => {
    if (c.estado === "EN_CARTERA") return true;
    if (c.estado !== "DIFERIDO") return false;
    const dias = diasHastaVencer(c.fecha_vencimiento);
    return dias === null || dias <= 0;
  };

  return (
    <Container>
      {/* Header */}
      <Header>
        <div>
          <Typography variant="h6" fontWeight={600}>Cheques</Typography>
          <Typography variant="body2" sx={{ opacity: 0.55, mt: 0.3 }}>
            {tipoVista === "RECIBIDO" ? "Cheques recibidos de clientes o terceros" : "Cheques propios emitidos a proveedores"}
          </Typography>
        </div>
        <Button variant="contained" startIcon={<Add />} onClick={() => { setForm({ ...FORM_VACIO, tipo: tipoVista }); setModalRegistrar(true); }}>
          Registrar cheque
        </Button>
      </Header>

      <ScreenGuia
        moduloPadre="Tesorería"
        titulo="Cheques"
        intro="La cartera de cheques recibidos y emitidos. Un cheque no es plata en la cuenta hasta que el banco lo acredita o lo debita: recién ahí se genera el movimiento."
        pasos={[
          { icon: "lucide:clock", color: "#38bdf8", titulo: "Diferido",
            desc: "Cheque a fecha. Todavía no se puede depositar ni debitar." },
          { icon: "lucide:wallet", color: "#f59e0b", titulo: "En cartera",
            desc: "Ya llegó su fecha (o no tiene). Se puede presentar al banco." },
          { icon: "lucide:building-2", color: "#22c55e", titulo: "Depositado / Debitado",
            desc: "El banco lo acreditó o lo debitó. Se genera el movimiento de tesorería y cambia el saldo." },
          { icon: "lucide:x-circle", color: "#ef4444", titulo: "Rechazado / Anulado",
            desc: "Si ya había movido el saldo, se genera una reversa automática. No se edita el movimiento a mano." },
        ]}
        configuracion={[
          { label: "Depositar / Debitar: el banco lo movió → crea el movimiento", color: "success" },
          { label: "Rechazar / Anular: el banco lo devolvió → crea la reversa (egreso)", color: "error" },
          { label: "Deshacer depósito: se cargó por error → anula el movimiento, sin reversa", color: "warning" },
          { label: "Devolver: se lo devolvés al cliente, nunca se depositó → no mueve saldo", color: "default" },
          { label: "Eliminar: borra el registro, sólo si está en cartera", color: "default" },
        ]}
        notas={[
          { icon: "lucide:refresh-cw",
            text: "Los cheques diferidos pasan solos a «En cartera» el día de su vencimiento: una tarea automática los revisa cada día a las 06:00 y también cada vez que arranca el sistema. No hay que cambiarlos a mano." },
          { icon: "lucide:shield",
            text: "El movimiento que genera un cheque no se puede anular desde Movimientos. Para revertirlo hay que rechazar o anular el cheque acá, y así se corrigen la cartera y el saldo juntos." },
          { icon: "lucide:landmark",
            text: "En los cheques emitidos, el banco sale de la cuenta contra la que se libra el cheque; por eso la cuenta es obligatoria y no se puede debitar desde otra." },
          { icon: "lucide:rotate-ccw",
            text: "«Rechazar» y «Deshacer depósito» no son lo mismo. Si el banco rechazó el cheque, usá Rechazar: hubo plata que entró y después salió, y el extracto tiene que mostrar las dos. Si el depósito nunca ocurrió y fue un error de carga, usá Deshacer depósito: el movimiento queda anulado, deja de sumar al saldo y no aparece ningún egreso que el banco no tuvo." },
          { icon: "lucide:copy",
            text: "Si cargás un cheque con el mismo número y banco que otro que sigue vivo, el sistema avisa y te muestra cuál es antes de duplicarlo." },
        ]}
      />

      {/* Toggle Recibidos/Emitidos */}
      <ToggleWrap>
        <ToggleButtonGroup value={tipoVista} exclusive onChange={(_, v) => { if (v) { setTipoVista(v); setFiltroEstados(estadosPorDefecto(v)); } }} size="small">
          <ToggleButton value="RECIBIDO">
            <ArrowDownward fontSize="small" sx={{ mr: 0.5, color: "#22c55e" }} />
            Recibidos
          </ToggleButton>
          <ToggleButton value="EMITIDO">
            <ArrowUpward fontSize="small" sx={{ mr: 0.5, color: "#ef4444" }} />
            Emitidos
          </ToggleButton>
        </ToggleButtonGroup>
      </ToggleWrap>

      {/* Resumen */}
      {!isLoading && chequesRaw.length > 0 && (
        <ResumenBar>
          <ResumenItem>
            <ResumenLabel>En cartera (al día)</ResumenLabel>
            <ResumenValor>{enCartera.length} cheques</ResumenValor>
            <ResumenDetalle>{fmtTotales(totalesPorMoneda(enCartera))}</ResumenDetalle>
          </ResumenItem>
          {diferidos.length > 0 && (
            <ResumenItem>
              <ResumenLabel>Diferidos (a fecha)</ResumenLabel>
              <ResumenValor>{diferidos.length} cheques</ResumenValor>
              <ResumenDetalle>{fmtTotales(totalesPorMoneda(diferidos))}</ResumenDetalle>
            </ResumenItem>
          )}
          {tipoVista === "RECIBIDO" && depositados.length > 0 && (
            <ResumenItem>
              <ResumenLabel>Depositados</ResumenLabel>
              <ResumenValor>{depositados.length} cheques</ResumenValor>
              <ResumenDetalle>{fmtTotales(totalesPorMoneda(depositados))}</ResumenDetalle>
            </ResumenItem>
          )}
          {tipoVista === "EMITIDO" && debitados.length > 0 && (
            <ResumenItem>
              <ResumenLabel>Debitados</ResumenLabel>
              <ResumenValor>{debitados.length} cheques</ResumenValor>
              <ResumenDetalle>{fmtTotales(totalesPorMoneda(debitados))}</ResumenDetalle>
            </ResumenItem>
          )}
          {vencidosSinAcreditar.length > 0 && (
            <ResumenItem $alerta>
              <ResumenLabel>Vencidos sin acreditar</ResumenLabel>
              <ResumenValor $alerta>{vencidosSinAcreditar.length} cheque{vencidosSinAcreditar.length > 1 ? "s" : ""}</ResumenValor>
              <ResumenDetalle>{fmtTotales(totalesPorMoneda(vencidosSinAcreditar))}</ResumenDetalle>
            </ResumenItem>
          )}
        </ResumenBar>
      )}

      {/* Banner: requiere acción — ya se podían cobrar y siguen sin acreditarse */}
      {vencidosSinAcreditar.length > 0 && (
        <AlertaBanner>
          <WarningAmber fontSize="small" />
          <span>
            <strong>{vencidosSinAcreditar.length} cheque{vencidosSinAcreditar.length > 1 ? "s" : ""}</strong>
            {" "}pasó{vencidosSinAcreditar.length > 1 ? "ron" : ""} su fecha y sigue{vencidosSinAcreditar.length > 1 ? "n" : ""} sin{" "}
            {tipoVista === "RECIBIDO" ? "depositar" : "debitar"}. Revisá el extracto del banco.
          </span>
        </AlertaBanner>
      )}
      {proxVencer.length > 0 && (
        <AlertaBanner>
          <WarningAmber fontSize="small" />
          <span>
            <strong>{proxVencer.length} cheque{proxVencer.length > 1 ? "s" : ""}</strong> en cartera llega{proxVencer.length > 1 ? "n" : ""} a su fecha en los próximos 3 días.
            {" "}Ya {proxVencer.length > 1 ? "se pueden" : "se puede"} presentar al banco.
          </span>
        </AlertaBanner>
      )}

      {/* Banner informativo: el sistema los habilita solo, no hay que hacer nada */}
      {proxHabilitar.length > 0 && (
        <InfoBanner>
          <Icon icon="lucide:clock" width={16} />
          <span>
            <strong>{proxHabilitar.length} cheque{proxHabilitar.length > 1 ? "s" : ""} diferido{proxHabilitar.length > 1 ? "s" : ""}</strong>
            {" "}se habilita{proxHabilitar.length > 1 ? "n" : ""} en los próximos días — el primero el{" "}
            {fmtFecha(proxHabilitar[0].fecha_vencimiento)}. El sistema los pasa solo a <em>En cartera</em>;
            no hay que tocar nada.
          </span>
        </InfoBanner>
      )}

      {/* Filtros */}
      <FiltersBar>
        <TextField
          label="Buscar"
          size="small"
          placeholder="Titular, número, banco..."
          value={busqueda}
          onChange={e => { setBusqueda(e.target.value); setPage(1); }}
          sx={{ flex: "1 1 200px", minWidth: 180 }}
        />
        <FormControl size="small" sx={{ flex: "1 1 170px", minWidth: 150 }}>
          <InputLabel>Estados</InputLabel>
          <Select
            multiple
            value={filtroEstados}
            label="Estados"
            onChange={e => {
              const v = e.target.value;
              setFiltroEstados(typeof v === "string" ? v.split(",") : v);
              setPage(1);
            }}
            renderValue={(sel) =>
              opcionesEstado.every(e => sel.includes(e))
                ? "Todos"
                : sel.length === 0
                  ? "Ninguno"
                  : sel.map(e => ESTADO_CHEQUE_MAP[e]?.label || e).join(", ")
            }
          >
            {opcionesEstado.map(e => (
              <MenuItem key={e} value={e} dense>
                <Checkbox size="small" checked={filtroEstados.includes(e)} />
                <ListItemText primary={ESTADO_CHEQUE_MAP[e]?.label || e} />
              </MenuItem>
            ))}
          </Select>
        </FormControl>
        <FormControl size="small" sx={{ flex: "1 1 140px", minWidth: 130 }}>
          <InputLabel>Cuenta</InputLabel>
          <Select value={filtroCuenta} label="Cuenta" onChange={e => { setFiltroCuenta(e.target.value); setPage(1); }}>
            <MenuItem value="">Todas</MenuItem>
            {/* Incluye las cerradas: puede haber cheques históricos asociados a
                ellas y su historial se tiene que poder filtrar. */}
            {cuentas.map(c => (
              <MenuItem key={c.id} value={c.id}>
                {c.nombre}{c.activo === false ? " (inactiva)" : ""}
              </MenuItem>
            ))}
          </Select>
        </FormControl>
        <FormControl size="small" sx={{ flex: "1 1 130px", minWidth: 120 }}>
          <InputLabel>Filtrar fecha</InputLabel>
          <Select value={campoFecha} label="Filtrar fecha" onChange={e => { setCampoFecha(e.target.value); setPage(1); }}>
            <MenuItem value="fecha_emision">Emisión</MenuItem>
            <MenuItem value="fecha_vencimiento">Vencimiento</MenuItem>
            <MenuItem value="recepcion">Recepción</MenuItem>
          </Select>
        </FormControl>
        <TextField
          label="Desde"
          type="date"
          size="small"
          value={fechaDesde}
          onChange={e => { setFechaDesde(e.target.value); setPage(1); }}
          InputLabelProps={{ shrink: true }}
          sx={{ width: 145 }}
        />
        <TextField
          label="Hasta"
          type="date"
          size="small"
          value={fechaHasta}
          onChange={e => { setFechaHasta(e.target.value); setPage(1); }}
          InputLabelProps={{ shrink: true }}
          sx={{ width: 145 }}
        />
        <Button variant="outlined" size="small"
          onClick={() => exportarExcel(chequesRaw, tipoVista)}
          disabled={chequesRaw.length === 0}
          sx={{ whiteSpace: "nowrap" }}>
          Excel
        </Button>
      </FiltersBar>

      {/* Desktop: tabla con scroll horizontal */}
      <TableWrap className="desktop-table">
        <ScrollX>
          <StyledTable>
            <thead>
              <tr>
                <Th>N° Cheque</Th>
                <Th>Banco</Th>
                <Th>{tipoVista === "RECIBIDO" ? "Titular / Emisor" : "Beneficiario"}</Th>
                <Th style={{ textAlign: "right" }}>Monto</Th>
                <Th>Emisión</Th>
                <Th>Vencimiento</Th>
                <Th>Estado</Th>
                <Th>Acciones</Th>
              </tr>
            </thead>
            <tbody>
              {isLoading ? (
                <tr><Td colSpan={8} style={{ textAlign: "center", padding: 32 }}><CircularProgress size={24} /></Td></tr>
              ) : chequesPagina.length === 0 ? (
                <tr><Td colSpan={8} style={{ padding: 0 }}>
                  {chequesRawAll.length > 0 || filtroCuenta ? (
                    <EmptyState
                      compact
                      icon="lucide:search-x"
                      title="No hay cheques con estos filtros"
                      description="Probá limpiando el buscador, ampliando el rango de fechas o tildando más estados (los devueltos y anulados no se muestran por defecto)."
                    />
                  ) : (
                    <EmptyState
                      compact
                      icon="lucide:banknote"
                      title={tipoVista === "RECIBIDO" ? "Sin cheques recibidos" : "Sin cheques emitidos"}
                      description={tipoVista === "RECIBIDO"
                        ? "Los cheques que recibís de clientes entran acá y mueven el saldo recién al depositarse."
                        : "Los cheques que librás a proveedores entran acá y descuentan el saldo recién al debitarse."}
                      ctaLabel="Registrar cheque"
                      onCta={() => { setForm({ ...FORM_VACIO, tipo: tipoVista }); setModalRegistrar(true); }}
                    />
                  )}
                </Td></tr>
              ) : chequesPagina.map(c => {
                const moneda = c.cuenta?.moneda || c.moneda || "PYG";
                const dias = c.fecha_vencimiento ? diasHastaVencer(c.fecha_vencimiento) : null;
                const vencido = c.estado === "EN_CARTERA" && dias !== null && dias < 0;
                const proximo = c.estado === "EN_CARTERA" && dias !== null && dias >= 0 && dias <= 3;
                return (
                  <Tr key={c.id}>
                    <Td style={{ whiteSpace: "nowrap" }}><NumCode>{c.numero_cheque}</NumCode></Td>
                    <Td>{c.banco_emisor || <Muted>—</Muted>}</Td>
                    <Td>{c.titular || <Muted>—</Muted>}</Td>
                    <Td style={{ whiteSpace: "nowrap", textAlign: "right" }}>
                      <MontoCell $tipo={tipoVista}>
                        {tipoVista === "RECIBIDO"
                          ? <ArrowDownward sx={{ fontSize: 13 }} />
                          : <ArrowUpward sx={{ fontSize: 13 }} />}
                        {fmtMonto(c.monto, moneda)}
                      </MontoCell>
                    </Td>
                    <Td style={{ whiteSpace: "nowrap" }}>{fmtFecha(c.fecha_emision)}</Td>
                    <Td style={{ whiteSpace: "nowrap" }}>
                      {c.fecha_vencimiento
                        ? <VencCell $vencido={vencido} $proximo={proximo}>
                            {vencido ? `⚠ Vencido (${fmtFecha(c.fecha_vencimiento)})`
                              : proximo ? `⚠ ${dias}d (${fmtFecha(c.fecha_vencimiento)})`
                              : c.estado === "DIFERIDO" && dias !== null && dias > 0
                                ? `Se habilita en ${dias}d (${fmtFecha(c.fecha_vencimiento)})`
                                : fmtFecha(c.fecha_vencimiento)}
                          </VencCell>
                        : <Muted>—</Muted>}
                    </Td>
                    <Td style={{ whiteSpace: "nowrap" }}>
                      <EstadoChip estado={c.estado} customMap={ESTADO_CHEQUE_MAP} />
                    </Td>
                    <Td>
                      <AccionesMenu
                        cheque={c}
                        tipoVista={tipoVista}
                        isActiva={isActiva(c)}
                        esOperable={esOperable(c)}
                        onEditar={() => openEditar(c)}
                        onAccion={(tipo) => openAccion(tipo, c)}
                      />
                    </Td>
                  </Tr>
                );
              })}
            </tbody>
          </StyledTable>
        </ScrollX>

        <Pagination>
          <Typography variant="caption" sx={{ opacity: 0.6 }}>
            Página {pageSafe} de {totalPages} ({chequesRaw.length} registros)
          </Typography>
          <Button size="small" disabled={pageSafe <= 1} onClick={() => setPage(p => p - 1)}>Anterior</Button>
          <Button size="small" disabled={pageSafe >= totalPages} onClick={() => setPage(p => p + 1)}>Siguiente</Button>
        </Pagination>
      </TableWrap>

      {/* ── Modal: Registrar cheque ── */}
      <Dialog open={modalRegistrar} onClose={() => setModalRegistrar(false)} maxWidth="sm" fullWidth>
        <DialogTitle>
          {tipoVista === "RECIBIDO" ? "Registrar cheque recibido" : "Registrar cheque emitido"}
        </DialogTitle>
        <DialogContent>
          <FormGrid>
            {/* En un cheque emitido la cuenta es el dato que manda: define de
                dónde va a salir la plata y de qué banco es el cheque. Por eso va
                primero y es obligatoria. En uno recibido es opcional: la cuenta
                de depósito recién se decide al depositarlo. */}
            <FormControl fullWidth required={esEmitido} sx={{ gridColumn: "1 / -1" }}>
              <InputLabel id="cheque-cuenta-label">
                {esEmitido ? "Cuenta contra la que se libra" : "Cuenta de tesorería"}
              </InputLabel>
              {/* labelId asocia el label con el Select: sin eso el campo no
                  tiene nombre accesible y un lector de pantalla lo anuncia
                  vacío. */}
              <Select value={form.cuenta_id}
                labelId="cheque-cuenta-label"
                label={esEmitido ? "Cuenta contra la que se libra" : "Cuenta de tesorería"}
                onChange={e => setF("cuenta_id", e.target.value)}>
                {!esEmitido && <MenuItem value="">Sin asignar</MenuItem>}
                {cuentasActivas.map(c => <MenuItem key={c.id} value={c.id}>{c.nombre}</MenuItem>)}
              </Select>
              <FormHelperText>
                {esEmitido
                  ? (bancoDeCuenta
                      ? `Banco: ${bancoDeCuenta}${cuentaSeleccionada?.numero_cuenta ? ` — Nº ${cuentaSeleccionada.numero_cuenta}` : ""}. Se debita de esta misma cuenta.`
                      : "El banco del cheque sale de esta cuenta. Si la cuenta no tiene banco asignado, cargalo en Configuración › Cuentas.")
                  : "Opcional. Podés elegirla ahora o recién al depositar el cheque."}
              </FormHelperText>
            </FormControl>

            <TextField label="Número de cheque" required fullWidth value={form.numero_cheque}
              onChange={e => setF("numero_cheque", e.target.value)}
              placeholder="Ej: 001-12345678"
            />
            <TextField
              label={esEmitido ? "Beneficiario" : "Emisor / Titular"}
              fullWidth value={form.titular}
              onChange={e => setF("titular", e.target.value)}
              placeholder={esEmitido ? "A nombre de quién se libra" : "Nombre de quien emite el cheque"}
            />

            {/* En los recibidos el banco es el del cliente: dato externo que hay
                que tipear. En los emitidos se deriva de la cuenta, no se pide. */}
            {!esEmitido && (
              <>
                <BancoSelect
                  label="Banco emisor"
                  value={form.banco_emisor}
                  onChange={v => setF("banco_emisor", v)}
                  size="medium"
                  helperText="El banco del cliente que firma el cheque"
                />
                <TextField label="Nº cuenta bancaria (del cheque)" fullWidth value={form.cuenta_bancaria_origen}
                  onChange={e => setF("cuenta_bancaria_origen", e.target.value)}
                  placeholder="Opcional"
                />
              </>
            )}

            <MonedaInput
              label="Monto *"
              fullWidth
              value={form.monto}
              onChange={v => setF("monto", v)}
              moneda={form.moneda || "PYG"}
            />
            <TextField label="Fecha de emisión" type="date" required fullWidth value={form.fecha_emision}
              onChange={e => setF("fecha_emision", e.target.value)}
              InputLabelProps={{ shrink: true }}
            />
            <TextField label="Fecha de vencimiento" type="date" fullWidth value={form.fecha_vencimiento}
              onChange={e => setF("fecha_vencimiento", e.target.value)}
              InputLabelProps={{ shrink: true }}
              helperText={
                form.fecha_vencimiento && form.fecha_vencimiento > hoyInput()
                  ? `Cheque a fecha: queda en Diferido y se habilita solo el ${fmtFecha(form.fecha_vencimiento)}.`
                  : "Dejala vacía si el cheque es al día."
              }
            />
            <TextField label="Referencia / Nota" fullWidth multiline rows={2} value={form.referencia}
              onChange={e => setF("referencia", e.target.value)}
              placeholder="Ej: Cobro factura 001-002-000123"
              sx={{ gridColumn: "1 / -1" }}
            />
          </FormGrid>
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setModalRegistrar(false)}>Cancelar</Button>
          <Button variant="contained" onClick={handleRegistrar}
            disabled={!form.numero_cheque.trim() || !form.monto || (esEmitido && !form.cuenta_id) || createCheque.isPending}>
            {createCheque.isPending ? <CircularProgress size={18} /> : "Registrar"}
          </Button>
        </DialogActions>
      </Dialog>

      {/* ── Modal: Editar cheque ── */}
      {modalEditar && editForm && (
        <Dialog open onClose={() => { setModalEditar(null); setEditForm(null); }} maxWidth="sm" fullWidth>
          <DialogTitle>Editar cheque Nº {modalEditar.numero_cheque}</DialogTitle>
          <DialogContent>
            <Typography variant="body2" sx={{ mb: 2, opacity: 0.7 }}>
              La cuenta no es editable. El monto se corrige sólo en cheques cargados a mano en Tesorería; si el cheque viene de un recibo, se corrige en el recibo. Cada cambio queda en auditoría con tu usuario y el motivo.
            </Typography>
            <FormGrid>
              <TextField label="Número de cheque" fullWidth size="small" value={editForm.numero_cheque}
                onChange={e => setEditForm(f => ({ ...f, numero_cheque: e.target.value }))} />
              <BancoSelect
                label="Banco emisor"
                value={editForm.banco_emisor}
                onChange={v => setEditForm(f => ({ ...f, banco_emisor: v }))}
              />
              <TextField label={tipoVista === "RECIBIDO" ? "Emisor / Titular" : "Beneficiario"} fullWidth size="small"
                value={editForm.titular}
                onChange={e => setEditForm(f => ({ ...f, titular: e.target.value }))} />
              <TextField label="Nº cuenta bancaria (del cheque)" fullWidth size="small" value={editForm.cuenta_bancaria_origen}
                onChange={e => setEditForm(f => ({ ...f, cuenta_bancaria_origen: e.target.value }))} />
              <MonedaInput
                label="Monto"
                fullWidth
                value={editForm.monto}
                onChange={v => setEditForm(f => ({ ...f, monto: v }))}
                moneda={monedaDe(modalEditar)}
                disabled={Boolean(modalEditar.origen_tipo)}
                helperText={
                  modalEditar.origen_tipo
                    ? "Viene de un recibo u otro documento: el monto se corrige ahí"
                    : "Ej: 2.408.582"
                }
              />
              <TextField label="Fecha de emisión" type="date" fullWidth size="small" value={editForm.fecha_emision}
                onChange={e => setEditForm(f => ({ ...f, fecha_emision: e.target.value }))}
                InputLabelProps={{ shrink: true }} />
              <TextField label="Fecha de vencimiento" type="date" fullWidth size="small" value={editForm.fecha_vencimiento}
                onChange={e => setEditForm(f => ({ ...f, fecha_vencimiento: e.target.value }))}
                InputLabelProps={{ shrink: true }} />
              <TextField label="Referencia / Nota" fullWidth size="small" multiline rows={2}
                value={editForm.referencia}
                onChange={e => setEditForm(f => ({ ...f, referencia: e.target.value }))}
                sx={{ gridColumn: "1 / -1" }} />
              <TextField label="Motivo de la corrección" fullWidth size="small" multiline rows={2} required
                value={editForm.motivo}
                onChange={e => setEditForm(f => ({ ...f, motivo: e.target.value }))}
                placeholder="Ej: fecha de vencimiento mal cargada — corregida según cheque físico"
                helperText="Queda registrado en auditoría"
                sx={{ gridColumn: "1 / -1" }} />
            </FormGrid>
          </DialogContent>
          <DialogActions>
            <Button onClick={() => { setModalEditar(null); setEditForm(null); }}>Cancelar</Button>
            <Button variant="contained"
              onClick={handleGuardarEdicion}
              disabled={!editForm.motivo?.trim() || editarCheque.isPending}>
              {editarCheque.isPending ? <CircularProgress size={18} /> : "Guardar cambios"}
            </Button>
          </DialogActions>
        </Dialog>
      )}

      {/* ── Modal: Acción sobre cheque ── */}
      {modalAccion && (
        <Dialog open onClose={() => setModalAccion(null)} maxWidth="xs" fullWidth>
          <DialogTitle>{ACCION_LABEL[modalAccion.tipo]}</DialogTitle>
          <DialogContent>
            <Typography variant="body2" sx={{ mb: 2, opacity: 0.7 }}>
              {ACCION_DESC[modalAccion.tipo](modalAccion.cheque)}
            </Typography>

            {(modalAccion.tipo === "depositar" || modalAccion.tipo === "debitar") && (
              <>
                {/* Si el cheque ya se registró contra una cuenta, esa es la
                    cuenta. Debitar de otra deja la real con saldo de más y la
                    elegida con saldo de menos, y ninguna concilia contra el
                    extracto. El backend lo rechaza; acá directamente no se ofrece. */}
                <FormControl fullWidth size="small" sx={{ mb: 2 }}
                  disabled={modalAccion.tipo === "debitar" && !!modalAccion.cheque?.cuenta_id}>
                  <InputLabel>Cuenta *</InputLabel>
                  <Select value={accionData.cuenta_id} label="Cuenta *"
                    onChange={e => setAccionData(d => ({ ...d, cuenta_id: e.target.value }))}>
                    {cuentasActivas.map(c => <MenuItem key={c.id} value={c.id}>{c.nombre}</MenuItem>)}
                  </Select>
                  <FormHelperText>
                    {modalAccion.tipo === "debitar" && modalAccion.cheque?.cuenta_id
                      ? "El cheque se libró contra esta cuenta. Se debita de acá."
                      : "Cuenta donde el banco acreditó el cheque."}
                  </FormHelperText>
                </FormControl>
                <TextField
                  label={modalAccion.tipo === "depositar" ? "Fecha del depósito" : "Fecha del débito"}
                  type="date" fullWidth size="small" sx={{ mb: 2 }}
                  InputLabelProps={{ shrink: true }}
                  value={accionData.fecha_movimiento}
                  onChange={e => setAccionData(d => ({ ...d, fecha_movimiento: e.target.value }))}
                  inputProps={{ max: hoyInput(), min: toDateInput(modalAccion.cheque?.fecha_emision) }}
                  helperText="La fecha real en que el banco lo acreditó/debitó, no necesariamente hoy"
                />
                <TextField label="Referencia (opcional)" fullWidth size="small"
                  value={accionData.referencia}
                  onChange={e => setAccionData(d => ({ ...d, referencia: e.target.value }))}
                  placeholder="Nº de boleta, nota..."
                />
              </>
            )}

            {["rechazar", "devolver", "anular"].includes(modalAccion.tipo) && (
              <TextField label="Motivo *" fullWidth multiline rows={2} autoFocus
                value={accionData.motivo}
                onChange={e => setAccionData(d => ({ ...d, motivo: e.target.value }))}
              />
            )}

            {modalAccion.tipo === "eliminar" && (
              <Typography color="error" variant="body2">Esta acción no se puede deshacer.</Typography>
            )}
          </DialogContent>
          <DialogActions>
            <Button onClick={() => setModalAccion(null)}>Cancelar</Button>
            <Button
              variant="contained"
              color={["rechazar", "devolver", "anular", "eliminar"].includes(modalAccion.tipo) ? "error" : "primary"}
              onClick={handleAccion}
              disabled={
                isPendingAccion ||
                ((modalAccion.tipo === "depositar" || modalAccion.tipo === "debitar") && (!accionData.cuenta_id || !accionData.fecha_movimiento)) ||
                (["rechazar", "devolver", "anular"].includes(modalAccion.tipo) && !accionData.motivo.trim())
              }
            >
              {isPendingAccion ? <CircularProgress size={18} /> : ACCION_LABEL[modalAccion.tipo]}
            </Button>
          </DialogActions>
        </Dialog>
      )}
      {/* ── Aviso de cheque duplicado ── */}
      <Dialog open={!!duplicado} onClose={() => setDuplicado(null)} maxWidth="sm" fullWidth>
        <DialogTitle>¿Este cheque ya está cargado?</DialogTitle>
        <DialogContent>
          <Typography variant="body2" sx={{ mb: 1.5 }}>
            {duplicado?.mensaje}
          </Typography>
          <Typography variant="body2" sx={{ opacity: 0.75 }}>
            Si es el mismo cheque, cerrá este aviso: cargarlo de nuevo duplicaría el ingreso en la cuenta cuando lo
            deposites. Si de verdad es otro cheque distinto con el mismo número, confirmá.
          </Typography>
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setDuplicado(null)}>Cancelar</Button>
          <Button variant="contained" color="warning" onClick={handleConfirmarDuplicado} disabled={createCheque.isPending}>
            {createCheque.isPending ? <CircularProgress size={18} /> : "Es otro cheque, cargarlo igual"}
          </Button>
        </DialogActions>
      </Dialog>
    </Container>
  );
};

// ── Menú de acciones por fila ─────────────────────────────────────────────────

const AccionesMenu = ({ cheque, tipoVista, isActiva, esOperable, onEditar, onAccion }) => {
  const [open, setOpen] = useState(false);
  const wrapRef = useRef(null);

  useEffect(() => {
    if (!open) return undefined;
    const onClick = (e) => {
      if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
    };
    const onEsc = (e) => { if (e.key === "Escape") setOpen(false); };
    document.addEventListener("mousedown", onClick);
    document.addEventListener("keydown", onEsc);
    return () => {
      document.removeEventListener("mousedown", onClick);
      document.removeEventListener("keydown", onEsc);
    };
  }, [open]);

  const items = [];
  if (tipoVista === "RECIBIDO" && isActiva) {
    if (esOperable) {
      items.push({ key: "depositar", label: "Depositar", icon: "lucide:arrow-down-to-line", onClick: () => onAccion("depositar") });
    }
    items.push({ key: "devolver", label: "Devolver", icon: "lucide:undo-2", onClick: () => onAccion("devolver") });
  }
  if (tipoVista === "EMITIDO" && isActiva && esOperable) {
    items.push({ key: "debitar", label: "Debitar", icon: "lucide:arrow-up-from-line", onClick: () => onAccion("debitar") });
  }
  if (isActiva) {
    items.push({ key: "editar", label: "Editar", icon: "lucide:pencil", onClick: () => onEditar() });
  }
  // Cargado por error: no hubo hecho en el banco, así que el movimiento se
  // ANULA en vez de compensarse con un egreso (que sería una salida inventada).
  if (
    (tipoVista === "RECIBIDO" && cheque.estado === "DEPOSITADO") ||
    (tipoVista === "EMITIDO" && cheque.estado === "DEBITADO")
  ) {
    items.push({
      key: "deshacer",
      label: tipoVista === "RECIBIDO" ? "Deshacer depósito" : "Deshacer débito",
      icon: "lucide:rotate-ccw",
      onClick: () => onAccion("deshacer"),
    });
  }

  const destructivas = [];
  if (isActiva || (cheque.estado === "DEPOSITADO" && tipoVista === "RECIBIDO")) {
    destructivas.push({ key: "rechazar", label: "Rechazar", icon: "lucide:x-circle", onClick: () => onAccion("rechazar") });
  }
  if (tipoVista === "EMITIDO" && (isActiva || cheque.estado === "DEBITADO")) {
    destructivas.push({ key: "anular", label: "Anular", icon: "lucide:ban", onClick: () => onAccion("anular") });
  }
  if (isActiva) {
    destructivas.push({ key: "eliminar", label: "Eliminar", icon: "lucide:trash-2", onClick: () => onAccion("eliminar") });
  }

  const noHayAcciones = items.length === 0 && destructivas.length === 0;
  const anulado = cheque.estado === "ANULADO" || cheque.estado === "RECHAZADO" || cheque.estado === "DEVUELTO";

  return (
    <ActionWrap ref={wrapRef} onClick={(e) => e.stopPropagation()}>
      <ActionBtn
        type="button"
        $anulado={anulado}
        disabled={noHayAcciones}
        onClick={() => setOpen(o => !o)}
      >
        <Icon icon="lucide:more-horizontal" width={14} />
        <span>Acciones</span>
        <Icon icon="lucide:chevron-down" width={12} />
      </ActionBtn>
      {open && !noHayAcciones && (
        <ActionMenu>
          {items.map(it => (
            <ActionItem key={it.key} onClick={() => { setOpen(false); it.onClick(); }}>
              <Icon icon={it.icon} width={14} /> {it.label}
            </ActionItem>
          ))}
          {items.length > 0 && destructivas.length > 0 && <ActionDivider />}
          {destructivas.map(it => (
            <ActionItem key={it.key} $danger onClick={() => { setOpen(false); it.onClick(); }}>
              <Icon icon={it.icon} width={14} /> {it.label}
            </ActionItem>
          ))}
        </ActionMenu>
      )}
    </ActionWrap>
  );
};

AccionesMenu.propTypes = {
  cheque: PropTypes.shape({
    estado: PropTypes.string,
    numero_cheque: PropTypes.string,
  }).isRequired,
  tipoVista: PropTypes.oneOf(["RECIBIDO", "EMITIDO"]).isRequired,
  isActiva: PropTypes.bool,
  esOperable: PropTypes.bool,
  onEditar: PropTypes.func.isRequired,
  onAccion: PropTypes.func.isRequired,
};

// ── Constantes de acciones ────────────────────────────────────────────────────

const ACCION_LABEL = {
  depositar: "Depositar cheque",
  debitar: "Marcar como debitado",
  rechazar: "Rechazar cheque",
  devolver: "Devolver cheque",
  anular: "Anular cheque",
  eliminar: "Eliminar registro",
  deshacer: "Deshacer por carga errónea",
};

const ACCION_DESC = {
  depositar: (c) => `Seleccioná la cuenta donde se acreditará el cheque Nº ${c.numero_cheque} por ${fmtMonto(c.monto, monedaDe(c))}. Se generará un movimiento de ingreso automáticamente.`,
  debitar: (c) => `Confirmá el débito del cheque Nº ${c.numero_cheque} por ${fmtMonto(c.monto, monedaDe(c))}. Se generará un movimiento de egreso automáticamente.`,
  rechazar: (c) => c.estado === "DEPOSITADO"
    ? `El banco rechazó el cheque Nº ${c.numero_cheque}. Como ya estaba depositado, se genera una reversa por ${fmtMonto(c.monto, monedaDe(c))} que descuenta el ingreso de la cuenta.`
    : `Marcá el cheque Nº ${c.numero_cheque} como rechazado por el banco. Ingresá el motivo.`,
  devolver: (c) => `Devolver el cheque Nº ${c.numero_cheque} al emisor ${c.titular || ""}. No mueve saldo: el cheque nunca se depositó.`,
  anular: (c) => c.estado === "DEBITADO"
    ? `Anular el cheque Nº ${c.numero_cheque}. Como ya estaba debitado, se genera una reversa por ${fmtMonto(c.monto, monedaDe(c))} que devuelve el egreso a la cuenta.`
    : `Anular el cheque Nº ${c.numero_cheque}. Todavía no movió saldo, así que no genera movimiento.`,
  eliminar: (c) => `¿Eliminar el registro del cheque Nº ${c.numero_cheque}? Solo disponible para cheques en cartera.`,
  // Se explica el efecto en plata, que es lo que al usuario le importa.
  deshacer: (c) => `Usá esto sólo si el ${c.estado === "DEBITADO" ? "débito" : "depósito"} nunca ocurrió en el banco y se cargó por error. ` +
    `El movimiento de ${fmtMonto(c.monto, monedaDe(c))} se anula: deja de sumar al saldo y no aparece en el extracto ni en el arqueo (no se crea ningún ${c.estado === "DEBITADO" ? "ingreso" : "egreso"} de reversa). ` +
    `El cheque Nº ${c.numero_cheque} vuelve a la cartera. Si en cambio el banco rechazó el cheque, cerrá esto y usá "Rechazar".`,
};

// ── Styled components ─────────────────────────────────────────────────────────

const Container = styled.div`
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
`;

const Header = styled.div`
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 10px;
`;

const ToggleWrap = styled.div`display: flex;`;

const ResumenBar = styled.div`
  background: ${({ theme }) => theme.bg2};
  border: 1px solid ${({ theme }) => theme.color2};
  border-radius: 10px;
  padding: 12px 20px;
  display: flex;
  gap: 28px;
  flex-wrap: wrap;
`;
const ResumenItem = styled.div`display: flex; flex-direction: column; gap: 2px;`;
const ResumenLabel = styled.span`font-size: 11px; opacity: 0.6; text-transform: uppercase; letter-spacing: 0.4px;`;
const ResumenValor = styled.span`
  font-size: 15px;
  font-weight: 600;
  color: ${({ $alerta }) => $alerta ? "#f59e0b" : "inherit"};
`;

const ResumenDetalle = styled.span`
  font-size: 11px;
  opacity: 0.55;
  white-space: nowrap;
`;

const InfoBanner = styled.div`
  background: #38bdf818;
  border: 1px solid #38bdf855;
  border-radius: 8px;
  padding: 10px 14px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: #38bdf8;
`;

const AlertaBanner = styled.div`
  background: #f59e0b18;
  border: 1px solid #f59e0b55;
  border-radius: 8px;
  padding: 10px 14px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: #f59e0b;
`;

const NumCode = styled.span`
  font-family: monospace;
  font-size: 12px;
  opacity: 0.75;
`;

const MontoCell = styled.span`
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-weight: 700;
  font-size: 14px;
  color: ${({ $tipo }) => $tipo === "RECIBIDO" ? "#22c55e" : "#ef4444"};
  white-space: nowrap;
`;

const VencCell = styled.span`
  font-size: 12px;
  font-weight: ${({ $vencido, $proximo }) => ($vencido || $proximo) ? 600 : 400};
  color: ${({ $vencido, $proximo }) => $vencido ? "#ef4444" : $proximo ? "#f59e0b" : "inherit"};
`;

const Muted = styled.span`opacity: 0.35;`;

const FiltersBar = styled.div`display: flex; flex-wrap: wrap; gap: 10px; align-items: center;`;

const TableWrap = styled.div`
  background: ${({ theme }) => theme.bg2};
  border: 1px solid ${({ theme }) => theme.color2};
  border-radius: 10px;
  overflow-x: auto;
`;
const ScrollX = styled.div``;
const StyledTable = styled.table`width: 100%; border-collapse: collapse; min-width: 900px;`;
const Th = styled.th`
  background: ${({ theme }) => theme.bg3};
  color: ${({ theme }) => theme.text2};
  padding: 10px 12px;
  text-align: left;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  border-bottom: 1px solid ${({ theme }) => theme.color2};
  white-space: nowrap;
`;
const Td = styled.td`
  padding: 10px 12px;
  border-bottom: 1px solid ${({ theme }) => theme.color2};
  font-size: 13px;
  color: ${({ theme }) => theme.text1};
  vertical-align: top;
`;
const Tr = styled.tr`
  &:last-child td { border-bottom: none; }
  &:hover { background: ${({ theme }) => theme.bg3}; }
`;
const Pagination = styled.div`
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 12px 16px;
  border-top: 1px solid ${({ theme }) => theme.color2};
`;

const FormGrid = styled.div`
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin-top: 8px;
  @media (max-width: 500px) { grid-template-columns: 1fr; }
`;

// ── Acciones (estilo Recibos) ────────────────────────────────────────────────
const ActionWrap = styled.div`
  position: relative;
  display: inline-block;
`;
const ActionBtn = styled.button`
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: #1e293b;
  color: ${({ $anulado }) => ($anulado ? "#6b7280" : "#e2e8f0")};
  border: 1px solid ${({ $anulado }) => ($anulado ? "#374151" : "#334155")};
  border-radius: 6px;
  padding: 5px 10px;
  font-size: 11px;
  font-weight: 500;
  cursor: ${({ $anulado }) => ($anulado ? "not-allowed" : "pointer")};
  outline: none;
  min-width: 110px;
  transition: border-color 0.15s, background-color 0.15s;
  &:hover:not(:disabled) {
    border-color: #475569;
    background-color: #253347;
  }
  &:focus-visible {
    border-color: #3b82f6;
    box-shadow: 0 0 0 2px #3b82f620;
  }
  &:disabled {
    opacity: 0.4;
    cursor: not-allowed;
  }
`;
const ActionMenu = styled.div`
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  z-index: 20;
  min-width: 180px;
  background: #0f172a;
  border: 1px solid #334155;
  border-radius: 8px;
  padding: 4px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
  display: flex;
  flex-direction: column;
  gap: 2px;
`;
const ActionItem = styled.button`
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  background: transparent;
  border: 0;
  color: ${({ $danger }) => ($danger ? "#fca5a5" : "#e2e8f0")};
  font-size: 12px;
  font-weight: 500;
  padding: 7px 10px;
  border-radius: 5px;
  cursor: pointer;
  text-align: left;
  transition: background 0.12s, color 0.12s;
  &:hover {
    background: ${({ $danger }) => ($danger ? "#ef44441a" : "#1e293b")};
    color: ${({ $danger }) => ($danger ? "#ef4444" : "#fff")};
  }
`;
const ActionDivider = styled.div`
  height: 1px;
  background: #1e293b;
  margin: 4px 2px;
`;
