import { useState, useCallback } from 'react';
import { toast } from 'sonner';
import cnabService from '../services/cnabService';
import { useCnabStore } from './useCnabStore';

/**
 * @typedef {Object} MappingSchema
 * @property {string} key
 * @property {string} label
 * @property {boolean} required
 */

/**
 * Normaliza o tipo de chave PIX, convertendo nomes para números
 * Aceita tanto números quanto nomes descritivos
 * @param {string|number} value - Tipo de chave PIX (número ou nome)
 * @returns {string} - Tipo normalizado como string numérica ('1', '2', '3', '4', '5')
 * 
 * Mapeamento:
 * - 1 = Telefone
 * - 2 = E-mail
 * - 3 = CPF/CNPJ (aceita tanto CPF quanto CNPJ)
 * - 4 = Chave Aleatória
 * - 5 = Dados bancários
 */
const normalizeTipoChavePix = (value) => {
    if (!value && value !== 0) return '4'; // Default: Chave Aleatória
    
    const str = String(value).trim();
    
    // Se já é um número válido (1-5), retorna como string
    if (/^[1-5]$/.test(str)) {
        return str;
    }
    
    // Normaliza string removendo acentos e caracteres especiais
    const normalized = str.toLowerCase()
        .normalize('NFD')
        .replace(/[\u0300-\u036f]/g, '') // Remove diacríticos
        .replace(/[^a-z0-9]/g, ''); // Remove caracteres especiais
    
    // Mapeia nomes para números (case-insensitive)
    // Ordem importa: termos mais específicos primeiro
    // IMPORTANTE: Tipo 3 aceita tanto CPF quanto CNPJ
    const nameMap = [
        { keys: ['telefone', 'phone'], value: '1' },
        { keys: ['email', 'e-mail', 'mail'], value: '2' },
        { keys: ['cpfcnpj', 'cpf', 'cnpj', 'cpf/cnpj'], value: '3' }, // Tipo 3: CPF ou CNPJ
        { keys: ['chavealeatoria', 'aleatoria', 'aleatória', 'random', 'evp'], value: '4' },
        { keys: ['dadosbancarios', 'bancarios', 'dados', 'conta'], value: '5' }
    ];
    
    // Procura match exato ou parcial
    for (const { keys, value: num } of nameMap) {
        for (const key of keys) {
            if (normalized === key || normalized.includes(key) || key.includes(normalized)) {
                return num;
            }
        }
    }
    
    // Se não encontrou match, retorna default
    console.warn(`⚠️ [CNAB] Tipo de chave PIX não reconhecido: "${value}". Usando default (4 - Chave Aleatória)`);
    return '4';
};

/**
 * Remove caracteres especiais de documentos (CPF/CNPJ)
 * CPF/CNPJ sempre precisa ser sanitizado (sem caracteres especiais)
 * @param {string} value - Valor a ser sanitizado
 * @returns {string} - Valor sanitizado (apenas números)
 */
const sanitizeDocumentValue = (value) => {
    if (!value || typeof value !== 'string') return value;
    // Remove todos os caracteres especiais, mantendo apenas números
    // Remove: pontos, traços, barras, espaços, parênteses, etc.
    return value.replace(/[^0-9]/g, '');
};

/**
 * Remove caracteres especiais de chave PIX
 * Apenas para tipos 1 (Telefone) ou 3 (CPF/CNPJ)
 * @param {string} value - Valor da chave PIX
 * @param {string|number} tipoChavePix - Tipo da chave PIX ('1', '3', '2', '4', '5')
 * @returns {string} - Valor sanitizado ou original
 */
const sanitizeChavePix = (value, tipoChavePix) => {
    if (!value || typeof value !== 'string') return value;
    
    // Converte para string para comparação
    const tipo = String(tipoChavePix);
    
    // Apenas tipos 1 (Telefone) ou 3 (CPF/CNPJ) precisam de sanitização
    // Tipo 1 = Telefone, Tipo 3 = CPF/CNPJ
    if (tipo === '1' || tipo === '3') {
        // Remove todos os caracteres especiais, mantendo apenas números e letras
        return value.replace(/[^a-zA-Z0-9]/g, '');
    }
    
    // Para outros tipos (2 - E-mail, 4 - Chave Aleatória, 5 - Dados bancários)
    // Mantém como está (pode ter caracteres especiais como @, -, etc.)
    return value;
};

/**
 * Sanitiza os dados de uma linha, removendo caracteres especiais conforme regras
 * @param {Object} row - Linha de dados
 * @param {string} paymentType - Tipo de pagamento (PIX ou TED)
 * @returns {Object} - Linha sanitizada
 */
const sanitizeRowData = (row, paymentType) => {
    const sanitized = { ...row };
    
    // CPF/CNPJ sempre precisa ser sanitizado (remove caracteres especiais)
    if (sanitized.CPF_CNPJ_FAVORECIDO) {
        sanitized.CPF_CNPJ_FAVORECIDO = sanitizeDocumentValue(sanitized.CPF_CNPJ_FAVORECIDO);
    }
    
    // Para PIX: normaliza tipo de chave PIX (converte nomes para números) e sanitiza Chave PIX
    if (paymentType === 'PIX') {
        // Normaliza TIPO_CHAVE_PIX (converte nomes para números)
        if (sanitized.TIPO_CHAVE_PIX !== undefined && sanitized.TIPO_CHAVE_PIX !== null) {
            const originalTipo = sanitized.TIPO_CHAVE_PIX;
            sanitized.TIPO_CHAVE_PIX = normalizeTipoChavePix(sanitized.TIPO_CHAVE_PIX);
            if (originalTipo !== sanitized.TIPO_CHAVE_PIX) {
                console.log(`🔄 [CNAB] Tipo de chave PIX normalizado: "${originalTipo}" → "${sanitized.TIPO_CHAVE_PIX}"`);
            }
        }
        
        // Sanitiza Chave PIX apenas se tipo for 1 (Telefone) ou 3 (CPF/CNPJ)
        if (sanitized.CHAVE_PIX) {
            const tipoChavePix = sanitized.TIPO_CHAVE_PIX;
            sanitized.CHAVE_PIX = sanitizeChavePix(sanitized.CHAVE_PIX, tipoChavePix);
        }
    }
    
    return sanitized;
};

const MODEL_SCHEMAS = {
    PIX: [
        { key: 'NOME_FAVORECIDO', label: 'Nome Favorecido', required: true },
        { key: 'VALOR_PAGAMENTO', label: 'Valor Pagamento', required: true },
        { key: 'TIPO_CHAVE_PIX', label: 'Tipo Chave PIX', required: true },
        { key: 'CHAVE_PIX', label: 'Chave PIX', required: true },
        { key: 'CPF_CNPJ_FAVORECIDO', label: 'CPF/CNPJ Favorecido', required: true }
    ],
    TED: [
        { key: 'NOME_FAVORECIDO', label: 'Nome Favorecido', required: true },
        { key: 'VALOR_PAGAMENTO', label: 'Valor Pagamento', required: true },
        { key: 'CPF_CNPJ_FAVORECIDO', label: 'CPF/CNPJ Favorecido', required: true },
        { key: 'BANCO_FAVORECIDO', label: 'Banco Favorecido', required: true },
        { key: 'AGENCIA_FAVORECIDA', label: 'Agência Favorecida', required: true },
        { key: 'DIGITO_AGENCIA_FAVORECIDA', label: 'Dígito Agência', required: false },
        { key: 'CONTA_FAVORECIDA', label: 'Conta Favorecida', required: true },
        { key: 'DIGITO_CONTA_FAVORECIDA', label: 'Dígito Conta', required: true },
        { key: 'DATA_PAGAMENTO', label: 'Data Pagamento', required: false },
        { key: 'TIPO_CONTA_FAVORECIDA', label: 'Tipo Conta Favorecida', required: false },
        { key: 'FINALIDADE_TED', label: 'Finalidade TED', required: false },
        { key: 'INFORMACAO', label: 'Informação', required: false }
    ],
    BRADESCO_COBRANCA: [
        { key: 'VALOR', label: 'Valor Título', required: true },
        { key: 'VENCIMENTO', label: 'Data Vencimento', required: true },
        { key: 'NOSSO_NUMERO', label: 'Nosso Número', required: true },
        { key: 'NUMERO_DOCUMENTO', label: 'Número Documento', required: true },
        { key: 'NOME_PAGADOR', label: 'Nome Pagador', required: true },
        { key: 'CPF_CNPJ_PAGADOR', label: 'CPF/CNPJ Pagador', required: true },
        { key: 'ENDERECO', label: 'Endereço', required: true },
        { key: 'BAIRRO', label: 'Bairro', required: true },
        { key: 'CEP', label: 'CEP', required: true },
        { key: 'CIDADE', label: 'Cidade', required: true },
        { key: 'UF', label: 'UF', required: true },
        { key: 'DATA_EMISSAO', label: 'Data Emissão', required: true },
        { key: 'USO_EMPRESA', label: 'Uso Empresa', required: false },
        { key: 'ESPECIE_TITULO', label: 'Espécie Título', required: false }
    ]
};

/**
 * Hook customizado para lógica de geração de remessa CNAB
 * Segue o fluxo completo do código legado:
 * 1. Upload → 2. Mapping → 3. Validate Columns → 4. Validate JSON → 5. Generate Excel → 6. Generate REM
 */
export const useGerarRemessa = () => {
    const { selectedBank, paymentMode, bradescoRemessaVariant } = useCnabStore(); // Banco, modo de pagamento e variante TED Bradesco (ted | folha_pagamento | cobranca)
    const [step, setStep] = useState('upload'); // upload | mapping | validate | success
    
    // Calcula o tipo de pagamento efetivo para seleção do schema
    const effectivePaymentType = paymentMode === 'TED' && selectedBank === 'BRADESCO' && bradescoRemessaVariant === 'cobranca'
        ? 'BRADESCO_COBRANCA'
        : paymentMode;

    const paymentType = paymentMode; 
    const [loading, setLoading] = useState(false);
    
    // Dados do arquivo
    const [rawHeaders, setRawHeaders] = useState([]);
    const [rawData, setRawData] = useState([]);
    const [tableHtml, setTableHtml] = useState(null); // HTML da tabela retornada pelo backend
    const [columnMapping, setColumnMapping] = useState({});
    const [validatedTableHtml, setValidatedTableHtml] = useState(null); // HTML da tabela validada
    const [tableData, setTableData] = useState([]); // Dados em formato JSON para validação final
    
    // Arquivo gerado
    const [remessaFile, setRemessaFile] = useState(null);
    const [remessaFilename, setRemessaFilename] = useState(null);
    
    // Erros de validação do backend
    const [validationErrors, setValidationErrors] = useState(null);

    /**
     * Processa o upload do arquivo
     * Passo 1: Upload e parse do Excel
     */
    const handleUpload = useCallback(async (file) => {
        if (!file) return;
        
        console.group('📤 [CNAB] Iniciando upload do arquivo');
        console.log('📄 Arquivo:', file.name, 'Tipo:', file.type, 'Tamanho:', file.size);
        console.log('💳 Tipo de pagamento:', paymentType);
        
        setLoading(true);
        try {
            const result = await cnabService.uploadAndParseExcel(file, paymentType);
            console.log('✅ Resposta do backend:', result);
            
            // O backend retorna HTML da tabela
            const html = result.html || result.Base_Dados_API?.Relatorio;
            
            if (!html) {
                console.error('❌ HTML vazio ou inválido');
                throw new Error('Arquivo vazio ou formato inválido');
            }

            console.log('📋 HTML recebido (primeiros 500 chars):', html.substring(0, 500));
            
            // Extrai headers e dados do HTML (ou usa dados brutos se disponíveis)
            setTableHtml(html);
            
            // Tenta extrair headers e dados do HTML usando DOM parser
            const parser = new DOMParser();
            const doc = parser.parseFromString(html, 'text/html');
            const table = doc.querySelector('table');
            
            console.log('🔍 Tabela encontrada:', !!table);
            
            if (table) {
                // Tenta encontrar headers em thead ou na primeira linha
                let headers = Array.from(table.querySelectorAll('thead th, thead td')).map(th => th.textContent.trim());
                console.log('📊 Headers do thead:', headers);
                
                // Se não encontrar no thead, tenta na primeira linha do tbody
                if (headers.length === 0) {
                    const firstRow = table.querySelector('tbody tr, tr');
                    if (firstRow) {
                        headers = Array.from(firstRow.querySelectorAll('th, td')).map(cell => cell.textContent.trim());
                        console.log('📊 Headers da primeira linha:', headers);
                    }
                }
                
                // Extrai dados das linhas (pula a primeira se for header)
                const allRows = Array.from(table.querySelectorAll('tbody tr, tr'));
                console.log('📝 Total de linhas encontradas:', allRows.length);
                
                const dataRows = headers.length > 0 && allRows.length > 0 && 
                    allRows[0].querySelectorAll('th, td').length === headers.length
                    ? allRows.slice(1) 
                    : allRows;
                
                console.log('📝 Linhas de dados (após filtrar header):', dataRows.length);
                
                const rows = dataRows.map((tr, rowIdx) => {
                    const cells = Array.from(tr.querySelectorAll('td, th'));
                    const rowData = { id: rowIdx + 1 }; // Adiciona ID único
                    cells.forEach((cell, idx) => {
                        if (headers[idx]) {
                            rowData[headers[idx]] = cell.textContent.trim();
                        }
                    });
                    if (rowIdx < 3) {
                        console.log(`📝 Linha ${rowIdx + 1}:`, rowData);
                    }
                    return rowData;
                }).filter(row => Object.keys(row).length > 1); // Remove linhas vazias (mais de 1 porque tem id)
                
                console.log('✅ Headers extraídos:', headers);
                console.log('✅ Total de linhas válidas:', rows.length);
                console.log('📋 Primeiras 3 linhas:', rows.slice(0, 3));
                
                setRawHeaders(headers);
                setRawData(rows);
            } else {
                console.warn('⚠️ Tabela não encontrada no HTML');
                setRawHeaders([]);
                setRawData([]);
            }
            
            // Sugestão automática de mapeamento baseada em nomes similares
            const newMapping = {};
            const usedHeaders = new Set(); // Evita mapear o mesmo header para múltiplos campos
            const clean = (s) => String(s || '').toLowerCase().replace(/[^a-z0-9]/g, '');
            
            console.group('🔗 Mapeamento automático de colunas');
            console.log('📊 Headers disponíveis:', rawHeaders);
            
            MODEL_SCHEMAS[effectivePaymentType].forEach(field => {
                // Tenta múltiplas estratégias de matching
                const fieldKey = clean(field.key);
                const fieldKeyParts = field.key.split('_').map(p => clean(p)).filter(p => p.length > 2);
                const fieldLabel = clean(field.label);
                const fieldLabelParts = field.label.split(' ').map(p => clean(p)).filter(p => p.length > 2);
                
                console.log(`🔍 Procurando match para: ${field.key} (${field.label})`);
                console.log('   - fieldKey:', fieldKey);
                console.log('   - fieldKeyParts:', fieldKeyParts);
                console.log('   - fieldLabel:', fieldLabel);
                console.log('   - fieldLabelParts:', fieldLabelParts);
                
                // Procura o melhor match, evitando headers já usados
                const match = rawHeaders.find(h => {
                    // Pula se já foi usado
                    if (usedHeaders.has(h)) return false;
                    
                    const cleanH = clean(h);
                    
                    // Match exato (maior prioridade)
                    if (cleanH === fieldKey || cleanH === fieldLabel) {
                        console.log(`   ✅ Match EXATO encontrado: "${h}" → ${field.key}`);
                        return true;
                    }
                    
                    // Match por palavra-chave principal (segunda prioridade)
                    const mainKeyword = fieldKeyParts[0] || fieldLabelParts[0];
                    if (mainKeyword && mainKeyword.length > 3 && cleanH.includes(mainKeyword)) {
                        console.log(`   ✅ Match por palavra-chave: "${h}" (contém "${mainKeyword}") → ${field.key}`);
                        return true;
                    }
                    
                    // Match por partes (terceira prioridade)
                    const matchesKeyPart = fieldKeyParts.some(part => part.length > 3 && cleanH.includes(part));
                    const matchesLabelPart = fieldLabelParts.some(part => part.length > 3 && cleanH.includes(part));
                    
                    if (matchesKeyPart || matchesLabelPart) {
                        console.log(`   ✅ Match por partes: "${h}" → ${field.key}`);
                        return true;
                    }
                    
                    // Match inverso (menor prioridade)
                    if (fieldKey.length > 4 && cleanH.length > 4) {
                        const matchesReverse = fieldKey.includes(cleanH) || cleanH.includes(fieldKey);
                        if (matchesReverse) {
                            console.log(`   ✅ Match reverso: "${h}" → ${field.key}`);
                            return true;
                        }
                    }
                    
                    return false;
                });
                
                if (match) {
                    console.log(`   ✅ Match FINAL: "${match}" → ${field.key}`);
                    newMapping[field.key] = match;
                    usedHeaders.add(match); // Marca como usado
                } else {
                    console.log(`   ❌ Nenhum match encontrado para ${field.key}`);
                }
            });
            console.groupEnd();
            
            console.log('📋 Mapeamento final:', newMapping);
            console.log('📊 Headers disponíveis:', rawHeaders);
            
            setColumnMapping(newMapping);
            setStep('mapping');
            toast.success('Arquivo processado. Verifique o mapeamento das colunas.');
            console.groupEnd();
        } catch (error) {
            console.error('❌ Erro ao processar arquivo:', error);
            console.error('Stack:', error.stack);
            toast.error(error.message || 'Erro ao processar arquivo. Verifique o formato e tente novamente.');
            console.groupEnd();
        } finally {
            setLoading(false);
        }
    }, [paymentType]);

    /**
     * Confirma o mapeamento e valida as colunas
     * Passo 2: Mapeamento → Passo 3: Validação de Colunas
     */
    const confirmMapping = useCallback(async () => {
        console.group('🔗 [CNAB] Confirmando mapeamento e validando colunas');
        console.log('📋 Mapeamento atual:', columnMapping);
        console.log('📊 Total de linhas brutas:', rawData.length);
        console.log('💳 Tipo de pagamento:', paymentType);
        
        setLoading(true);
        try {
            // Converte os dados brutos para o formato esperado pelo backend
            const mappedData = rawData.map((row, idx) => {
                const newRow = { id: row.id || idx + 1 };
                MODEL_SCHEMAS[effectivePaymentType].forEach(field => {
                    const sourceCol = columnMapping[field.key];
                    newRow[field.key] = sourceCol ? (row[sourceCol] || '') : '';
                });
                if (idx < 3) {
                    console.log(`📝 Linha mapeada ${idx + 1}:`, newRow);
                }
                return newRow;
            });

            // Sanitiza os dados: remove caracteres especiais de CPF/CNPJ e Chaves PIX
            console.log('🧹 Sanitizando dados: removendo caracteres especiais de documentos e chaves PIX...');
            const sanitizedData = mappedData.map((row, idx) => {
                const sanitized = sanitizeRowData(row, paymentType);
                if (idx < 3) {
                    console.log(`🧹 Linha sanitizada ${idx + 1}:`, sanitized);
                }
                return sanitized;
            });

            console.log('✅ Total de linhas mapeadas e sanitizadas:', sanitizedData.length);
            console.log('📋 Primeiras 3 linhas sanitizadas:', sanitizedData.slice(0, 3));
            console.log('📤 Enviando para validação de colunas...');

            // Chama a validação de colunas com dados sanitizados
            const validationResponse = await cnabService.validateColumns(columnMapping, sanitizedData, paymentType);
            
            // Verifica se o backend retornou dados tratados
            let validatedHtml = null;
            let treatedData = null;
            
            if (validationResponse && typeof validationResponse === 'object' && validationResponse.treatedData) {
                // Backend retornou dados tratados em JSON
                console.log('✅ [CNAB] Backend retornou dados tratados! Usando dados do backend.');
                treatedData = validationResponse.treatedData;
                validatedHtml = validationResponse.html;
                
                // Atualiza tableData com os dados tratados do backend (já normalizados)
                console.log('🔄 [CNAB] Atualizando tableData com dados tratados do backend');
                console.log('   - Total de linhas tratadas:', treatedData.length);
                console.log('   - Primeira linha tratada:', treatedData[0]);
                setTableData(treatedData);
            } else {
                // Backend retornou apenas HTML (comportamento antigo)
                validatedHtml = validationResponse;
                console.log('✅ HTML validado recebido (primeiros 500 chars):', validatedHtml?.substring(0, 500));
            }
            
            // Extrai informações de validação do HTML (cores, mensagens de erro)
            // Só processa HTML se houver HTML disponível
            let extractedErrors = null;
            if (validatedHtml && typeof validatedHtml === 'string') {
                try {
                    const parser = new DOMParser();
                    const doc = parser.parseFromString(validatedHtml, 'text/html');
                    const table = doc.querySelector('table#editable-table, table');
                    
                    if (table) {
                        // Verifica se há células com erro (vermelhas)
                        const errorCells = table.querySelectorAll('td[style*="background-color"][style*="ffb3b3"], td[style*="background-color"][style*="rose"], td[style*="background-color"][style*="red"]');
                        console.log(`🔍 Células com erro encontradas no HTML: ${errorCells.length}`);
                        
                        if (errorCells.length > 0) {
                            // Constrói objeto de erros baseado no HTML
                            const totalLinhas = treatedData ? treatedData.length : mappedData.length;
                            const errorsFromHtml = { erros: [], total_linhas: totalLinhas };
                            const rows = Array.from(table.querySelectorAll('tbody tr'));
                            
                            rows.forEach((tr, rowIdx) => {
                                const rowErrors = {};
                                const cells = Array.from(tr.querySelectorAll('td[data-col]'));
                                
                                cells.forEach(cell => {
                                    const field = cell.getAttribute('data-col');
                                    const bgColor = cell.style.backgroundColor || '';
                                    const title = cell.title || cell.getAttribute('title') || '';
                                    
                                    // Se tem cor vermelha, marca como erro
                                    if (bgColor && (bgColor.includes('ffb3b3') || bgColor.includes('rose') || bgColor.includes('red'))) {
                                        rowErrors[field] = title || 'Campo inválido';
                                    }
                                });
                                
                                if (Object.keys(rowErrors).length > 0) {
                                    errorsFromHtml.erros.push([rowIdx, rowErrors]);
                                }
                            });
                            
                            if (errorsFromHtml.erros.length > 0) {
                                console.log('📋 Erros extraídos do HTML:', errorsFromHtml);
                                extractedErrors = errorsFromHtml;
                                setValidationErrors(errorsFromHtml);
                            }
                        }
                    }
                } catch (e) {
                    console.warn('⚠️ Erro ao extrair validação do HTML:', e);
                }
            }
            
            setValidatedTableHtml(validatedHtml);
            // Usa dados tratados do backend se disponíveis, senão usa dados sanitizados localmente
            if (treatedData && treatedData.length > 0) {
                console.log('✅ [CNAB] Usando dados tratados do backend para tableData');
                setTableData(treatedData);
            } else {
                console.log('✅ [CNAB] Usando dados sanitizados localmente para tableData');
                setTableData(sanitizedData);
            }
            setStep('validate');
            
            if (extractedErrors?.erros && extractedErrors.erros.length > 0) {
                toast.warning(`${extractedErrors.erros.length} erro(s) encontrado(s). Revise os campos destacados em vermelho.`);
            } else {
                toast.success('Colunas validadas. Revise os dados antes de gerar a remessa.');
            }
            console.groupEnd();
        } catch (error) {
            console.error('❌ Erro ao validar colunas:', error);
            console.error('Stack:', error.stack);
            toast.error('Erro ao validar colunas. Verifique o mapeamento e tente novamente.');
            console.groupEnd();
        } finally {
            setLoading(false);
        }
    }, [rawData, columnMapping, paymentType]);

    /**
     * Converte tabela HTML editável para JSON
     * Usado quando o usuário edita células na tabela validada
     */
    const tableHtmlToJson = useCallback((htmlString) => {
        if (!htmlString) {
            console.warn('⚠️ [CNAB] tableHtmlToJson: HTML vazio');
            return [];
        }
        
        console.log('🔄 [CNAB] Convertendo HTML para JSON...');
        const parser = new DOMParser();
        const doc = parser.parseFromString(htmlString, 'text/html');
        const table = doc.querySelector('table#editable-table, table');
        
        if (!table) {
            console.warn('⚠️ [CNAB] Tabela não encontrada no HTML');
            return [];
        }

        const rows = Array.from(table.querySelectorAll('tbody tr')).map((tr, idx) => {
            const row = { id: idx + 1 };
            const cells = Array.from(tr.querySelectorAll('td[data-col]'));
            cells.forEach(cell => {
                const col = cell.getAttribute('data-col');
                const value = cell.textContent.trim();
                if (col) row[col] = value;
            });
            // Só retorna se tiver pelo menos um campo preenchido
            return Object.keys(row).length > 1 ? row : null;
        }).filter(row => row !== null); // Remove linhas vazias

        console.log(`✅ [CNAB] Convertidas ${rows.length} linhas para JSON`);
        if (rows.length > 0) {
            console.log('📋 Primeira linha convertida:', rows[0]);
        }

        return rows;
    }, []);

    /**
     * Atualiza o HTML da tabela após edição inline
     */
    const updateTableHtml = useCallback((newHtml) => {
        console.log('🔄 [CNAB] Atualizando HTML da tabela após edição');
        setValidatedTableHtml(newHtml);
        // Atualiza também os dados JSON
        const jsonData = tableHtmlToJson(newHtml);
        console.log(`✅ [CNAB] Dados JSON atualizados: ${jsonData.length} linhas`);
        setTableData(jsonData);
    }, [tableHtmlToJson]);

    /**
     * Atualiza uma célula específica nos dados da tabela
     */
    const updateCellValue = useCallback((rowId, field, newValue) => {
        console.log(`🔄 [CNAB] Atualizando célula: Linha ${rowId}, Campo ${field}, Valor: ${newValue}`);
        
        // Atualiza tableData com sanitização conforme as regras
        setTableData(prev => {
            const currentRow = prev.find(row => row.id === rowId);
            let sanitizedValue = newValue;
            
            // CPF/CNPJ sempre precisa ser sanitizado
            if (field === 'CPF_CNPJ_FAVORECIDO' || field === 'cpf_cnpj_favorecido') {
                sanitizedValue = sanitizeDocumentValue(newValue);
            } 
            // TIPO_CHAVE_PIX: normaliza (converte nomes para números)
            else if (field === 'TIPO_CHAVE_PIX' || field === 'tipo_chave_pix') {
                const originalTipo = newValue;
                sanitizedValue = normalizeTipoChavePix(newValue);
                if (originalTipo !== sanitizedValue) {
                    console.log(`🔄 [CNAB] Tipo de chave PIX normalizado: "${originalTipo}" → "${sanitizedValue}"`);
                }
            }
            // Chave PIX: só sanitiza se tipo for 1 (Telefone) ou 3 (CPF/CNPJ)
            else if (field === 'CHAVE_PIX' || field === 'chave_pix') {
                const tipoChavePix = currentRow?.TIPO_CHAVE_PIX || currentRow?.tipo_chave_pix;
                sanitizedValue = sanitizeChavePix(newValue, tipoChavePix);
                if (sanitizedValue !== newValue) {
                    console.log(`🧹 [CNAB] Chave PIX sanitizada (tipo ${tipoChavePix}): "${newValue}" → "${sanitizedValue}"`);
                }
            }
            
            if (sanitizedValue !== newValue && field !== 'CHAVE_PIX' && field !== 'chave_pix') {
                console.log(`🧹 [CNAB] Valor sanitizado: "${newValue}" → "${sanitizedValue}"`);
            }
            
            const updated = prev.map(row => {
                if (row.id === rowId) {
                    const updatedRow = { ...row, [field]: sanitizedValue };
                    return updatedRow;
                }
                return row;
            });
            
            const updatedRow = updated.find(r => r.id === rowId);
            console.log(`✅ [CNAB] tableData atualizado: ${updated.length} linhas`);
            console.log(`📋 [CNAB] Linha ${rowId} atualizada:`, updatedRow);
            console.log(`📋 [CNAB] Campo ${field} = "${sanitizedValue}" (era: "${currentRow?.[field]}")`);
            
            // Atualiza validatedTableHtml sincronizadamente com o valor sanitizado
            if (validatedTableHtml) {
                try {
                    const parser = new DOMParser();
                    const doc = parser.parseFromString(validatedTableHtml, 'text/html');
                    const table = doc.querySelector('table#editable-table, table');
                    
                    if (table) {
                        const rows = Array.from(table.querySelectorAll('tbody tr'));
                        const targetRow = rows[rowId - 1]; // rowId é 1-indexed
                        
                        if (targetRow) {
                            const cell = targetRow.querySelector(`td[data-col="${field}"]`);
                            if (cell) {
                                // Atualiza com o valor sanitizado, não o valor original
                                cell.textContent = sanitizedValue;
                                // Remove estilos de erro ao editar (será revalidado depois)
                                cell.style.backgroundColor = '';
                                cell.style.color = '';
                                cell.title = '';
                                
                                const newHtml = doc.documentElement.outerHTML;
                                setValidatedTableHtml(newHtml);
                                console.log('✅ [CNAB] validatedTableHtml atualizado com valor sanitizado');
                            }
                        }
                    }
                } catch (e) {
                    console.warn('⚠️ [CNAB] Erro ao atualizar HTML:', e);
                }
            }
            
            return updated;
        });

        // Limpa erros de validação para esta célula específica
        setValidationErrors(prev => {
            if (!prev || !prev.erros) return prev;
            
            const updatedErros = prev.erros.map(([rowIdx, errors]) => {
                if (rowIdx === rowId - 1) { // rowId é 1-indexed, rowIdx é 0-indexed
                    const newErrors = { ...errors };
                    delete newErrors[field];
                    return Object.keys(newErrors).length > 0 ? [rowIdx, newErrors] : null;
                }
                return [rowIdx, errors];
            }).filter(item => item !== null);
            
            return updatedErros.length > 0 
                ? { ...prev, erros: updatedErros }
                : null;
        });
    }, [validatedTableHtml, tableData]);

    /**
     * Finaliza e gera o arquivo .REM
     * Passo 4: Validação JSON → Passo 5: Geração Excel → Passo 6: Geração REM
     */
    const finalize = useCallback(async () => {
        console.group('🚀 [CNAB] Finalizando e gerando arquivo REM');
        console.log('📊 Total de linhas para validação:', tableData.length);
        console.log('💳 Tipo de pagamento:', paymentType);
        console.log('📋 Primeiras 3 linhas ANTES da sanitização:', tableData.slice(0, 3));
        
        setLoading(true);
        try {
            // IMPORTANTE: Usa tableData diretamente (já contém as edições do usuário)
            // Não usa processedValidatedData que pode estar desatualizado do HTML
            console.log('📋 Usando tableData atualizado (com edições do usuário):', tableData.length, 'linhas');
            
            // Sanitiza os dados antes de validar (remove caracteres especiais de documentos e chaves PIX)
            console.log('🧹 Sanitizando dados finais antes de validar JSON...');
            const sanitizedTableData = tableData.map(row => sanitizeRowData(row, paymentType));
            console.log('✅ Dados sanitizados:', sanitizedTableData.length, 'linhas');
            console.log('📋 Primeiras 3 linhas DEPOIS da sanitização:', sanitizedTableData.slice(0, 3));
            
            // Passo 1: Valida JSON final
            console.log('🔍 Passo 1: Validando JSON final...');
            console.log('📤 Enviando para validação:', JSON.stringify(sanitizedTableData, null, 2));
            const jsonValidation = await cnabService.validateJson(sanitizedTableData, paymentType);
            console.log('✅ Resultado da validação JSON:', jsonValidation);
            
            if (!jsonValidation.success) {
                console.error('❌ Validação JSON falhou');
                
                // Usa os erros já parseados pelo serviço ou tenta parsear
                if (jsonValidation.errors) {
                    console.log('📋 Erros já parseados pelo serviço:', jsonValidation.errors);
                    setValidationErrors(jsonValidation.errors);
                } else if (jsonValidation.html) {
                    try {
                        // Tenta parsear o HTML como JSON
                        const errorData = typeof jsonValidation.html === 'string' 
                            ? JSON.parse(jsonValidation.html) 
                            : jsonValidation.html;
                        console.log('📋 Erros parseados do HTML:', errorData);
                        setValidationErrors(errorData);
                    } catch (e) {
                        console.warn('⚠️ Não foi possível parsear erros como JSON:', e);
                        // Se não for JSON, pode ser HTML da tabela
                        setValidatedTableHtml(jsonValidation.html);
                    }
                }
                
                toast.error('Existem erros na planilha. Corrija os campos destacados e verifique os logs de erro.');
                console.groupEnd();
                return;
            }
            
            // Limpa erros se validação passou
            setValidationErrors(null);

            // Passo 2: Gera Excel validado (usa dados sanitizados)
            console.log('📊 Passo 2: Gerando Excel validado...');
            const excelBlob = await cnabService.generateExcel(sanitizedTableData, paymentType);
            console.log('✅ Excel gerado:', excelBlob?.size, 'bytes');
            
            // Passo 3: Prepara metadados
            console.log('📝 Passo 3: Preparando metadados...');
            const now = new Date();
            const dia = now.toLocaleDateString('pt-BR');
            const dia_banco = now.toISOString().split('T')[0];
            const hora = now.toTimeString().split(' ')[0];
            
            // Obtém dados do usuário do localStorage (se disponível)
            const userData = JSON.parse(localStorage.getItem('integra_user') || '{}');
            const usuarioNome = userData?.usuario?.nome || userData?.nome || 'Usuário';
            
            const variantLabel = selectedBank === 'BRADESCO' && paymentType === 'TED' && bradescoRemessaVariant === 'folha_pagamento' 
                ? ' (Folha de Pagamento)' 
                : '';

            const metadata = {
                usuario: usuarioNome,
                acao: 'Geracao de Rem',
                descricao: `${usuarioNome} realizou a geração de um arquivo CNAB240 ${paymentType}${variantLabel}, no dia ${dia} as ${hora}`,
                data_envio: `${dia_banco}T${hora}`
            };
            
            console.log('📋 Metadados:', metadata);

            // Passo 4: Gera arquivo REM
            console.log('📦 Passo 4: Gerando arquivo REM...');
            console.log('🏦 Banco selecionado:', selectedBank);
            const { blob, filename } = await cnabService.generateRemessaFile(
                excelBlob, 
                metadata, 
                paymentType,
                selectedBank, // Usa o banco selecionado do store (INTER ou BRADESCO)
                bradescoRemessaVariant // Variante TED Bradesco: 'ted' ou 'folha_pagamento'
            );

            console.log('✅ Arquivo REM gerado:', filename, blob?.size, 'bytes');
            
            setRemessaFile(blob);
            setRemessaFilename(filename);
            setStep('success');
            toast.success(`Arquivo de remessa ${paymentType} gerado com sucesso!`);
            console.groupEnd();
        } catch (error) {
            console.error('❌ Erro ao gerar remessa:', error);
            console.error('Stack:', error.stack);
            toast.error('Falha na geração do arquivo. Tente novamente.');
            console.groupEnd();
        } finally {
            setLoading(false);
        }
    }, [tableData, paymentType, selectedBank, bradescoRemessaVariant]);

    /**
     * Faz download do arquivo .REM gerado
     */
    const downloadRemessa = useCallback(() => {
        if (remessaFile && remessaFilename) {
            cnabService.downloadFile(remessaFile, remessaFilename);
        }
    }, [remessaFile, remessaFilename]);

    /**
     * Reseta todo o fluxo
     */
    const reset = useCallback(() => {
        setStep('upload');
        setTableData([]);
        setRawData([]);
        setRawHeaders([]);
        setColumnMapping({});
        setTableHtml(null);
        setValidatedTableHtml(null);
        setRemessaFile(null);
        setRemessaFilename(null);
        setValidationErrors(null);
    }, []);

    return {
        step,
        setStep,
        paymentType,
        loading,
        rawHeaders,
        rawData,
        tableHtml,
        columnMapping,
        setColumnMapping,
        validatedTableHtml,
        tableData,
        remessaFile,
        remessaFilename,
        validationErrors,
        handleUpload,
        confirmMapping,
        updateTableHtml,
        updateCellValue,
        finalize,
        downloadRemessa,
        reset,
        schemas: MODEL_SCHEMAS,
        effectivePaymentType
    };
};
