'use client';

import { useState, useRef, useCallback, useEffect } from 'react';
import { useDebounce } from '@horux/shared-ui';
import { Header } from '@/components/layouts/header';
import { Card, CardContent, CardHeader, CardTitle, CardDescription, Button, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, Popover, PopoverTrigger, PopoverContent } from '@horux/shared-ui';
import { useCfdis, useCreateCfdi, useDeleteCfdi } from '@/lib/hooks/use-cfdi';
import { createManyCfdis, searchEmisores, searchReceptores, type EmisorReceptor } from '@/lib/api/cfdi';
import { cancelarFactura } from '@/lib/api/facturacion';
import type { CfdiFilters, TipoCfdi, Cfdi } from '@horux/shared';
import type { CreateCfdiData } from '@/lib/api/cfdi';
import { FileText, Search, ChevronLeft, ChevronRight, Plus, Upload, Trash2, X, FileUp, CheckCircle, AlertCircle, Loader2, Eye, Filter, XCircle, Calendar, User, Building2, Download, Printer } from 'lucide-react';
import * as XLSX from 'xlsx';
import { saveAs } from 'file-saver';
import { CfdiViewerModal } from '@/components/cfdi/cfdi-viewer-modal';
import { getCfdiById } from '@/lib/api/cfdi';
import { useAuthStore } from '@/stores/auth-store';
import { useTenantViewStore } from '@/stores/tenant-view-store';
import { useContribuyenteStore } from '@/stores/contribuyente-store';
import { useQueryClient } from '@tanstack/react-query';

// Upload progress state
interface UploadProgress {
  status: 'idle' | 'parsing' | 'uploading' | 'complete' | 'error';
  totalFiles: number;
  parsedFiles: number;
  validFiles: number;
  currentBatch: number;
  totalBatches: number;
  uploaded: number;
  duplicates: number;
  errors: number;
  errorMessages: string[];
}

type CfdiTipo = 'EMITIDO' | 'RECIBIDO';

const initialFormData: CreateCfdiData = {
  uuid: '',
  type: 'EMITIDO',
  serie: '',
  folio: '',
  fechaEmision: new Date().toISOString().split('T')[0],
  rfcEmisor: '',
  nombreEmisor: '',
  rfcReceptor: '',
  nombreReceptor: '',
  subtotal: 0,
  descuento: 0,
  ivaTraslado: 0,
  isrRetencion: 0,
  ivaRetencion: 0,
  total: 0,
  moneda: 'MXN',
  metodoPago: 'PUE',
  formaPago: '03',
  usoCfdi: 'G03',
};

// Helper function to find element regardless of namespace prefix
function findElement(doc: Document, localName: string): Element | null {
  // Try common prefixes first (most reliable for CFDI)
  const prefixes = ['cfdi', 'tfd', 'pago20', 'pago10', 'nomina12', ''];
  for (const prefix of prefixes) {
    const tagName = prefix ? `${prefix}:${localName}` : localName;
    const el = doc.getElementsByTagName(tagName)[0] as Element;
    if (el) return el;
  }

  // Try with wildcard - search all elements by localName
  const elements = doc.getElementsByTagName('*');
  for (let i = 0; i < elements.length; i++) {
    if (elements[i].localName === localName) {
      return elements[i];
    }
  }

  return null;
}

// Parse CFDI XML and extract data
function parseCfdiXml(xmlString: string, tenantRfc: string): CreateCfdiData | null {
  try {
    const parser = new DOMParser();
    const doc = parser.parseFromString(xmlString, 'text/xml');

    // Check for parse errors
    const parseError = doc.querySelector('parsererror');
    if (parseError) {
      console.error('XML parse error:', parseError.textContent);
      return null;
    }

    // Get the Comprobante element (root)
    const comprobante = findElement(doc, 'Comprobante');
    if (!comprobante) {
      console.error('No se encontro elemento Comprobante');
      return null;
    }

    // Get TimbreFiscalDigital for UUID
    const timbre = findElement(doc, 'TimbreFiscalDigital');
    const uuid = timbre?.getAttribute('UUID') || '';
    const fechaTimbradoRaw = timbre?.getAttribute('FechaTimbrado') || '';

    // Get Emisor
    const emisor = findElement(doc, 'Emisor');
    const rfcEmisor = emisor?.getAttribute('Rfc') || emisor?.getAttribute('rfc') || '';
    const nombreEmisor = emisor?.getAttribute('Nombre') || emisor?.getAttribute('nombre') || '';

    // Get Receptor
    const receptor = findElement(doc, 'Receptor');
    const rfcReceptor = receptor?.getAttribute('Rfc') || receptor?.getAttribute('rfc') || '';
    const nombreReceptor = receptor?.getAttribute('Nombre') || receptor?.getAttribute('nombre') || '';
    const usoCfdi = receptor?.getAttribute('UsoCFDI') || '';

    // Determine type based on tenant RFC
    // If tenant is emisor -> ingreso (we issued the invoice)
    // If tenant is receptor -> egreso (we received the invoice)
    const tenantRfcUpper = tenantRfc.toUpperCase();
    let tipoFinal: CreateCfdiData['type'];
    if (rfcEmisor.toUpperCase() === tenantRfcUpper) {
      tipoFinal = 'EMITIDO';
    } else {
      tipoFinal = 'RECIBIDO';
    }

    // Get impuestos - search for the Impuestos element that is direct child of Comprobante
    // (not the ones inside Conceptos)
    let totalImpuestosTrasladados = 0;
    let totalImpuestosRetenidos = 0;

    // Try to get TotalImpuestosTrasladados from Comprobante's direct Impuestos child
    const allImpuestos = doc.getElementsByTagName('*');
    for (let i = 0; i < allImpuestos.length; i++) {
      const el = allImpuestos[i];
      if (el.localName === 'Impuestos' && el.parentElement?.localName === 'Comprobante') {
        totalImpuestosTrasladados = parseFloat(el.getAttribute('TotalImpuestosTrasladados') || '0');
        totalImpuestosRetenidos = parseFloat(el.getAttribute('TotalImpuestosRetenidos') || '0');
        break;
      }
    }

    // Fallback: calculate IVA from total - subtotal if not found
    const subtotal = parseFloat(comprobante.getAttribute('SubTotal') || '0');
    const descuento = parseFloat(comprobante.getAttribute('Descuento') || '0');
    const total = parseFloat(comprobante.getAttribute('Total') || '0');

    if (totalImpuestosTrasladados === 0 && total > subtotal) {
      totalImpuestosTrasladados = Math.max(0, total - subtotal + descuento + totalImpuestosRetenidos);
    }

    // Get retenciones breakdown
    let isrRetenido = 0;
    let ivaRetenido = 0;
    const retenciones = doc.querySelectorAll('[localName="Retencion"], Retencion, cfdi\\:Retencion');
    retenciones.forEach((ret: Element) => {
      const impuesto = ret.getAttribute('Impuesto');
      const importe = parseFloat(ret.getAttribute('Importe') || '0');
      if (impuesto === '001') isrRetenido = importe; // ISR
      if (impuesto === '002') ivaRetenido = importe; // IVA
    });

    // Parse dates - handle both ISO format and datetime format
    const fechaEmisionRaw = comprobante.getAttribute('Fecha') || '';
    const fechaEmision = fechaEmisionRaw.includes('T') ? fechaEmisionRaw.split('T')[0] : fechaEmisionRaw;
    const fechaTimbrado = fechaTimbradoRaw.includes('T') ? fechaTimbradoRaw.split('T')[0] : fechaTimbradoRaw;

    // Validate required fields
    if (!uuid) {
      console.error('UUID no encontrado en el XML');
      return null;
    }
    if (!rfcEmisor || !rfcReceptor) {
      console.error('RFC emisor o receptor no encontrado');
      return null;
    }
    if (!fechaEmision) {
      console.error('Fecha de emision no encontrada');
      return null;
    }

    return {
      uuid: uuid.toUpperCase(),
      type: tipoFinal,
      serie: comprobante.getAttribute('Serie') || '',
      folio: comprobante.getAttribute('Folio') || '',
      fechaEmision,
      rfcEmisor,
      nombreEmisor: nombreEmisor || 'Sin nombre',
      rfcReceptor,
      nombreReceptor: nombreReceptor || 'Sin nombre',
      subtotal,
      descuento,
      ivaTraslado: totalImpuestosTrasladados,
      isrRetencion: isrRetenido,
      ivaRetencion: ivaRetenido,
      total,
      moneda: comprobante.getAttribute('Moneda') || 'MXN',
      tipoCambio: parseFloat(comprobante.getAttribute('TipoCambio') || '1'),
      tipoComprobante: comprobante.getAttribute('TipoDeComprobante') || '',
      metodoPago: comprobante.getAttribute('MetodoPago') || '',
      formaPago: comprobante.getAttribute('FormaPago') || '',
      usoCfdi,
    };
  } catch (error) {
    console.error('Error parsing XML:', error);
    return null;
  }
}

const TIPO_COMPROBANTE_LABELS: Record<string, string> = {
  I: 'Ingreso',
  E: 'Egreso',
  P: 'Pago',
  T: 'Traslado',
  N: 'Nómina',
};

function formatTipoComprobante(value: string | null | undefined): string {
  if (!value) return '';
  const upper = value.toUpperCase();
  return TIPO_COMPROBANTE_LABELS[upper] ? `${upper} - ${TIPO_COMPROBANTE_LABELS[upper]}` : upper;
}

// Chunk size for batch uploads
const PARSE_CHUNK_SIZE = 500; // Parse 500 files at a time
const UPLOAD_CHUNK_SIZE = 200; // Upload 200 CFDIs per request

export default function CfdiPage() {
  const { user } = useAuthStore();
  const { viewingTenantRfc } = useTenantViewStore();
  const { selectedContribuyenteId } = useContribuyenteStore();
  const fileInputRef = useRef<HTMLInputElement>(null);
  const queryClient = useQueryClient();

  // Get the effective tenant RFC (viewing tenant or user's tenant)
  const tenantRfc = viewingTenantRfc || user?.tenantRfc || '';
  const [filters, setFilters] = useState<CfdiFilters>({
    page: 1,
    limit: 20,
  });

  const [searchTerm, setSearchTerm] = useState('');
  const [columnFilters, setColumnFilters] = useState({
    fechaInicio: '',
    fechaFin: '',
    emisor: '',
    receptor: '',
  });

  // Reset pagination and filters when contribuyente changes
  useEffect(() => {
    setFilters({ page: 1, limit: 20 });
    setSearchTerm('');
    setColumnFilters({ fechaInicio: '', fechaFin: '', emisor: '', receptor: '' });
  }, [selectedContribuyenteId]);
  const [openFilter, setOpenFilter] = useState<'fecha' | 'emisor' | 'receptor' | null>(null);
  const [emisorSuggestions, setEmisorSuggestions] = useState<EmisorReceptor[]>([]);
  const [receptorSuggestions, setReceptorSuggestions] = useState<EmisorReceptor[]>([]);
  const [loadingEmisor, setLoadingEmisor] = useState(false);
  const [loadingReceptor, setLoadingReceptor] = useState(false);
  const [showForm, setShowForm] = useState(false);

  // Debounced values for autocomplete
  const debouncedEmisor = useDebounce(columnFilters.emisor, 300);
  const debouncedReceptor = useDebounce(columnFilters.receptor, 300);

  // Fetch emisor suggestions when debounced value changes
  useEffect(() => {
    if (debouncedEmisor.length < 2) {
      setEmisorSuggestions([]);
      return;
    }
    setLoadingEmisor(true);
    searchEmisores(debouncedEmisor)
      .then(setEmisorSuggestions)
      .catch(() => setEmisorSuggestions([]))
      .finally(() => setLoadingEmisor(false));
  }, [debouncedEmisor]);

  // Fetch receptor suggestions when debounced value changes
  useEffect(() => {
    if (debouncedReceptor.length < 2) {
      setReceptorSuggestions([]);
      return;
    }
    setLoadingReceptor(true);
    searchReceptores(debouncedReceptor)
      .then(setReceptorSuggestions)
      .catch(() => setReceptorSuggestions([]))
      .finally(() => setLoadingReceptor(false));
  }, [debouncedReceptor]);

  const [showBulkForm, setShowBulkForm] = useState(false);
  const [formData, setFormData] = useState<CreateCfdiData>(initialFormData);
  const [bulkData, setBulkData] = useState('');
  const [uploadMode, setUploadMode] = useState<'xml' | 'json'>('xml');
  const [jsonUploading, setJsonUploading] = useState(false);

  // Optimized upload state
  const [uploadProgress, setUploadProgress] = useState<UploadProgress>({
    status: 'idle',
    totalFiles: 0,
    parsedFiles: 0,
    validFiles: 0,
    currentBatch: 0,
    totalBatches: 0,
    uploaded: 0,
    duplicates: 0,
    errors: 0,
    errorMessages: []
  });
  const [parsedCfdis, setParsedCfdis] = useState<CreateCfdiData[]>([]);
  const uploadAbortRef = useRef(false);

  const { data, isLoading } = useCfdis(filters);
  const createCfdi = useCreateCfdi();
  const deleteCfdi = useDeleteCfdi();

  // CFDI Viewer state
  const [viewingCfdi, setViewingCfdi] = useState<Cfdi | null>(null);
  const [loadingCfdi, setLoadingCfdi] = useState<string | null>(null);

  // Cancelación Facturapi state
  const [cancelTarget, setCancelTarget] = useState<any | null>(null);
  const [cancelMotive, setCancelMotive] = useState<'01' | '02' | '03' | '04'>('02');
  const [cancelSubstitution, setCancelSubstitution] = useState('');
  const [cancelling, setCancelling] = useState(false);

  const handleViewCfdi = async (id: string) => {
    setLoadingCfdi(id);
    try {
      const cfdi = await getCfdiById(id);
      setViewingCfdi(cfdi);
    } catch (error) {
      console.error('Error loading CFDI:', error);
      alert('Error al cargar el CFDI');
    } finally {
      setLoadingCfdi(null);
    }
  };

  const canEdit = user?.role === 'owner' || user?.role === 'cfo' || user?.role === 'contador' || user?.role === 'auxiliar';

  const handleSearch = () => {
    setFilters({ ...filters, search: searchTerm, page: 1 });
  };

  // Export to Excel
  const [exporting, setExporting] = useState(false);

  const exportToExcel = async () => {
    if (!data?.data.length) return;

    setExporting(true);
    try {
      const exportData = data.data.map(cfdi => ({
        'Fecha Emisión': new Date(cfdi.fechaEmision).toLocaleDateString('es-MX'),
        'Tipo Comprobante': formatTipoComprobante(cfdi.tipoComprobante),
        'Serie': cfdi.serie || '',
        'Folio': cfdi.folio || '',
        'RFC Emisor': cfdi.rfcEmisor,
        'Nombre Emisor': cfdi.nombreEmisor,
        'RFC Receptor': cfdi.rfcReceptor,
        'Nombre Receptor': cfdi.nombreReceptor,
        'Subtotal': cfdi.subtotal,
        'IVA': cfdi.ivaTraslado,
        'Total': cfdi.total,
        'Moneda': cfdi.moneda,
        'Estatus': cfdi.status === 'Vigente' || cfdi.status === '1' ? 'Vigente' : 'Cancelado',
        'Fecha Cancelación': cfdi.fechaCancelacion
          ? new Date(cfdi.fechaCancelacion).toLocaleDateString('es-MX')
          : '',
        'UUID': cfdi.uuid,
      }));

      const ws = XLSX.utils.json_to_sheet(exportData);
      const wb = XLSX.utils.book_new();
      XLSX.utils.book_append_sheet(wb, ws, 'CFDIs');

      // Auto-size columns
      const colWidths = Object.keys(exportData[0]).map(key => ({
        wch: Math.max(key.length, ...exportData.map(row => String(row[key as keyof typeof row]).length))
      }));
      ws['!cols'] = colWidths;

      const excelBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
      const blob = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });

      const fileName = `cfdis_${new Date().toISOString().split('T')[0]}.xlsx`;
      saveAs(blob, fileName);
    } catch (error) {
      console.error('Error exporting:', error);
      alert('Error al exportar');
    } finally {
      setExporting(false);
    }
  };

  const exportSingleCfdiToExcel = (cfdi: Cfdi) => {
    const row = {
      'Fecha Emisión': new Date(cfdi.fechaEmision).toLocaleDateString('es-MX'),
      'Tipo Comprobante': formatTipoComprobante(cfdi.tipoComprobante),
      'Serie': cfdi.serie || '',
      'Folio': cfdi.folio || '',
      'RFC Emisor': cfdi.rfcEmisor,
      'Nombre Emisor': cfdi.nombreEmisor,
      'RFC Receptor': cfdi.rfcReceptor,
      'Nombre Receptor': cfdi.nombreReceptor,
      'Subtotal': cfdi.subtotal,
      'IVA': cfdi.ivaTraslado,
      'Total': cfdi.total,
      'Moneda': cfdi.moneda,
      'Estatus': cfdi.status === 'Vigente' || cfdi.status === '1' ? 'Vigente' : 'Cancelado',
      'Fecha Cancelación': cfdi.fechaCancelacion
        ? new Date(cfdi.fechaCancelacion).toLocaleDateString('es-MX')
        : '',
      'UUID': cfdi.uuid,
    };

    const ws = XLSX.utils.json_to_sheet([row]);
    ws['!cols'] = Object.keys(row).map((key) => ({
      wch: Math.max(key.length, String(row[key as keyof typeof row] ?? '').length),
    }));

    const wb = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(wb, ws, 'CFDI');

    const buffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
    const blob = new Blob([buffer], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    });

    const idParte = [cfdi.serie, cfdi.folio].filter(Boolean).join('-') || cfdi.uuid.slice(0, 8);
    saveAs(blob, `cfdi_${idParte}.xlsx`);
  };

  const selectEmisor = (emisor: EmisorReceptor) => {
    setColumnFilters(prev => ({ ...prev, emisor: emisor.nombre }));
    setEmisorSuggestions([]);
  };

  const selectReceptor = (receptor: EmisorReceptor) => {
    setColumnFilters(prev => ({ ...prev, receptor: receptor.nombre }));
    setReceptorSuggestions([]);
  };

  const applyDateFilter = () => {
    setFilters({
      ...filters,
      fechaInicio: columnFilters.fechaInicio || undefined,
      fechaFin: columnFilters.fechaFin || undefined,
      page: 1,
    });
    setOpenFilter(null);
  };

  const applyEmisorFilter = () => {
    setFilters({
      ...filters,
      emisor: columnFilters.emisor || undefined,
      page: 1,
    });
    setOpenFilter(null);
  };

  const applyReceptorFilter = () => {
    setFilters({
      ...filters,
      receptor: columnFilters.receptor || undefined,
      page: 1,
    });
    setOpenFilter(null);
  };

  const clearDateFilter = () => {
    setColumnFilters({ ...columnFilters, fechaInicio: '', fechaFin: '' });
    setFilters({ ...filters, fechaInicio: undefined, fechaFin: undefined, page: 1 });
    setOpenFilter(null);
  };

  const clearEmisorFilter = () => {
    setColumnFilters({ ...columnFilters, emisor: '' });
    setFilters({ ...filters, emisor: undefined, page: 1 });
    setOpenFilter(null);
  };

  const clearReceptorFilter = () => {
    setColumnFilters({ ...columnFilters, receptor: '' });
    setFilters({ ...filters, receptor: undefined, page: 1 });
    setOpenFilter(null);
  };

  const hasDateFilter = filters.fechaInicio || filters.fechaFin;
  const hasEmisorFilter = filters.emisor;
  const hasReceptorFilter = filters.receptor;
  const hasActiveColumnFilters = hasDateFilter || hasEmisorFilter || hasReceptorFilter;

  const handleFilterType = (tipo?: TipoCfdi) => {
    setFilters({ ...filters, tipo, page: 1 });
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    try {
      await createCfdi.mutateAsync(formData);
      setFormData(initialFormData);
      setShowForm(false);
    } catch (error: any) {
      alert(error.response?.data?.message || 'Error al crear CFDI');
    }
  };

  const handleBulkSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setJsonUploading(true);
    try {
      const cfdis = JSON.parse(bulkData);
      if (!Array.isArray(cfdis)) {
        throw new Error('El formato debe ser un array de CFDIs');
      }
      const result = await createManyCfdis(cfdis);
      alert(`Se crearon ${result.inserted} CFDIs exitosamente`);
      setBulkData('');
      setShowBulkForm(false);
      queryClient.invalidateQueries({ queryKey: ['cfdis'] });
    } catch (error: any) {
      alert(error.message || 'Error al procesar CFDIs');
    } finally {
      setJsonUploading(false);
    }
  };

  // Optimized: Parse files in chunks to prevent memory issues
  const handleXmlFilesChange = useCallback(async (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = Array.from(e.target.files || []);
    if (files.length === 0) return;

    uploadAbortRef.current = false;
    setUploadProgress({
      status: 'parsing',
      totalFiles: files.length,
      parsedFiles: 0,
      validFiles: 0,
      currentBatch: 0,
      totalBatches: 0,
      uploaded: 0,
      duplicates: 0,
      errors: 0,
      errorMessages: []
    });
    setParsedCfdis([]);

    const validCfdis: CreateCfdiData[] = [];
    let parsedCount = 0;
    let errorCount = 0;

    // Process in chunks to prevent memory issues
    for (let i = 0; i < files.length; i += PARSE_CHUNK_SIZE) {
      if (uploadAbortRef.current) break;

      const chunk = files.slice(i, i + PARSE_CHUNK_SIZE);

      // Parse chunk in parallel
      const results = await Promise.all(
        chunk.map(async (file) => {
          try {
            const text = await file.text();
            const data = parseCfdiXml(text, tenantRfc);
            return data;
          } catch {
            return null;
          }
        })
      );

      // Collect valid results
      results.forEach((data) => {
        if (data && data.uuid) {
          validCfdis.push(data);
        } else {
          errorCount++;
        }
      });

      parsedCount += chunk.length;

      setUploadProgress(prev => ({
        ...prev,
        parsedFiles: parsedCount,
        validFiles: validCfdis.length,
        errors: errorCount
      }));

      // Small delay to allow UI to update
      await new Promise(r => setTimeout(r, 10));
    }

    setParsedCfdis(validCfdis);
    setUploadProgress(prev => ({
      ...prev,
      status: uploadAbortRef.current ? 'idle' : 'idle',
      totalBatches: Math.ceil(validCfdis.length / UPLOAD_CHUNK_SIZE)
    }));
  }, [tenantRfc]);

  // Optimized: Upload in batches with progress
  const handleXmlBulkSubmit = async (e: React.FormEvent) => {
    e.preventDefault();

    if (parsedCfdis.length === 0) {
      alert('No hay CFDIs validos para cargar');
      return;
    }

    uploadAbortRef.current = false;
    const totalBatches = Math.ceil(parsedCfdis.length / UPLOAD_CHUNK_SIZE);

    setUploadProgress(prev => ({
      ...prev,
      status: 'uploading',
      currentBatch: 0,
      totalBatches,
      uploaded: 0,
      duplicates: 0,
      errors: 0,
      errorMessages: []
    }));

    let totalUploaded = 0;
    let totalDuplicates = 0;
    let totalErrors = 0;
    const allErrors: string[] = [];

    // Upload in batches
    for (let i = 0; i < parsedCfdis.length; i += UPLOAD_CHUNK_SIZE) {
      if (uploadAbortRef.current) break;

      const batchNumber = Math.floor(i / UPLOAD_CHUNK_SIZE) + 1;
      const chunk = parsedCfdis.slice(i, i + UPLOAD_CHUNK_SIZE);

      setUploadProgress(prev => ({
        ...prev,
        currentBatch: batchNumber
      }));

      try {
        const result = await createManyCfdis(chunk, batchNumber, totalBatches, parsedCfdis.length);

        totalUploaded += result.inserted;
        totalDuplicates += result.duplicates;
        totalErrors += result.errors;
        if (result.errorMessages) {
          allErrors.push(...result.errorMessages);
        }

        setUploadProgress(prev => ({
          ...prev,
          uploaded: totalUploaded,
          duplicates: totalDuplicates,
          errors: prev.errors + result.errors,
          errorMessages: allErrors.slice(0, 20) // Limit error messages
        }));
      } catch (error: any) {
        console.error(`Error en lote ${batchNumber}:`, error);
        totalErrors += chunk.length;
        allErrors.push(`Lote ${batchNumber}: ${error.message || 'Error desconocido'}`);

        setUploadProgress(prev => ({
          ...prev,
          errors: prev.errors + chunk.length,
          errorMessages: allErrors.slice(0, 20)
        }));
      }

      // Small delay between batches
      await new Promise(r => setTimeout(r, 100));
    }

    setUploadProgress(prev => ({
      ...prev,
      status: 'complete'
    }));

    // Invalidate queries to refresh the list
    queryClient.invalidateQueries({ queryKey: ['cfdis'] });
  };

  const clearXmlFiles = () => {
    uploadAbortRef.current = true;
    setParsedCfdis([]);
    setUploadProgress({
      status: 'idle',
      totalFiles: 0,
      parsedFiles: 0,
      validFiles: 0,
      currentBatch: 0,
      totalBatches: 0,
      uploaded: 0,
      duplicates: 0,
      errors: 0,
      errorMessages: []
    });
    if (fileInputRef.current) {
      fileInputRef.current.value = '';
    }
  };

  // Keyboard shortcuts - Esc to close popovers and forms
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === 'Escape') {
        // Close open filter popovers
        if (openFilter !== null) {
          setOpenFilter(null);
          return;
        }
        // Close forms
        if (showForm) {
          setShowForm(false);
          return;
        }
        if (showBulkForm) {
          setShowBulkForm(false);
          clearXmlFiles();
          return;
        }
      }
    };

    document.addEventListener('keydown', handleKeyDown);
    return () => document.removeEventListener('keydown', handleKeyDown);
  }, [openFilter, showForm, showBulkForm]);

  const cancelUpload = () => {
    uploadAbortRef.current = true;
    setUploadProgress(prev => ({ ...prev, status: 'idle' }));
  };

  const handleDelete = async (id: string) => {
    if (confirm('¿Eliminar este CFDI?')) {
      try {
        await deleteCfdi.mutateAsync(id);
      } catch (error) {
        console.error('Error deleting CFDI:', error);
      }
    }
  };

  const openCancelDialog = (cfdi: any) => {
    setCancelTarget(cfdi);
    setCancelMotive('02');
    setCancelSubstitution('');
  };

  const handleCancelFactura = async () => {
    if (!cancelTarget) return;
    if (cancelMotive === '01' && cancelSubstitution.trim().length !== 36) {
      alert('El motivo 01 requiere el UUID completo (36 caracteres) de la factura que sustituye a esta.');
      return;
    }
    setCancelling(true);
    try {
      await cancelarFactura(cancelTarget.uuid, cancelMotive, cancelMotive === '01' ? cancelSubstitution.trim() : undefined);
      await queryClient.invalidateQueries({ queryKey: ['cfdis'] });
      setCancelTarget(null);
      alert('Factura cancelada. El estatus final depende del SAT (puede quedar en "pendiente" si requiere aceptación del receptor).');
    } catch (err: any) {
      alert(err?.response?.data?.message || err?.message || 'Error al cancelar la factura');
    } finally {
      setCancelling(false);
    }
  };

  const calculateTotal = () => {
    const subtotal = formData.subtotal || 0;
    const descuento = formData.descuento || 0;
    const iva = formData.ivaTrasladoTraslado || 0;
    const isrRetencion = formData.isrRetencion || 0;
    const ivaRetencion = formData.ivaTrasladoRetencion || 0;
    return subtotal - descuento + iva - isrRetencion - ivaRetencion;
  };

  const formatCurrency = (value: number) =>
    new Intl.NumberFormat('es-MX', {
      style: 'currency',
      currency: 'MXN',
    }).format(value);

  const formatDate = (dateString: string) =>
    new Date(dateString).toLocaleDateString('es-MX', {
      day: '2-digit',
      month: 'short',
      year: 'numeric',
    });

  const generateUUID = () => {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
      const r = Math.random() * 16 | 0;
      const v = c === 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
    }).toUpperCase();
  };

  return (
    <>
      <Header title="Gestion de CFDI" />
      <main className="p-6 space-y-6">
        {/* Filters */}
        <Card>
          <CardContent className="p-4">
            <div className="flex flex-wrap gap-4">
              <div className="flex gap-2 flex-1 min-w-[300px]">
                <Input
                  placeholder="Buscar por UUID, RFC o nombre..."
                  value={searchTerm}
                  onChange={(e) => setSearchTerm(e.target.value)}
                  onKeyDown={(e) => e.key === 'Enter' && handleSearch()}
                />
                <Button onClick={handleSearch}>
                  <Search className="h-4 w-4" />
                </Button>
              </div>
              <div className="flex gap-2">
                <Button
                  variant={filters.tipo === undefined ? 'default' : 'outline'}
                  size="sm"
                  onClick={() => handleFilterType(undefined)}
                >
                  Todos
                </Button>
                <Button
                  variant={filters.tipo === 'EMITIDO' ? 'default' : 'outline'}
                  size="sm"
                  onClick={() => handleFilterType('EMITIDO')}
                >
                  Emitidos
                </Button>
                <Button
                  variant={filters.tipo === 'RECIBIDO' ? 'default' : 'outline'}
                  size="sm"
                  onClick={() => handleFilterType('RECIBIDO')}
                >
                  Recibidos
                </Button>
              </div>
              <div className="flex items-center gap-2">
                <Select
                  value={filters.tipoComprobante ?? 'ALL'}
                  onValueChange={(value) =>
                    setFilters({
                      ...filters,
                      tipoComprobante: value === 'ALL' ? undefined : (value as 'I' | 'E' | 'P' | 'T' | 'N'),
                      page: 1,
                    })
                  }
                >
                  <SelectTrigger className="w-[200px]">
                    <SelectValue placeholder="Tipo de Comprobante" />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="ALL">Todos los comprobantes</SelectItem>
                    <SelectItem value="I">I - Ingreso</SelectItem>
                    <SelectItem value="E">E - Egreso</SelectItem>
                    <SelectItem value="P">P - Pago</SelectItem>
                    <SelectItem value="T">T - Traslado</SelectItem>
                    <SelectItem value="N">N - Nómina</SelectItem>
                  </SelectContent>
                </Select>
              </div>
              <div className="flex gap-2">
                {data && data.data.length > 0 && (
                  <Button variant="outline" onClick={exportToExcel} disabled={exporting}>
                    {exporting ? (
                      <Loader2 className="h-4 w-4 mr-1 animate-spin" />
                    ) : (
                      <Download className="h-4 w-4 mr-1" />
                    )}
                    Exportar
                  </Button>
                )}
                {canEdit && (
                  <>
                    <Button onClick={() => { setShowForm(true); setShowBulkForm(false); }}>
                      <Plus className="h-4 w-4 mr-1" />
                      Agregar
                    </Button>
                    <Button variant="outline" onClick={() => { setShowBulkForm(true); setShowForm(false); }}>
                      <Upload className="h-4 w-4 mr-1" />
                      Carga Masiva
                    </Button>
                  </>
                )}
              </div>
            </div>
          </CardContent>
        </Card>

        {/* Add CFDI Form */}
        {showForm && canEdit && (
          <Card>
            <CardHeader>
              <div className="flex items-center justify-between">
                <div>
                  <CardTitle className="text-base">Agregar CFDI</CardTitle>
                  <CardDescription>Ingresa los datos del comprobante fiscal</CardDescription>
                </div>
                <Button variant="ghost" size="icon" onClick={() => setShowForm(false)}>
                  <X className="h-4 w-4" />
                </Button>
              </div>
            </CardHeader>
            <CardContent>
              <form onSubmit={handleSubmit} className="space-y-4">
                <div className="grid gap-4 md:grid-cols-3">
                  <div className="space-y-2">
                    <Label>UUID Fiscal</Label>
                    <div className="flex gap-2">
                      <Input
                        value={formData.uuid}
                        onChange={(e) => setFormData({ ...formData, uuid: e.target.value.toUpperCase() })}
                        placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
                        required
                      />
                      <Button type="button" variant="outline" onClick={() => setFormData({ ...formData, uuid: generateUUID() })}>
                        Gen
                      </Button>
                    </div>
                  </div>
                  <div className="space-y-2">
                    <Label>Tipo</Label>
                    <Select
                      value={formData.type}
                      onValueChange={(v) => setFormData({ ...formData, type: v as CfdiTipo })}
                    >
                      <SelectTrigger>
                        <SelectValue />
                      </SelectTrigger>
                      <SelectContent>
                        <SelectItem value="EMITIDO">Emitido</SelectItem>
                        <SelectItem value="RECIBIDO">Recibido</SelectItem>
                      </SelectContent>
                    </Select>
                  </div>
                  <div className="grid grid-cols-2 gap-2">
                    <div className="space-y-2">
                      <Label>Serie</Label>
                      <Input
                        value={formData.serie}
                        onChange={(e) => setFormData({ ...formData, serie: e.target.value })}
                        placeholder="A"
                      />
                    </div>
                    <div className="space-y-2">
                      <Label>Folio</Label>
                      <Input
                        value={formData.folio}
                        onChange={(e) => setFormData({ ...formData, folio: e.target.value })}
                        placeholder="001"
                      />
                    </div>
                  </div>
                </div>

                <div className="grid gap-4 md:grid-cols-2">
                  <div className="space-y-2">
                    <Label>Fecha Emision</Label>
                    <Input
                      type="date"
                      value={formData.fechaEmision}
                      onChange={(e) => setFormData({ ...formData, fechaEmision: e.target.value })}
                      required
                    />
                  </div>
                  <div className="space-y-2">
                    <Label>Moneda</Label>
                    <Input
                      value={formData.moneda}
                      onChange={(e) => setFormData({ ...formData, moneda: e.target.value.toUpperCase() })}
                      placeholder="MXN"
                    />
                  </div>
                </div>

                <div className="grid gap-4 md:grid-cols-2">
                  <div className="p-4 border rounded-lg space-y-3">
                    <h4 className="font-medium">Emisor</h4>
                    <div className="space-y-2">
                      <Label>RFC Emisor</Label>
                      <Input
                        value={formData.rfcEmisor}
                        onChange={(e) => setFormData({ ...formData, rfcEmisor: e.target.value.toUpperCase() })}
                        placeholder="XAXX010101000"
                        maxLength={13}
                        required
                      />
                    </div>
                    <div className="space-y-2">
                      <Label>Nombre Emisor</Label>
                      <Input
                        value={formData.nombreEmisor}
                        onChange={(e) => setFormData({ ...formData, nombreEmisor: e.target.value })}
                        placeholder="Empresa Emisora SA de CV"
                        required
                      />
                    </div>
                  </div>
                  <div className="p-4 border rounded-lg space-y-3">
                    <h4 className="font-medium">Receptor</h4>
                    <div className="space-y-2">
                      <Label>RFC Receptor</Label>
                      <Input
                        value={formData.rfcReceptor}
                        onChange={(e) => setFormData({ ...formData, rfcReceptor: e.target.value.toUpperCase() })}
                        placeholder="XAXX010101000"
                        maxLength={13}
                        required
                      />
                    </div>
                    <div className="space-y-2">
                      <Label>Nombre Receptor</Label>
                      <Input
                        value={formData.nombreReceptor}
                        onChange={(e) => setFormData({ ...formData, nombreReceptor: e.target.value })}
                        placeholder="Empresa Receptora SA de CV"
                        required
                      />
                    </div>
                  </div>
                </div>

                <div className="grid gap-4 md:grid-cols-6">
                  <div className="space-y-2">
                    <Label>Subtotal</Label>
                    <Input
                      type="number"
                      step="0.01"
                      value={formData.subtotal}
                      onChange={(e) => setFormData({ ...formData, subtotal: parseFloat(e.target.value) || 0 })}
                      required
                    />
                  </div>
                  <div className="space-y-2">
                    <Label>Descuento</Label>
                    <Input
                      type="number"
                      step="0.01"
                      value={formData.descuento}
                      onChange={(e) => setFormData({ ...formData, descuento: parseFloat(e.target.value) || 0 })}
                    />
                  </div>
                  <div className="space-y-2">
                    <Label>IVA</Label>
                    <Input
                      type="number"
                      step="0.01"
                      value={formData.ivaTraslado}
                      onChange={(e) => setFormData({ ...formData, ivaTraslado: parseFloat(e.target.value) || 0 })}
                    />
                  </div>
                  <div className="space-y-2">
                    <Label>ISR Ret.</Label>
                    <Input
                      type="number"
                      step="0.01"
                      value={formData.isrRetencion}
                      onChange={(e) => setFormData({ ...formData, isrRetencion: parseFloat(e.target.value) || 0 })}
                    />
                  </div>
                  <div className="space-y-2">
                    <Label>IVA Ret.</Label>
                    <Input
                      type="number"
                      step="0.01"
                      value={formData.ivaRetencion}
                      onChange={(e) => setFormData({ ...formData, ivaRetencion: parseFloat(e.target.value) || 0 })}
                    />
                  </div>
                  <div className="space-y-2">
                    <Label>Total</Label>
                    <Input
                      type="number"
                      step="0.01"
                      value={formData.total || calculateTotal()}
                      onChange={(e) => setFormData({ ...formData, total: parseFloat(e.target.value) || 0 })}
                      required
                    />
                  </div>
                </div>

                <div className="flex gap-2 justify-end">
                  <Button type="button" variant="outline" onClick={() => setShowForm(false)}>
                    Cancelar
                  </Button>
                  <Button type="submit" disabled={createCfdi.isPending}>
                    {createCfdi.isPending ? 'Guardando...' : 'Guardar CFDI'}
                  </Button>
                </div>
              </form>
            </CardContent>
          </Card>
        )}

        {/* Bulk Upload Form */}
        {showBulkForm && canEdit && (
          <Card>
            <CardHeader>
              <div className="flex items-center justify-between">
                <div>
                  <CardTitle className="text-base">Carga Masiva de CFDIs</CardTitle>
                  <CardDescription>Sube archivos XML o pega datos en formato JSON</CardDescription>
                </div>
                <Button variant="ghost" size="icon" onClick={() => { setShowBulkForm(false); clearXmlFiles(); }}>
                  <X className="h-4 w-4" />
                </Button>
              </div>
            </CardHeader>
            <CardContent>
              {/* Mode selector */}
              <div className="flex gap-2 mb-4">
                <Button
                  type="button"
                  variant={uploadMode === 'xml' ? 'default' : 'outline'}
                  size="sm"
                  onClick={() => setUploadMode('xml')}
                >
                  <FileUp className="h-4 w-4 mr-1" />
                  Subir XMLs
                </Button>
                <Button
                  type="button"
                  variant={uploadMode === 'json' ? 'default' : 'outline'}
                  size="sm"
                  onClick={() => setUploadMode('json')}
                >
                  JSON
                </Button>
              </div>

              {uploadMode === 'xml' ? (
                <form onSubmit={handleXmlBulkSubmit} className="space-y-4">
                  {/* File input - only show when idle */}
                  {uploadProgress.status === 'idle' && (
                    <div className="space-y-2">
                      <Label>Archivos XML de CFDI</Label>
                      <div className="border-2 border-dashed rounded-lg p-6 text-center">
                        <input
                          ref={fileInputRef}
                          type="file"
                          accept=".xml"
                          multiple
                          onChange={handleXmlFilesChange}
                          className="hidden"
                          id="xml-upload"
                        />
                        <label htmlFor="xml-upload" className="cursor-pointer">
                          <FileUp className="h-10 w-10 mx-auto text-muted-foreground mb-2" />
                          <p className="text-sm text-muted-foreground">
                            Haz clic para seleccionar archivos XML
                          </p>
                          <p className="text-xs text-muted-foreground mt-1">
                            Optimizado para cargas masivas (+100,000 archivos)
                          </p>
                        </label>
                      </div>
                    </div>
                  )}

                  {/* Parsing progress */}
                  {uploadProgress.status === 'parsing' && (
                    <div className="space-y-4">
                      <div className="flex items-center gap-3">
                        <Loader2 className="h-5 w-5 animate-spin text-primary" />
                        <div className="flex-1">
                          <p className="font-medium">Analizando archivos XML...</p>
                          <p className="text-sm text-muted-foreground">
                            {uploadProgress.parsedFiles.toLocaleString()} de {uploadProgress.totalFiles.toLocaleString()} archivos
                          </p>
                        </div>
                        <Button type="button" variant="outline" size="sm" onClick={cancelUpload}>
                          Cancelar
                        </Button>
                      </div>
                      <div className="h-2 bg-muted rounded-full overflow-hidden">
                        <div
                          className="h-full bg-primary transition-all duration-300"
                          style={{ width: `${(uploadProgress.parsedFiles / uploadProgress.totalFiles) * 100}%` }}
                        />
                      </div>
                      <div className="flex justify-between text-xs text-muted-foreground">
                        <span>{uploadProgress.validFiles.toLocaleString()} validos</span>
                        <span>{Math.round((uploadProgress.parsedFiles / uploadProgress.totalFiles) * 100)}%</span>
                      </div>
                    </div>
                  )}

                  {/* Upload progress */}
                  {uploadProgress.status === 'uploading' && (
                    <div className="space-y-4">
                      <div className="flex items-center gap-3">
                        <Loader2 className="h-5 w-5 animate-spin text-primary" />
                        <div className="flex-1">
                          <p className="font-medium">Subiendo CFDIs al servidor...</p>
                          <p className="text-sm text-muted-foreground">
                            Lote {uploadProgress.currentBatch} de {uploadProgress.totalBatches}
                          </p>
                        </div>
                        <Button type="button" variant="outline" size="sm" onClick={cancelUpload}>
                          Cancelar
                        </Button>
                      </div>
                      <div className="h-2 bg-muted rounded-full overflow-hidden">
                        <div
                          className="h-full bg-primary transition-all duration-300"
                          style={{ width: `${(uploadProgress.currentBatch / uploadProgress.totalBatches) * 100}%` }}
                        />
                      </div>
                      <div className="grid grid-cols-3 gap-4 text-center">
                        <div className="p-3 bg-success/10 rounded-lg">
                          <p className="text-2xl font-bold text-success">{uploadProgress.uploaded.toLocaleString()}</p>
                          <p className="text-xs text-muted-foreground">Cargados</p>
                        </div>
                        <div className="p-3 bg-warning/10 rounded-lg">
                          <p className="text-2xl font-bold text-warning">{uploadProgress.duplicates.toLocaleString()}</p>
                          <p className="text-xs text-muted-foreground">Duplicados</p>
                        </div>
                        <div className="p-3 bg-destructive/10 rounded-lg">
                          <p className="text-2xl font-bold text-destructive">{uploadProgress.errors.toLocaleString()}</p>
                          <p className="text-xs text-muted-foreground">Errores</p>
                        </div>
                      </div>
                    </div>
                  )}

                  {/* Upload complete */}
                  {uploadProgress.status === 'complete' && (
                    <div className="space-y-4">
                      <div className="flex items-center gap-3">
                        <CheckCircle className="h-6 w-6 text-success" />
                        <div className="flex-1">
                          <p className="font-medium text-success">Carga completada</p>
                          <p className="text-sm text-muted-foreground">
                            Se procesaron {uploadProgress.validFiles.toLocaleString()} archivos
                          </p>
                        </div>
                      </div>
                      <div className="grid grid-cols-3 gap-4 text-center">
                        <div className="p-3 bg-success/10 rounded-lg">
                          <p className="text-2xl font-bold text-success">{uploadProgress.uploaded.toLocaleString()}</p>
                          <p className="text-xs text-muted-foreground">Cargados</p>
                        </div>
                        <div className="p-3 bg-warning/10 rounded-lg">
                          <p className="text-2xl font-bold text-warning">{uploadProgress.duplicates.toLocaleString()}</p>
                          <p className="text-xs text-muted-foreground">Duplicados</p>
                        </div>
                        <div className="p-3 bg-destructive/10 rounded-lg">
                          <p className="text-2xl font-bold text-destructive">{uploadProgress.errors.toLocaleString()}</p>
                          <p className="text-xs text-muted-foreground">Errores</p>
                        </div>
                      </div>
                      {uploadProgress.errorMessages.length > 0 && (
                        <div className="p-3 bg-destructive/10 rounded-lg">
                          <p className="text-sm font-medium text-destructive mb-2">Errores:</p>
                          <ul className="text-xs text-destructive space-y-1 max-h-24 overflow-y-auto">
                            {uploadProgress.errorMessages.map((err, i) => (
                              <li key={i}>{err}</li>
                            ))}
                          </ul>
                        </div>
                      )}
                      <div className="flex gap-2 justify-end">
                        <Button type="button" variant="outline" onClick={clearXmlFiles}>
                          Cargar mas archivos
                        </Button>
                        <Button type="button" onClick={() => { setShowBulkForm(false); clearXmlFiles(); }}>
                          Cerrar
                        </Button>
                      </div>
                    </div>
                  )}

                  {/* Ready to upload - show summary and upload button */}
                  {uploadProgress.status === 'idle' && parsedCfdis.length > 0 && (
                    <div className="space-y-4">
                      <div className="p-4 bg-muted/50 rounded-lg">
                        <div className="flex items-center justify-between">
                          <div>
                            <p className="font-medium">{parsedCfdis.length.toLocaleString()} CFDIs listos para cargar</p>
                            <p className="text-sm text-muted-foreground">
                              Se enviaran en {Math.ceil(parsedCfdis.length / UPLOAD_CHUNK_SIZE)} lotes de {UPLOAD_CHUNK_SIZE} registros
                            </p>
                          </div>
                          <Button type="button" variant="ghost" size="sm" onClick={clearXmlFiles}>
                            Limpiar
                          </Button>
                        </div>
                      </div>
                      <div className="flex gap-2 justify-end">
                        <Button type="button" variant="outline" onClick={() => { setShowBulkForm(false); clearXmlFiles(); }}>
                          Cancelar
                        </Button>
                        <Button type="submit">
                          <Upload className="h-4 w-4 mr-2" />
                          Iniciar carga
                        </Button>
                      </div>
                    </div>
                  )}

                  {/* Initial state - no files */}
                  {uploadProgress.status === 'idle' && parsedCfdis.length === 0 && uploadProgress.totalFiles === 0 && (
                    <div className="flex gap-2 justify-end">
                      <Button type="button" variant="outline" onClick={() => setShowBulkForm(false)}>
                        Cancelar
                      </Button>
                    </div>
                  )}
                </form>
              ) : (
                <form onSubmit={handleBulkSubmit} className="space-y-4">
                  <div className="space-y-2">
                    <Label>Datos JSON</Label>
                    <textarea
                      className="w-full h-48 p-3 border rounded-lg font-mono text-sm bg-background"
                      value={bulkData}
                      onChange={(e) => setBulkData(e.target.value)}
                      placeholder={`[
  {
    "uuid": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "type": "ingreso",
    "fechaEmision": "2025-01-15",
    "rfcEmisor": "XAXX010101000",
    "nombreEmisor": "Empresa SA de CV",
    "rfcReceptor": "XAXX010101001",
    "nombreReceptor": "Cliente SA de CV",
    "subtotal": 10000,
    "ivaTraslado": 1600,
    "total": 11600
  }
]`}
                      required
                    />
                  </div>
                  <div className="flex gap-2 justify-end">
                    <Button type="button" variant="outline" onClick={() => setShowBulkForm(false)}>
                      Cancelar
                    </Button>
                    <Button type="submit" disabled={jsonUploading}>
                      {jsonUploading ? 'Procesando...' : 'Cargar CFDIs'}
                    </Button>
                  </div>
                </form>
              )}
            </CardContent>
          </Card>
        )}

        {/* Table */}
        <Card>
          <CardHeader>
            <div className="flex items-center justify-between">
              <CardTitle className="flex items-center gap-2 text-base">
                <FileText className="h-4 w-4" />
                CFDIs ({data?.total || 0})
              </CardTitle>
              {hasActiveColumnFilters && (
                <div className="flex items-center gap-2 text-xs text-muted-foreground">
                  <span>Filtros activos:</span>
                  {hasDateFilter && (
                    <span className="px-2 py-0.5 bg-primary/10 text-primary rounded-full flex items-center gap-1">
                      Fecha
                      <button onClick={clearDateFilter} className="hover:text-destructive">
                        <X className="h-3 w-3" />
                      </button>
                    </span>
                  )}
                  {hasEmisorFilter && (
                    <span className="px-2 py-0.5 bg-primary/10 text-primary rounded-full flex items-center gap-1">
                      Emisor: {filters.emisor}
                      <button onClick={clearEmisorFilter} className="hover:text-destructive">
                        <X className="h-3 w-3" />
                      </button>
                    </span>
                  )}
                  {hasReceptorFilter && (
                    <span className="px-2 py-0.5 bg-primary/10 text-primary rounded-full flex items-center gap-1">
                      Receptor: {filters.receptor}
                      <button onClick={clearReceptorFilter} className="hover:text-destructive">
                        <X className="h-3 w-3" />
                      </button>
                    </span>
                  )}
                </div>
              )}
            </div>
          </CardHeader>
          <CardContent>
            {isLoading ? (
              <div className="space-y-3">
                {/* Skeleton loader */}
                {[...Array(8)].map((_, i) => (
                  <div key={i} className="flex items-center gap-4 animate-pulse">
                    <div className="h-4 bg-muted rounded w-20"></div>
                    <div className="h-5 bg-muted rounded w-16"></div>
                    <div className="h-4 bg-muted rounded w-12"></div>
                    <div className="h-4 bg-muted rounded flex-1 max-w-[180px]"></div>
                    <div className="h-4 bg-muted rounded flex-1 max-w-[180px]"></div>
                    <div className="h-4 bg-muted rounded w-24 ml-auto"></div>
                    <div className="h-5 bg-muted rounded w-16"></div>
                    <div className="h-8 bg-muted rounded w-8"></div>
                  </div>
                ))}
              </div>
            ) : data?.data.length === 0 ? (
              <div className="text-center py-8 text-muted-foreground">
                No se encontraron CFDIs
              </div>
            ) : (
              <div className="overflow-x-auto">
                <table className="w-full">
                  <thead>
                    <tr className="border-b text-left text-sm text-muted-foreground">
                      <th className="pb-3 font-medium">
                        <div className="flex items-center gap-1">
                          Fecha
                          <Popover open={openFilter === 'fecha'} onOpenChange={(open) => setOpenFilter(open ? 'fecha' : null)}>
                            <PopoverTrigger asChild>
                              <button className={`p-1 rounded hover:bg-muted ${hasDateFilter ? 'text-primary' : ''}`}>
                                <Filter className="h-3.5 w-3.5" />
                              </button>
                            </PopoverTrigger>
                            <PopoverContent className="w-64" align="start">
                              <div className="space-y-3">
                                <h4 className="font-medium text-sm">Filtrar por fecha</h4>
                                <div className="space-y-2">
                                  <div>
                                    <Label className="text-xs">Desde</Label>
                                    <Input
                                      type="date"
                                      className="h-8 text-sm"
                                      value={columnFilters.fechaInicio}
                                      onChange={(e) => setColumnFilters({ ...columnFilters, fechaInicio: e.target.value })}
                                    />
                                  </div>
                                  <div>
                                    <Label className="text-xs">Hasta</Label>
                                    <Input
                                      type="date"
                                      className="h-8 text-sm"
                                      value={columnFilters.fechaFin}
                                      onChange={(e) => setColumnFilters({ ...columnFilters, fechaFin: e.target.value })}
                                    />
                                  </div>
                                </div>
                                <div className="flex gap-2">
                                  <Button size="sm" className="flex-1" onClick={applyDateFilter}>
                                    Aplicar
                                  </Button>
                                  {hasDateFilter && (
                                    <Button size="sm" variant="outline" onClick={clearDateFilter}>
                                      Limpiar
                                    </Button>
                                  )}
                                </div>
                              </div>
                            </PopoverContent>
                          </Popover>
                        </div>
                      </th>
                      <th className="pb-3 font-medium">Tipo Comp.</th>
                      <th className="pb-3 font-medium">UUID</th>
                      <th className="pb-3 font-medium">
                        <div className="flex items-center gap-1">
                          Emisor
                          <Popover open={openFilter === 'emisor'} onOpenChange={(open) => setOpenFilter(open ? 'emisor' : null)}>
                            <PopoverTrigger asChild>
                              <button className={`p-1 rounded hover:bg-muted ${hasEmisorFilter ? 'text-primary' : ''}`}>
                                <Filter className="h-3.5 w-3.5" />
                              </button>
                            </PopoverTrigger>
                            <PopoverContent className="w-72" align="start">
                              <div className="space-y-3">
                                <h4 className="font-medium text-sm">Filtrar por emisor</h4>
                                <div className="relative">
                                  <Label className="text-xs">RFC o Nombre</Label>
                                  <Input
                                    placeholder="Buscar emisor..."
                                    className="h-8 text-sm"
                                    value={columnFilters.emisor}
                                    onChange={(e) => setColumnFilters(prev => ({ ...prev, emisor: e.target.value }))}
                                    onKeyDown={(e) => e.key === 'Enter' && applyEmisorFilter()}
                                  />
                                  {emisorSuggestions.length > 0 && (
                                    <div className="absolute top-full left-0 right-0 mt-1 bg-white dark:bg-gray-900 border rounded-md shadow-lg max-h-48 overflow-y-auto z-50">
                                      {emisorSuggestions.map((emisor, idx) => (
                                        <button
                                          key={idx}
                                          type="button"
                                          className="w-full px-3 py-2 text-left text-sm hover:bg-muted transition-colors border-b last:border-b-0"
                                          onClick={() => selectEmisor(emisor)}
                                        >
                                          <p className="font-medium truncate">{emisor.nombre}</p>
                                          <p className="text-xs text-muted-foreground">{emisor.rfc}</p>
                                        </button>
                                      ))}
                                    </div>
                                  )}
                                  {loadingEmisor && columnFilters.emisor.length >= 2 && emisorSuggestions.length === 0 && (
                                    <div className="absolute top-full left-0 right-0 mt-1 bg-white dark:bg-gray-900 border rounded-md shadow-lg p-2 text-center text-sm text-muted-foreground">
                                      Buscando...
                                    </div>
                                  )}
                                </div>
                                <div className="flex gap-2">
                                  <Button size="sm" className="flex-1" onClick={applyEmisorFilter}>
                                    Aplicar
                                  </Button>
                                  {hasEmisorFilter && (
                                    <Button size="sm" variant="outline" onClick={clearEmisorFilter}>
                                      Limpiar
                                    </Button>
                                  )}
                                </div>
                              </div>
                            </PopoverContent>
                          </Popover>
                        </div>
                      </th>
                      <th className="pb-3 font-medium">
                        <div className="flex items-center gap-1">
                          Receptor
                          <Popover open={openFilter === 'receptor'} onOpenChange={(open) => setOpenFilter(open ? 'receptor' : null)}>
                            <PopoverTrigger asChild>
                              <button className={`p-1 rounded hover:bg-muted ${hasReceptorFilter ? 'text-primary' : ''}`}>
                                <Filter className="h-3.5 w-3.5" />
                              </button>
                            </PopoverTrigger>
                            <PopoverContent className="w-72" align="start">
                              <div className="space-y-3">
                                <h4 className="font-medium text-sm">Filtrar por receptor</h4>
                                <div className="relative">
                                  <Label className="text-xs">RFC o Nombre</Label>
                                  <Input
                                    placeholder="Buscar receptor..."
                                    className="h-8 text-sm"
                                    value={columnFilters.receptor}
                                    onChange={(e) => setColumnFilters(prev => ({ ...prev, receptor: e.target.value }))}
                                    onKeyDown={(e) => e.key === 'Enter' && applyReceptorFilter()}
                                  />
                                  {receptorSuggestions.length > 0 && (
                                    <div className="absolute top-full left-0 right-0 mt-1 bg-white dark:bg-gray-900 border rounded-md shadow-lg max-h-48 overflow-y-auto z-50">
                                      {receptorSuggestions.map((receptor, idx) => (
                                        <button
                                          key={idx}
                                          type="button"
                                          className="w-full px-3 py-2 text-left text-sm hover:bg-muted transition-colors border-b last:border-b-0"
                                          onClick={() => selectReceptor(receptor)}
                                        >
                                          <p className="font-medium truncate">{receptor.nombre}</p>
                                          <p className="text-xs text-muted-foreground">{receptor.rfc}</p>
                                        </button>
                                      ))}
                                    </div>
                                  )}
                                  {loadingReceptor && columnFilters.receptor.length >= 2 && receptorSuggestions.length === 0 && (
                                    <div className="absolute top-full left-0 right-0 mt-1 bg-white dark:bg-gray-900 border rounded-md shadow-lg p-2 text-center text-sm text-muted-foreground">
                                      Buscando...
                                    </div>
                                  )}
                                </div>
                                <div className="flex gap-2">
                                  <Button size="sm" className="flex-1" onClick={applyReceptorFilter}>
                                    Aplicar
                                  </Button>
                                  {hasReceptorFilter && (
                                    <Button size="sm" variant="outline" onClick={clearReceptorFilter}>
                                      Limpiar
                                    </Button>
                                  )}
                                </div>
                              </div>
                            </PopoverContent>
                          </Popover>
                        </div>
                      </th>
                      <th className="pb-3 font-medium text-right">Total</th>
                      <th className="pb-3 font-medium">Estado</th>
                      <th className="pb-3 font-medium"></th>
                      <th className="pb-3 font-medium"></th>
                      {canEdit && <th className="pb-3 font-medium"></th>}
                    </tr>
                  </thead>
                  <tbody className="text-sm">
                    {data?.data.map((cfdi) => (
                      <tr key={cfdi.id} className="border-b hover:bg-muted/50">
                        <td className="py-3">{formatDate(cfdi.fechaEmision)}</td>
                        <td className="py-3">
                          <span className="text-xs" title={formatTipoComprobante(cfdi.tipoComprobante)}>
                            {cfdi.tipoComprobante ? cfdi.tipoComprobante.toUpperCase() : '-'}
                          </span>
                        </td>
                        <td className="py-3">
                          <span className="font-mono text-xs" title={cfdi.uuid}>{cfdi.uuid?.substring(0, 8) || '-'}</span>
                        </td>
                        <td className="py-3">
                          <div>
                            <p className="font-medium truncate max-w-[180px]" title={cfdi.nombreEmisor}>
                              {cfdi.nombreEmisor}
                            </p>
                            <p className="text-xs text-muted-foreground">
                              {cfdi.rfcEmisor}
                            </p>
                          </div>
                        </td>
                        <td className="py-3">
                          <div>
                            <p className="font-medium truncate max-w-[180px]" title={cfdi.nombreReceptor}>
                              {cfdi.nombreReceptor}
                            </p>
                            <p className="text-xs text-muted-foreground">
                              {cfdi.rfcReceptor}
                            </p>
                          </div>
                        </td>
                        <td className="py-3 text-right font-medium">
                          {formatCurrency(cfdi.total)}
                        </td>
                        <td className="py-3">
                          <span
                            className={`px-2 py-1 rounded-full text-xs font-medium ${
                              cfdi.status === 'Vigente' || cfdi.status === '1'
                                ? 'bg-success/10 text-success'
                                : 'bg-muted text-muted-foreground'
                            }`}
                          >
                            {cfdi.status === 'Vigente' || cfdi.status === '1' ? 'Vigente' : 'Cancelado'}
                          </span>
                        </td>
                        <td className="py-3">
                          <Button
                            variant="ghost"
                            size="icon"
                            onClick={() => handleViewCfdi(cfdi.id)}
                            disabled={loadingCfdi === cfdi.id}
                            title="Ver factura"
                          >
                            {loadingCfdi === cfdi.id ? (
                              <Loader2 className="h-4 w-4 animate-spin" />
                            ) : (
                              <Eye className="h-4 w-4" />
                            )}
                          </Button>
                        </td>
                        <td className="py-3">
                          <Button
                            variant="ghost"
                            size="icon"
                            onClick={() => exportSingleCfdiToExcel(cfdi)}
                            title="Descargar Excel"
                          >
                            <Download className="h-4 w-4" />
                          </Button>
                        </td>
                        {canEdit && (
                          <td className="py-3">
                            <div className="flex items-center gap-0">
                              {(cfdi as any).source === 'facturapi' && (cfdi.status === 'Vigente' || cfdi.status === '1') && (
                                <Button
                                  variant="ghost"
                                  size="icon"
                                  onClick={() => openCancelDialog(cfdi)}
                                  className="text-destructive hover:text-destructive"
                                  title="Cancelar factura en Facturapi/SAT"
                                >
                                  <XCircle className="h-4 w-4" />
                                </Button>
                              )}
                              <Button
                              variant="ghost"
                              size="icon"
                              onClick={() => handleDelete(cfdi.id)}
                              className="text-destructive hover:text-destructive"
                              title="Eliminar registro (solo local)"
                            >
                              <Trash2 className="h-4 w-4" />
                            </Button>
                            </div>
                          </td>
                        )}
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            )}

            {/* Pagination */}
            {data && data.totalPages > 1 && (
              <div className="flex items-center justify-between mt-4 pt-4 border-t">
                <p className="text-sm text-muted-foreground">
                  Pagina {data.page} de {data.totalPages}
                </p>
                <div className="flex gap-2">
                  <Button
                    variant="outline"
                    size="sm"
                    disabled={data.page <= 1}
                    onClick={() =>
                      setFilters({ ...filters, page: (filters.page || 1) - 1 })
                    }
                  >
                    <ChevronLeft className="h-4 w-4" />
                  </Button>
                  <Button
                    variant="outline"
                    size="sm"
                    disabled={data.page >= data.totalPages}
                    onClick={() =>
                      setFilters({ ...filters, page: (filters.page || 1) + 1 })
                    }
                  >
                    <ChevronRight className="h-4 w-4" />
                  </Button>
                </div>
              </div>
            )}
          </CardContent>
        </Card>
      </main>

      <CfdiViewerModal
        cfdi={viewingCfdi}
        open={viewingCfdi !== null}
        onClose={() => setViewingCfdi(null)}
      />

      {/* Cancelación de factura Facturapi */}
      <Dialog open={!!cancelTarget} onOpenChange={(open) => !open && setCancelTarget(null)}>
        <DialogContent className="max-w-lg">
          <DialogHeader>
            <DialogTitle>Cancelar factura en el SAT</DialogTitle>
            <DialogDescription>
              Esta acción solicita la cancelación del CFDI ante el SAT vía Facturapi. Dependiendo del motivo y la antigüedad de la factura, podría requerir aceptación del receptor (proceso que toma hasta 72h).
            </DialogDescription>
          </DialogHeader>

          {cancelTarget && (
            <div className="space-y-4 py-2">
              <div className="rounded border p-3 bg-muted/30 text-sm">
                <div className="font-mono text-xs break-all">{cancelTarget.uuid}</div>
                <div className="text-muted-foreground text-xs mt-1">
                  {cancelTarget.rfcReceptor} · {cancelTarget.nombreReceptor}
                </div>
              </div>

              <div className="space-y-2">
                <Label>Motivo de cancelación</Label>
                <div className="grid gap-2">
                  <label className={`rounded border-2 p-3 cursor-pointer transition-all ${cancelMotive === '02' ? 'border-primary bg-primary/5' : 'border-border hover:border-primary/40'}`}>
                    <input type="radio" name="motive" value="02" checked={cancelMotive === '02'} onChange={() => setCancelMotive('02')} className="sr-only" />
                    <div className="font-medium text-sm">02 — Comprobante emitido con errores sin relación</div>
                    <p className="text-xs text-muted-foreground mt-0.5">El más común. La factura tiene errores y no la vas a reemplazar.</p>
                  </label>
                  <label className={`rounded border-2 p-3 cursor-pointer transition-all ${cancelMotive === '01' ? 'border-primary bg-primary/5' : 'border-border hover:border-primary/40'}`}>
                    <input type="radio" name="motive" value="01" checked={cancelMotive === '01'} onChange={() => setCancelMotive('01')} className="sr-only" />
                    <div className="font-medium text-sm">01 — Comprobante emitido con errores con relación</div>
                    <p className="text-xs text-muted-foreground mt-0.5">La factura tiene errores y la reemplazas por otra que ya emitiste. Requiere el UUID de la sustituta.</p>
                  </label>
                  <label className={`rounded border-2 p-3 cursor-pointer transition-all ${cancelMotive === '03' ? 'border-primary bg-primary/5' : 'border-border hover:border-primary/40'}`}>
                    <input type="radio" name="motive" value="03" checked={cancelMotive === '03'} onChange={() => setCancelMotive('03')} className="sr-only" />
                    <div className="font-medium text-sm">03 — No se llevó a cabo la operación</div>
                    <p className="text-xs text-muted-foreground mt-0.5">El cliente no compró/no se prestó el servicio.</p>
                  </label>
                  <label className={`rounded border-2 p-3 cursor-pointer transition-all ${cancelMotive === '04' ? 'border-primary bg-primary/5' : 'border-border hover:border-primary/40'}`}>
                    <input type="radio" name="motive" value="04" checked={cancelMotive === '04'} onChange={() => setCancelMotive('04')} className="sr-only" />
                    <div className="font-medium text-sm">04 — Operación nominativa relacionada en factura global</div>
                    <p className="text-xs text-muted-foreground mt-0.5">La operación se incluyó después en una factura global (público en general).</p>
                  </label>
                </div>
              </div>

              {cancelMotive === '01' && (
                <div className="space-y-1">
                  <Label htmlFor="substitution">UUID de la factura que sustituye a esta</Label>
                  <Input
                    id="substitution"
                    value={cancelSubstitution}
                    onChange={(e) => setCancelSubstitution(e.target.value)}
                    placeholder="00000000-0000-0000-0000-000000000000"
                    className="font-mono text-xs"
                  />
                </div>
              )}

              <div className="rounded border border-amber-300 bg-amber-50 text-amber-900 p-3 text-xs">
                <strong>Importante:</strong> una vez solicitada la cancelación, la factura puede quedar en estatus "pendiente" si el SAT requiere aceptación del receptor. El cambio en nuestra BD se refleja al confirmarse en el SAT. Revisa el estatus en unos minutos.
              </div>
            </div>
          )}

          <DialogFooter>
            <Button variant="outline" onClick={() => setCancelTarget(null)} disabled={cancelling}>
              Cerrar
            </Button>
            <Button onClick={handleCancelFactura} disabled={cancelling} className="bg-destructive text-destructive-foreground hover:bg-destructive/90">
              {cancelling && <Loader2 className="h-4 w-4 mr-2 animate-spin" />}
              Solicitar cancelación
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </>
  );
}
