import { categoriaAplicaA } from "../_standards";
import { useState, useMemo, useRef, useCallback } from "react";
import styled from "styled-components";
import { toast } from "sonner";
import {
  Autocomplete,
  Box,
  Button,
  Chip,
  CircularProgress,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  Divider,
  FormControl,
  InputLabel,
  LinearProgress,
  MenuItem,
  Select,
  TextField,
  Typography,
  IconButton,
  Tooltip,
  Alert,
  Paper,
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableRow,
  useTheme,
} from "@mui/material";
import { Add, AutoAwesome, Block, CheckCircle, Close, CloudUpload, Delete, LinkOff, RadioButtonUnchecked, TableChart } from "@mui/icons-material";
import { useTesCuentasQuery, useTesCategoriaQuery } from "../../tanstack/TesoreriaStack";
import {
  useTesExtractosQuery,
  useTesExtractoDetalleQuery,
  useTesMovimientosSinConciliarQuery,
  useImportarExtractoMutation,
  useImportarExtractoPdfMutation,
  useEliminarExtractoMutation,
  useConciliarLineaMutation,
  useDesconciliarLineaMutation,
  useMarcarSinCorrespondenciaMutation,
  useDesmarcarSinCorrespondenciaMutation,
  useCrearMovimientoDesdeLineaMutation,
  useActualizarLineaMutation,
  useDiferenciasQuery,
} from "../../tanstack/TesoreriaStack";

const fmtGs = (n) => new Intl.NumberFormat("es-PY", { minimumFractionDigits: 0 }).format(n ?? 0);
const fmtDate = (d) => (d ? new Date(d).toLocaleDateString("es-PY") : "—");

const Layout = styled.div`
  display: flex;
  gap: 12px;
  height: calc(100vh - 180px);
`;

const LeftPanel = styled.div`
  width: 320px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow-y: auto;
`;

const RightPanel = styled.div`
  flex: 1;
  overflow: hidden;
  display: flex;
  flex-direction: column;
`;

const ExtractoCard = styled.div`
  padding: 10px 14px;
  border-radius: 8px;
  border: 2px solid ${({ $selected, $dark }) => ($selected ? "#1976d2" : $dark ? "#333" : "#e0e0e0")};
  background: ${({ $selected, $dark }) => ($selected ? ($dark ? "#0d2a4a" : "#e3f2fd") : $dark ? "#1e1e1e" : "#fafafa")};
  cursor: pointer;
  &:hover {
    border-color: #90caf9;
  }
`;

const LineaRow = styled.tr`
  background: ${({ $conciliado, $sinCorrespondencia, $dark }) =>
    $conciliado ? ($dark ? "#1a2e1a" : "#f1f8e9") :
    $sinCorrespondencia ? ($dark ? "#1e1a10" : "#fff8e1") :
    ($dark ? "#181818" : "#fff")};
  opacity: ${({ $sinCorrespondencia }) => $sinCorrespondencia ? 0.7 : 1};
  &:hover {
    background: ${({ $conciliado, $sinCorrespondencia, $dark }) =>
      $conciliado ? ($dark ? "#1f381f" : "#dcedc8") :
      $sinCorrespondencia ? ($dark ? "#2a2410" : "#fff3cd") :
      ($dark ? "#242424" : "#f5f5f5")};
  }
`;

const Tabla = styled.table`
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  th {
    background: ${({ $dark }) => ($dark ? "#1e1e1e" : "#f5f5f5")};
    color: ${({ $dark }) => ($dark ? "#aaa" : "inherit")};
    padding: 6px 8px;
    text-align: left;
    border-bottom: 2px solid ${({ $dark }) => ($dark ? "#333" : "#e0e0e0")};
    white-space: nowrap;
  }
  td {
    padding: 5px 8px;
    border-bottom: 1px solid ${({ $dark }) => ($dark ? "#2a2a2a" : "#f0f0f0")};
  }
`;

const estadoColor = { PENDIENTE: "warning", PARCIAL: "info", CONCILIADO: "success" };
const estadoLabel = { PENDIENTE: "Pendiente", PARCIAL: "Parcial", CONCILIADO: "Conciliado" };

// ── Estilos del ImportDialog ───────────────────────────────────────────────────
const DropZone = styled(Paper)`
  border: 2px dashed ${({ $dragover, $dark }) => ($dragover ? ($dark ? "#90caf9" : "#1976d2") : $dark ? "rgba(255,255,255,0.18)" : "#bdbdbd")};
  border-radius: 12px !important;
  padding: 32px 16px;
  text-align: center;
  cursor: pointer;
  transition:
    border-color 0.2s,
    background 0.2s;
  background: ${({ $dragover, $dark }) => ($dragover ? ($dark ? "rgba(100,160,255,0.12)" : "#e3f2fd") : $dark ? "rgba(255,255,255,0.04)" : "#fafafa")} !important;
  &:hover {
    border-color: ${({ $dark }) => ($dark ? "#90caf9" : "#90caf9")};
    background: ${({ $dark }) => ($dark ? "rgba(100,160,255,0.1)" : "#f0f7ff")} !important;
  }
`;

const fmtImporte = (n) => new Intl.NumberFormat("es-PY").format(n ?? 0);

// ── Modal de importar extracto (PDF con IA o CSV manual) ──────────────────────
function ImportDialog({ open, onClose, cuentas }) {
  const theme = useTheme();
  const isDark = theme.palette.mode === "dark";
  const importarCsv = useImportarExtractoMutation();
  const importarPdf = useImportarExtractoPdfMutation();
  const [previewEdits, setPreviewEdits] = useState({});
  const [editCell, setEditCell] = useState(null); // { lineaId, field }
  const [editVal, setEditVal] = useState("");
  const fileRef = useRef();
  const [_previewExtractoId, _setPreviewExtractoId] = useState(null);
  const actualizarLineaMut = useActualizarLineaMutation(_previewExtractoId);

  // modo: 'idle' | 'procesando' | 'preview'
  const [modo, setModo] = useState("idle");
  const [dragover, setDragover] = useState(false);
  const [archivoFile, setArchivoFile] = useState(null); // File object (PDF)
  const [csvText, setCsvText] = useState(""); // texto CSV leído
  const [previewData, setPreviewData] = useState(null); // respuesta IA preview
  const [form, setForm] = useState({
    cuenta_id: "",
    periodo_desde: "",
    periodo_hasta: "",
    saldo_inicial: "",
    saldo_final: "",
  });
  const [tipoArchivo, setTipoArchivo] = useState(null); // 'pdf' | 'csv'

  const reset = useCallback(() => {
    setModo("idle");
    setArchivoFile(null);
    setCsvText("");
    setPreviewData(null);
    setForm({ cuenta_id: "", periodo_desde: "", periodo_hasta: "", saldo_inicial: "", saldo_final: "" });
    setTipoArchivo(null);
    setDragover(false);
  }, []);

  const handleClose = () => {
    reset();
    onClose();
  };

  const procesarArchivo = useCallback((file) => {
    if (!file) return;
    const nombre = file.name.toLowerCase();
    const esPdf = file.type === "application/pdf" || nombre.endsWith(".pdf");
    const esCsvOTxt = nombre.endsWith(".csv") || nombre.endsWith(".txt");
    if (!esPdf && !esCsvOTxt) {
      toast.error("Formato no soportado. Subí el extracto en PDF, CSV o TXT.");
      return;
    }
    setTipoArchivo(esPdf ? "pdf" : "csv");
    if (esPdf) {
      setArchivoFile(file);
      setCsvText(""); // limpiar CSV de una selección previa dentro del mismo diálogo
    } else {
      setArchivoFile(null); // limpiar PDF de una selección previa dentro del mismo diálogo
      const reader = new FileReader();
      reader.onload = (ev) => setCsvText(ev.target.result);
      reader.readAsText(file, "utf-8");
    }
  }, []);

  const handleFileInput = (e) => procesarArchivo(e.target.files[0]);

  const handleDrop = useCallback(
    (e) => {
      e.preventDefault();
      setDragover(false);
      procesarArchivo(e.dataTransfer.files[0]);
    },
    [procesarArchivo],
  );

  const validBase = form.cuenta_id;

  const handleProcesar = async () => {
    if (!validBase) return;
    if (tipoArchivo === "pdf") {
      // PDF → IA → preview
      setModo("procesando");
      try {
        const resultado = await importarPdf.mutateAsync({
          file: archivoFile,
          cuenta_id: form.cuenta_id,
          periodo_desde: form.periodo_desde || undefined,
          periodo_hasta: form.periodo_hasta || undefined,
          saldo_inicial: form.saldo_inicial || undefined,
          saldo_final: form.saldo_final || undefined,
        });
        setPreviewData(resultado);
        _setPreviewExtractoId(resultado?.id);
        setPreviewEdits({});
        setModo("preview");
      } catch {
        setModo("idle");
      }
    } else {
      // CSV → importación directa
      await importarCsv.mutateAsync({
        ...form,
        periodo_desde: form.periodo_desde || undefined,
        periodo_hasta: form.periodo_hasta || undefined,
        saldo_inicial: Number(form.saldo_inicial) || 0,
        saldo_final: Number(form.saldo_final) || 0,
        archivo_nombre: fileRef.current?.files[0]?.name,
        csv_content: csvText,
      });
      handleClose();
    }
  };

  const archivoListo = tipoArchivo === "pdf" ? !!archivoFile : !!csvText;
  const isPending = importarPdf.isPending || importarCsv.isPending;

  const commitEdit = (lineaId, field) => {
    if (!editVal.trim()) { setEditCell(null); return; }
    const payload = { lineaId };
    if (field === "fecha") payload.fecha = editVal;
    else if (field === "debito") payload.debito = parseFloat(editVal.replace(/\./g, "").replace(",", ".")) || 0;
    else if (field === "credito") payload.credito = parseFloat(editVal.replace(/\./g, "").replace(",", ".")) || 0;
    actualizarLineaMut.mutate(payload);
    setPreviewEdits((e) => ({ ...e, [lineaId]: { ...(e[lineaId] || {}), [field]: editVal } }));
    setEditCell(null);
  };

  return (
    <Dialog open={open} onClose={modo === "procesando" ? undefined : handleClose} maxWidth="md" fullWidth>
      <DialogTitle sx={{ display: "flex", alignItems: "center", gap: 1, pb: 1 }}>
        {modo === "preview" ? (
          <>
            <AutoAwesome sx={{ color: "#7c3aed", fontSize: 20 }} />
            Revisá los movimientos detectados por Novasis IA
          </>
        ) : (
          "Importar extracto bancario"
        )}
        {modo !== "procesando" && (
          <IconButton size="small" onClick={handleClose} sx={{ ml: "auto" }}>
            <Close fontSize="small" />
          </IconButton>
        )}
      </DialogTitle>

      <DialogContent sx={{ display: "flex", flexDirection: "column", gap: 2, pt: 1 }}>
        {/* ── Estado: PROCESANDO ── */}
        {modo === "procesando" && (
          <Box sx={{ py: 4, textAlign: "center" }}>
            <AutoAwesome
              sx={{ fontSize: 48, color: "#7c3aed", mb: 2, animation: "spin 2s linear infinite", "@keyframes spin": { from: { transform: "rotate(0deg)" }, to: { transform: "rotate(360deg)" } } }}
            />
            <Typography variant="h6" gutterBottom>
              Analizando extracto con Novasis IA…
            </Typography>
            <Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
              Leyendo movimientos de <b>{archivoFile?.name}</b>
            </Typography>
            <LinearProgress sx={{ borderRadius: 4, height: 6 }} />
            <Typography variant="caption" color="text.secondary" sx={{ mt: 1, display: "block" }}>
              Esto puede tomar unos segundos
            </Typography>
          </Box>
        )}

        {/* ── Estado: PREVIEW (resultado IA) ── */}
        {modo === "preview" && previewData && (
          <>
            <Alert severity="success" icon={<AutoAwesome />} sx={{ "& .MuiAlert-icon": { color: "#7c3aed" } }}>
              <b>IA detectó {previewData.stats?.total} movimientos</b>
              {previewData.ia_meta?.banco ? ` · ${previewData.ia_meta.banco}` : ""}
              {" · "}
              <b style={{ color: "#2e7d32" }}>{previewData.stats?.conciliadas} auto-conciliados</b>
              {previewData.stats?.pendientes > 0 && ` · ${previewData.stats.pendientes} para revisión manual`}
            </Alert>

            <Alert severity="warning" sx={{ fontSize: 12, py: 0.5 }}>
              Revisá que los importes coincidan con tu PDF antes de usar este extracto.
            </Alert>

            <Box sx={{ maxHeight: 320, overflow: "auto", border: "1px solid #e0e0e0", borderRadius: 1 }}>
              <Table size="small" stickyHeader>
                <TableHead>
                  <TableRow>
                    <TableCell>Fecha</TableCell>
                    <TableCell>Concepto</TableCell>
                    <TableCell>Ref.</TableCell>
                    <TableCell align="right" sx={{ color: "#d32f2f" }}>
                      Débito
                    </TableCell>
                    <TableCell align="right" sx={{ color: "#2e7d32" }}>
                      Crédito
                    </TableCell>
                    <TableCell>Estado</TableCell>
                  </TableRow>
                </TableHead>
                <TableBody>
                  {previewData.lineas?.map((l) => {
                    const edits = previewEdits[l.id] || {};
                    const isEditing = (field) => editCell?.lineaId === l.id && editCell?.field === field;
                    const startEdit = (field, currentVal) => {
                      if (l.conciliado) return;
                      setEditCell({ lineaId: l.id, field });
                      setEditVal(String(currentVal ?? ""));
                    };
                    return (
                      <TableRow key={l.id} sx={{ background: l.conciliado ? (isDark ? "#1a2e1a" : "#f1f8e9") : undefined }}>
                        <TableCell sx={{ whiteSpace: "nowrap", fontSize: 12, cursor: l.conciliado ? "default" : "pointer" }}
                          onClick={() => startEdit("fecha", (edits.fecha || l.fecha?.substring(0, 10)))}>
                          {isEditing("fecha") ? (
                            <input type="date" value={editVal} autoFocus style={{ width: 130, fontSize: 12 }}
                              onChange={(e) => setEditVal(e.target.value)}
                              onBlur={() => commitEdit(l.id, "fecha")}
                              onKeyDown={(e) => { if (e.key === "Enter") commitEdit(l.id, "fecha"); if (e.key === "Escape") setEditCell(null); }} />
                          ) : (
                            <span title={l.conciliado ? "" : "Click para editar"}>{edits.fecha ? new Date(edits.fecha).toLocaleDateString("es-PY") : fmtDate(l.fecha)}</span>
                          )}
                        </TableCell>
                        <TableCell sx={{ fontSize: 12, maxWidth: 260 }}>{l.descripcion || "—"}</TableCell>
                        <TableCell sx={{ fontSize: 11, color: "#888" }}>{l.referencia || ""}</TableCell>
                        <TableCell align="right" sx={{ color: "#d32f2f", fontSize: 12, cursor: l.conciliado || l.credito > 0 ? "default" : "pointer" }}
                          onClick={() => { if (!l.conciliado && l.debito > 0) startEdit("debito", edits.debito || l.debito); }}>
                          {isEditing("debito") ? (
                            <input type="number" value={editVal} autoFocus style={{ width: 90, fontSize: 12, textAlign: "right" }}
                              onChange={(e) => setEditVal(e.target.value)}
                              onBlur={() => commitEdit(l.id, "debito")}
                              onKeyDown={(e) => { if (e.key === "Enter") commitEdit(l.id, "debito"); if (e.key === "Escape") setEditCell(null); }} />
                          ) : (
                            <span title={!l.conciliado && l.debito > 0 ? "Click para editar" : ""}>
                              {(edits.debito ?? l.debito) > 0 ? fmtImporte(edits.debito ?? l.debito) : ""}
                            </span>
                          )}
                        </TableCell>
                        <TableCell align="right" sx={{ color: "#2e7d32", fontSize: 12, cursor: l.conciliado || l.debito > 0 ? "default" : "pointer" }}
                          onClick={() => { if (!l.conciliado && l.credito > 0) startEdit("credito", edits.credito || l.credito); }}>
                          {isEditing("credito") ? (
                            <input type="number" value={editVal} autoFocus style={{ width: 90, fontSize: 12, textAlign: "right" }}
                              onChange={(e) => setEditVal(e.target.value)}
                              onBlur={() => commitEdit(l.id, "credito")}
                              onKeyDown={(e) => { if (e.key === "Enter") commitEdit(l.id, "credito"); if (e.key === "Escape") setEditCell(null); }} />
                          ) : (
                            <span title={!l.conciliado && l.credito > 0 ? "Click para editar" : ""}>
                              {(edits.credito ?? l.credito) > 0 ? fmtImporte(edits.credito ?? l.credito) : ""}
                            </span>
                          )}
                        </TableCell>
                        <TableCell>
                          {l.conciliado ? (
                            <Chip label="Auto-conciliado" size="small" color="success" sx={{ fontSize: 10, height: 18 }} />
                          ) : (
                            <Chip label="Pendiente" size="small" color="warning" sx={{ fontSize: 10, height: 18 }} />
                          )}
                        </TableCell>
                      </TableRow>
                    );
                  })}
                </TableBody>
              </Table>
            </Box>
          </>
        )}

        {/* ── Estado: IDLE (selección de archivo y campos) ── */}
        {modo === "idle" && (
          <>
            {/* Selector de cuenta */}
            <FormControl size="small" fullWidth required>
              <InputLabel>Cuenta bancaria *</InputLabel>
              <Select value={form.cuenta_id} label="Cuenta bancaria *" onChange={(e) => setForm((f) => ({ ...f, cuenta_id: e.target.value }))}>
                {cuentas
                  ?.filter((c) => c.activo)
                  .map((c) => (
                    <MenuItem key={c.id} value={c.id}>
                      {c.nombre} ({c.moneda})
                    </MenuItem>
                  ))}
              </Select>
            </FormControl>

            {/* Drop zone */}
            <input ref={fileRef} type="file" accept=".pdf,.csv,.txt" style={{ display: "none" }} onChange={handleFileInput} />
            <DropZone
              $dragover={dragover}
              $dark={isDark}
              elevation={0}
              onClick={() => fileRef.current.click()}
              onDragOver={(e) => {
                e.preventDefault();
                setDragover(true);
              }}
              onDragLeave={() => setDragover(false)}
              onDrop={handleDrop}
            >
              {archivoListo ? (
                <Box>
                  {tipoArchivo === "pdf" ? <AutoAwesome sx={{ fontSize: 36, color: "#7c3aed", mb: 1 }} /> : <TableChart sx={{ fontSize: 36, color: "#1976d2", mb: 1 }} />}
                  <Typography variant="body1" fontWeight={600}>
                    {archivoFile?.name || "Archivo cargado"}
                  </Typography>
                  {tipoArchivo === "csv" && (
                    <Typography variant="caption" color="success.main">
                      ✓ {csvText.split("\n").filter(Boolean).length - 1} líneas detectadas
                    </Typography>
                  )}
                  {tipoArchivo === "pdf" && (
                    <Typography variant="caption" sx={{ color: "#7c3aed" }}>
                      ✨ Será procesado automáticamente por Novasis IA
                    </Typography>
                  )}
                  <br />
                  <Typography variant="caption" color="text.secondary">
                    Hacé clic para cambiar el archivo
                  </Typography>
                </Box>
              ) : (
                <Box>
                  <CloudUpload sx={{ fontSize: 40, color: "#bdbdbd", mb: 1 }} />
                  <Typography variant="body1" fontWeight={500} color="text.secondary">
                    Arrastrá tu extracto aquí
                  </Typography>
                  <Typography variant="caption" color="text.secondary">
                    o hacé clic para seleccionar
                  </Typography>
                  <Box sx={{ mt: 1.5 }}>
                    <Chip label="PDF" size="small" icon={<AutoAwesome sx={{ fontSize: "14px !important", color: "#7c3aed !important" }} />} sx={{ mr: 0.5, fontSize: 11 }} />
                    <Chip label="CSV" size="small" sx={{ mr: 0.5, fontSize: 11 }} />
                    <Chip label="TXT" size="small" sx={{ fontSize: 11 }} />
                  </Box>
                  <Typography variant="caption" sx={{ display: "block", mt: 1, color: "#7c3aed" }}>
                    ✨ Los PDFs son procesados automáticamente por Novasis IA
                  </Typography>
                </Box>
              )}
            </DropZone>

            {/* Período (opcional siempre — si no se completa, se infiere de las fechas del archivo) */}
            <Box sx={{ display: "flex", gap: 1 }}>
              <TextField
                size="small"
                label="Período desde (opcional)"
                type="date"
                InputLabelProps={{ shrink: true }}
                fullWidth
                value={form.periodo_desde}
                onChange={(e) => setForm((f) => ({ ...f, periodo_desde: e.target.value }))}
                helperText={tipoArchivo === "csv" ? "Si lo dejás vacío, se infiere de las fechas del CSV" : undefined}
              />
              <TextField
                size="small"
                label="Período hasta (opcional)"
                type="date"
                InputLabelProps={{ shrink: true }}
                fullWidth
                value={form.periodo_hasta}
                onChange={(e) => setForm((f) => ({ ...f, periodo_hasta: e.target.value }))}
                helperText={tipoArchivo === "csv" ? "Si lo dejás vacío, se infiere de las fechas del CSV" : undefined}
              />
            </Box>
            <Box sx={{ display: "flex", gap: 1 }}>
              <TextField
                size="small" label="Saldo inicial" type="number" fullWidth
                value={form.saldo_inicial}
                onChange={(e) => setForm((f) => ({ ...f, saldo_inicial: e.target.value }))}
                helperText={tipoArchivo === "pdf" ? "Opcional — la IA lo detecta del PDF" : "Opcional"}
              />
              <TextField
                size="small" label="Saldo final" type="number" fullWidth
                value={form.saldo_final}
                onChange={(e) => setForm((f) => ({ ...f, saldo_final: e.target.value }))}
                helperText={tipoArchivo === "pdf" ? "Opcional — la IA lo detecta del PDF" : "Opcional"}
              />
            </Box>

            {tipoArchivo === "csv" && (
              <Alert severity="info" sx={{ fontSize: 12, py: 0.5 }}>
                CSV con columnas: <b>fecha;descripcion;debito;credito;referencia</b> (separador ; o ,)
              </Alert>
            )}
          </>
        )}
      </DialogContent>

      <DialogActions sx={{ px: 3, pb: 2 }}>
        {modo === "idle" && (
          <>
            <Button onClick={handleClose}>Cancelar</Button>
            <Button
              variant="contained"
              disabled={!validBase || !archivoListo || isPending}
              onClick={handleProcesar}
              startIcon={tipoArchivo === "pdf" ? <AutoAwesome /> : undefined}
              sx={tipoArchivo === "pdf" ? { background: "#7c3aed", "&:hover": { background: "#6d28d9" } } : {}}
            >
              {isPending ? <CircularProgress size={18} /> : tipoArchivo === "pdf" ? "Analizar con IA" : tipoArchivo === "csv" ? "Importar CSV" : "Importar"}
            </Button>
          </>
        )}
        {modo === "preview" && (
          <>
            <Button onClick={handleClose} variant="contained" color="success">
              Listo — ver extracto
            </Button>
          </>
        )}
      </DialogActions>
    </Dialog>
  );
}

// ── Selector de movimiento para conciliar una línea ───────────────────────────
function ConciliarSelector({ linea, movimientos, extractoId, onDone }) {
  const [selected, setSelected] = useState(null);
  const conciliar = useConciliarLineaMutation(extractoId);

  const candidatos = movimientos
    .filter((m) => m.tipo === (linea.debito > 0 ? "EGRESO" : "INGRESO"))
    .map((m) => ({
      id: m.id,
      label: `${fmtDate(m.fecha)} — ${fmtGs(m.monto)} — ${m.descripcion?.substring(0, 40) || "—"}`,
    }));

  const handleConciliar = async () => {
    if (!selected) return;
    await conciliar.mutateAsync({ lineaId: linea.id, movimientoId: selected.id });
    onDone();
  };

  return (
    <Box sx={{ display: "flex", gap: 1, alignItems: "center", minWidth: 380 }}>
      <Autocomplete
        size="small"
        sx={{ flex: 1 }}
        options={candidatos}
        value={selected}
        onChange={(_, v) => setSelected(v)}
        noOptionsText="Sin coincidencias"
        renderInput={(params) => <TextField {...params} placeholder="Buscar movimiento…" />}
        isOptionEqualToValue={(o, v) => o.id === v.id}
      />
      <Button size="small" variant="contained" disabled={!selected || conciliar.isPending} onClick={handleConciliar}>
        {conciliar.isPending ? <CircularProgress size={14} /> : "Vincular"}
      </Button>
    </Box>
  );
}

// ── Modal crear movimiento desde línea ────────────────────────────────────────
function CrearMovimientoDialog({ open, linea, extractoId, onClose }) {
  const { data: categorias = [] } = useTesCategoriaQuery();
  const crear = useCrearMovimientoDesdeLineaMutation(extractoId);
  const [categoriaId, setCategoriaId] = useState("");
  const [descripcion, setDescripcion] = useState("");

  const tipo = linea?.debito > 0 ? "EGRESO" : "INGRESO";
  // Misma regla que el resto de Tesorería (incluye las de tipo "Ingreso y egreso").
  const categoriasFiltered = categorias.filter((c) => categoriaAplicaA(c, tipo));
  const monto = linea ? (linea.debito > 0 ? linea.debito : linea.credito) : 0;

  const handleSubmit = async () => {
    if (!categoriaId) return;
    await crear.mutateAsync({ lineaId: linea.id, categoria_id: categoriaId, descripcion: descripcion || undefined });
    setCategoriaId("");
    setDescripcion("");
    onClose();
  };

  return (
    <Dialog open={open} onClose={onClose} maxWidth="sm" fullWidth>
      <DialogTitle sx={{ display: "flex", alignItems: "center", gap: 1 }}>
        Registrar movimiento para esta línea
        <IconButton size="small" onClick={onClose} sx={{ ml: "auto" }}><Close fontSize="small" /></IconButton>
      </DialogTitle>
      <DialogContent sx={{ display: "flex", flexDirection: "column", gap: 2, pt: 2 }}>
        {linea && (
          <Alert severity="info" sx={{ fontSize: 12 }}>
            <b>{linea.descripcion || "Sin descripción"}</b><br />
            {fmtDate(linea.fecha)} — {tipo === "EGRESO" ? "Débito" : "Crédito"}: <b>{fmtGs(monto)}</b>
          </Alert>
        )}
        <FormControl size="small" fullWidth required>
          <InputLabel>Categoría</InputLabel>
          <Select value={categoriaId} onChange={(e) => setCategoriaId(e.target.value)} label="Categoría">
            {categoriasFiltered.map((c) => (
              <MenuItem key={c.id} value={c.id}>{c.nombre}</MenuItem>
            ))}
          </Select>
        </FormControl>
        <TextField
          size="small" label="Descripción (opcional)" fullWidth
          value={descripcion}
          onChange={(e) => setDescripcion(e.target.value)}
          placeholder={linea?.descripcion || ""}
        />
      </DialogContent>
      <DialogActions>
        <Button onClick={onClose}>Cancelar</Button>
        <Button variant="contained" disabled={!categoriaId || crear.isPending} onClick={handleSubmit}>
          {crear.isPending ? <CircularProgress size={16} /> : "Crear y conciliar"}
        </Button>
      </DialogActions>
    </Dialog>
  );
}

// ── Panel detalle del extracto ────────────────────────────────────────────────
function ExtractoDetalle({ extractoId }) {
  const theme = useTheme();
  const isDark = theme.palette.mode === "dark";
  const { data, isLoading } = useTesExtractoDetalleQuery(extractoId);
  const desconciliar = useDesconciliarLineaMutation(extractoId);
  const marcarSC = useMarcarSinCorrespondenciaMutation(extractoId);
  const desmarcarSC = useDesmarcarSinCorrespondenciaMutation(extractoId);
  const [expandLinea, setExpandLinea] = useState(null);
  const [crearMovLinea, setCrearMovLinea] = useState(null);
  const [buscar, setBuscar] = useState("");
  const [showDiferencias, setShowDiferencias] = useState(false);
  const { data: diferencias } = useDiferenciasQuery(showDiferencias ? extractoId : null);

  const movParams = useMemo(
    () =>
      data
        ? {
            cuenta_id: data.cuenta_id,
            fecha_desde: data.periodo_desde?.substring(0, 10),
            fecha_hasta: data.periodo_hasta?.substring(0, 10),
          }
        : null,
    [data],
  );

  const { data: movimientos = [] } = useTesMovimientosSinConciliarQuery(movParams, !!movParams);

  if (isLoading)
    return (
      <Box sx={{ display: "flex", justifyContent: "center", pt: 4 }}>
        <CircularProgress />
      </Box>
    );
  if (!data) return null;

  const lineasFiltradas = buscar ? data.lineas.filter((l) => l.descripcion?.toLowerCase().includes(buscar.toLowerCase()) || l.referencia?.toLowerCase().includes(buscar.toLowerCase())) : data.lineas;

  return (
    <Box sx={{ display: "flex", flexDirection: "column", height: "100%", overflow: "hidden" }}>
      {/* Header */}
      <Box sx={{ p: 1.5, borderBottom: "1px solid #e0e0e0", display: "flex", gap: 2, alignItems: "center", flexWrap: "wrap" }}>
        <Box>
          <Typography variant="subtitle1" fontWeight={600}>
            {data.cuenta?.nombre}
          </Typography>
          <Typography variant="caption" color="text.secondary">
            {fmtDate(data.periodo_desde)} → {fmtDate(data.periodo_hasta)}
          </Typography>
        </Box>
        <Chip label={estadoLabel[data.estado] || data.estado} color={estadoColor[data.estado] || "default"} size="small" />
        <Box sx={{ ml: "auto", display: "flex", gap: 2 }}>
          <Box textAlign="center">
            <Typography variant="h6" color="success.main">{data.stats.conciliadas}</Typography>
            <Typography variant="caption">Conciliadas</Typography>
          </Box>
          {data.stats.sin_correspondencia > 0 && (
            <Box textAlign="center">
              <Typography variant="h6" color="text.secondary">{data.stats.sin_correspondencia}</Typography>
              <Typography variant="caption">Sin corresp.</Typography>
            </Box>
          )}
          <Box textAlign="center">
            <Typography variant="h6" color="warning.main">{data.stats.pendientes}</Typography>
            <Typography variant="caption">Pendientes</Typography>
          </Box>
          <Box textAlign="center">
            <Typography variant="h6">{data.stats.total}</Typography>
            <Typography variant="caption">Total</Typography>
          </Box>
        </Box>
        <Box sx={{ display: "flex", gap: 1, alignItems: "center" }}>
          <Typography variant="body2" color="text.secondary">
            Saldo banco ({data.cuenta?.moneda || "GS"}):
          </Typography>
          <Typography variant="body2">
            <b>{fmtGs(data.saldo_inicial)}</b> → <b>{fmtGs(data.saldo_final)}</b>
          </Typography>
        </Box>
        <Button
          size="small"
          variant={showDiferencias ? "contained" : "outlined"}
          color="warning"
          sx={{ ml: "auto", fontSize: 11 }}
          onClick={() => setShowDiferencias((v) => !v)}
        >
          {showDiferencias ? "← Líneas" : "Diferencias ⚠"}
        </Button>
      </Box>

      {/* Buscador */}
      <Box sx={{ p: 1, borderBottom: "1px solid #f0f0f0" }}>
        <TextField
          size="small"
          placeholder="Buscar descripción o referencia…"
          value={buscar}
          onChange={(e) => setBuscar(e.target.value)}
          sx={{ width: 300 }}
          InputProps={{
            endAdornment: buscar ? (
              <IconButton size="small" onClick={() => setBuscar("")}>
                <Close fontSize="small" />
              </IconButton>
            ) : null,
          }}
        />
        <Typography variant="caption" sx={{ ml: 1, color: "text.secondary" }}>
          {lineasFiltradas.length} de {data.lineas.length} líneas
        </Typography>
      </Box>

      {/* Diferencias panel */}
      {showDiferencias && (
        <Box sx={{ flex: 1, overflow: "auto", p: 2 }}>
          <Typography variant="subtitle2" color="error" gutterBottom>En banco, no en sistema ({diferencias?.en_banco?.length ?? 0})</Typography>
          {diferencias?.en_banco?.length > 0 ? (
            <Tabla $dark={isDark} style={{ marginBottom: 24 }}>
              <thead><tr><th>Fecha</th><th>Descripción</th><th style={{ textAlign: "right" }}>Débito</th><th style={{ textAlign: "right" }}>Crédito</th></tr></thead>
              <tbody>
                {diferencias.en_banco.map((l) => (
                  <tr key={l.id}>
                    <td style={{ whiteSpace: "nowrap" }}>{fmtDate(l.fecha)}</td>
                    <td>{l.descripcion || "—"}{l.referencia && <span style={{ color: "#888", fontSize: 11 }}> · {l.referencia}</span>}</td>
                    <td style={{ textAlign: "right", color: "#d32f2f" }}>{l.debito > 0 ? fmtGs(l.debito) : ""}</td>
                    <td style={{ textAlign: "right", color: "#2e7d32" }}>{l.credito > 0 ? fmtGs(l.credito) : ""}</td>
                  </tr>
                ))}
              </tbody>
            </Tabla>
          ) : <Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>Sin partidas pendientes en extracto.</Typography>}

          <Typography variant="subtitle2" color="warning.main" gutterBottom>En sistema, no en banco ({diferencias?.en_sistema?.length ?? 0})</Typography>
          {diferencias?.en_sistema?.length > 0 ? (
            <Tabla $dark={isDark}>
              <thead><tr><th>Fecha</th><th>Descripción</th><th>Categoría</th><th>Tipo</th><th style={{ textAlign: "right" }}>Monto</th></tr></thead>
              <tbody>
                {diferencias.en_sistema.map((m) => (
                  <tr key={m.id}>
                    <td style={{ whiteSpace: "nowrap" }}>{fmtDate(m.fecha)}</td>
                    <td>{m.descripcion || "—"}</td>
                    <td style={{ fontSize: 11, color: "#888" }}>{m.detalles?.map((d) => d.categoria?.nombre).filter(Boolean).join(", ") || "—"}</td>
                    <td><Chip label={m.tipo} size="small" color={m.tipo === "INGRESO" ? "success" : "error"} sx={{ fontSize: 10, height: 18 }} /></td>
                    <td style={{ textAlign: "right" }}>{fmtGs(m.monto)}</td>
                  </tr>
                ))}
              </tbody>
            </Tabla>
          ) : <Typography variant="body2" color="text.secondary">Sin movimientos del sistema sin conciliar en este período.</Typography>}
        </Box>
      )}

      {/* Tabla de líneas */}
      {!showDiferencias && <Box sx={{ flex: 1, overflow: "auto" }}>
        <Tabla $dark={isDark}>
          <thead>
            <tr>
              <th style={{ width: 32 }}></th>
              <th>Fecha</th>
              <th>Descripción / Referencia</th>
              <th style={{ textAlign: "right" }}>Débito</th>
              <th style={{ textAlign: "right" }}>Crédito</th>
              <th>Movimiento vinculado</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {lineasFiltradas.map((l) => (
              <>
                <LineaRow key={l.id} $conciliado={l.conciliado} $sinCorrespondencia={l.sin_correspondencia} $dark={isDark}>
                  <td>
                    {l.conciliado
                      ? <CheckCircle fontSize="small" color="success" />
                      : l.sin_correspondencia
                      ? <Tooltip title="Sin correspondencia bancaria"><Block fontSize="small" sx={{ color: "#9e9e9e" }} /></Tooltip>
                      : <RadioButtonUnchecked fontSize="small" color="disabled" />}
                  </td>
                  <td style={{ whiteSpace: "nowrap" }}>{fmtDate(l.fecha)}</td>
                  <td>
                    <div>{l.descripcion || "—"}</div>
                    {l.referencia && <div style={{ color: "#888", fontSize: 11 }}>{l.referencia}</div>}
                    {l.sin_correspondencia && <div style={{ color: "#9e9e9e", fontSize: 11, fontStyle: "italic" }}>Sin correspondencia</div>}
                  </td>
                  <td style={{ textAlign: "right", color: "#d32f2f" }}>{l.debito > 0 ? fmtGs(l.debito) : ""}</td>
                  <td style={{ textAlign: "right", color: "#2e7d32" }}>{l.credito > 0 ? fmtGs(l.credito) : ""}</td>
                  <td>
                    {l.conciliado && l.movimiento ? (
                      <Typography variant="caption">
                        {fmtDate(l.movimiento.fecha)} — {l.movimiento.tipo} — {fmtGs(l.movimiento.monto)}
                        {l.movimiento.descripcion && <span style={{ color: "#888" }}> · {l.movimiento.descripcion.substring(0, 30)}</span>}
                      </Typography>
                    ) : !l.conciliado && !l.sin_correspondencia && expandLinea === l.id ? (
                      <ConciliarSelector linea={l} movimientos={movimientos} extractoId={extractoId} onDone={() => setExpandLinea(null)} />
                    ) : null}
                  </td>
                  <td>
                    <Box sx={{ display: "flex", gap: 0.5, alignItems: "center" }}>
                      {l.conciliado ? (
                        <Tooltip title="Desconciliar">
                          <IconButton size="small" onClick={() => desconciliar.mutate(l.id)}>
                            <LinkOff fontSize="small" />
                          </IconButton>
                        </Tooltip>
                      ) : l.sin_correspondencia ? (
                        <Tooltip title="Quitar marca sin correspondencia">
                          <IconButton size="small" onClick={() => desmarcarSC.mutate(l.id)}>
                            <LinkOff fontSize="small" />
                          </IconButton>
                        </Tooltip>
                      ) : (
                        <Box sx={{ display: "flex", gap: 0.5 }}>
                          <Button size="small" variant="outlined" sx={{ fontSize: 11, py: 0.25 }} onClick={() => setExpandLinea(expandLinea === l.id ? null : l.id)}>
                            {expandLinea === l.id ? "Cancelar" : "Conciliar"}
                          </Button>
                          <Tooltip title="Registrar movimiento nuevo para esta línea">
                            <Button size="small" variant="outlined" color="secondary" sx={{ fontSize: 11, py: 0.25 }} onClick={() => setCrearMovLinea(l)}>
                              + Mov.
                            </Button>
                          </Tooltip>
                          <Tooltip title="Marcar como sin correspondencia (comisión, cargo bancario sin movimiento)">
                            <IconButton size="small" onClick={() => marcarSC.mutate(l.id)}>
                              <Block fontSize="small" />
                            </IconButton>
                          </Tooltip>
                        </Box>
                      )}
                    </Box>
                  </td>
                </LineaRow>
              </>
            ))}
            {lineasFiltradas.length === 0 && (
              <tr>
                <td colSpan={7} style={{ textAlign: "center", padding: 16, color: "#888" }}>
                  Sin resultados
                </td>
              </tr>
            )}
          </tbody>
        </Tabla>
      </Box>}
      <CrearMovimientoDialog
        open={!!crearMovLinea}
        linea={crearMovLinea}
        extractoId={extractoId}
        onClose={() => setCrearMovLinea(null)}
      />
    </Box>
  );
}

// ── Componente principal ───────────────────────────────────────────────────────
export const ConciliacionTab = () => {
  const theme = useTheme();
  const [selectedCuenta, setSelectedCuenta] = useState("");
  const [selectedExtracto, setSelectedExtracto] = useState(null);
  const [showImport, setShowImport] = useState(false);
  const { data: cuentas = [] } = useTesCuentasQuery();
  const { data: extractos = [], isLoading } = useTesExtractosQuery(selectedCuenta ? { cuenta_id: selectedCuenta } : {});
  const eliminar = useEliminarExtractoMutation();

  return (
    <Layout>
      {/* Panel izquierdo: lista de extractos */}
      <LeftPanel>
        <Box sx={{ display: "flex", gap: 1, alignItems: "center" }}>
          <FormControl size="small" sx={{ flex: 1 }}>
            <InputLabel>Filtrar cuenta</InputLabel>
            <Select
              value={selectedCuenta}
              label="Filtrar cuenta"
              onChange={(e) => {
                setSelectedCuenta(e.target.value);
                setSelectedExtracto(null);
              }}
            >
              <MenuItem value="">Todas</MenuItem>
              {cuentas
                .filter((c) => c.activo)
                .map((c) => (
                  <MenuItem key={c.id} value={c.id}>
                    {c.nombre}
                  </MenuItem>
                ))}
            </Select>
          </FormControl>
          <Tooltip title="Importar extracto (PDF con IA o CSV)">
            <IconButton color="primary" onClick={() => setShowImport(true)}>
              <Add />
            </IconButton>
          </Tooltip>
        </Box>

        <Divider />

        {isLoading && <CircularProgress size={24} sx={{ mx: "auto", mt: 2 }} />}

        {!isLoading && extractos.length === 0 && (
          <Typography color="text.secondary" variant="body2" sx={{ textAlign: "center", mt: 2 }}>
            No hay extractos importados.{"\n"}Importá uno con el botón +
          </Typography>
        )}

        {extractos.map((ex) => (
          <ExtractoCard key={ex.id} $selected={selectedExtracto === ex.id} $dark={theme.palette.mode === "dark"} onClick={() => setSelectedExtracto(ex.id)}>
            <Box sx={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
              <Typography variant="body2" fontWeight={600}>
                {ex.cuenta?.nombre}
              </Typography>
              <Box sx={{ display: "flex", gap: 0.5 }}>
                <Chip label={estadoLabel[ex.estado] || ex.estado} color={estadoColor[ex.estado] || "default"} size="small" sx={{ fontSize: 10, height: 18 }} />
                <Tooltip title="Eliminar extracto">
                  <IconButton
                    size="small"
                    color="error"
                    onClick={(e) => {
                      e.stopPropagation();
                      eliminar.mutate(ex.id);
                      if (selectedExtracto === ex.id) setSelectedExtracto(null);
                    }}
                    sx={{ "&:hover": { bgcolor: "error.main", color: "#fff" } }}
                  >
                    <Delete fontSize="small" />
                  </IconButton>
                </Tooltip>
              </Box>
            </Box>
            <Typography variant="caption" color="text.secondary">
              {fmtDate(ex.periodo_desde)} → {fmtDate(ex.periodo_hasta)}
            </Typography>
            <Box sx={{ display: "flex", alignItems: "center", gap: 0.5, mt: 0.25 }}>
              {ex.archivo_nombre?.toLowerCase().endsWith(".pdf") && <Chip label="✨ IA" size="small" sx={{ fontSize: 9, height: 16, background: "#f3e8ff", color: "#7c3aed", fontWeight: 700 }} />}
              {ex.archivo_nombre && (
                <Typography variant="caption" sx={{ color: "#888", fontSize: 10 }} noWrap>
                  {ex.archivo_nombre}
                </Typography>
              )}
            </Box>
          </ExtractoCard>
        ))}
      </LeftPanel>

      {/* Panel derecho: detalle */}
      <RightPanel>
        {selectedExtracto ? (
          <ExtractoDetalle extractoId={selectedExtracto} />
        ) : (
          <Box sx={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", color: "text.secondary" }}>
            <Box textAlign="center">
              <Typography variant="h6" gutterBottom>
                Conciliación Bancaria
              </Typography>
              <Typography>Seleccioná un extracto para ver y conciliar sus líneas</Typography>
              <Button variant="contained" startIcon={<AutoAwesome />} sx={{ mt: 2, background: "#7c3aed", "&:hover": { background: "#6d28d9" } }} onClick={() => setShowImport(true)}>
                Importar Extracto
              </Button>
            </Box>
          </Box>
        )}
      </RightPanel>

      <ImportDialog open={showImport} onClose={() => setShowImport(false)} cuentas={cuentas} />
    </Layout>
  );
};
