// ======= ОБЩИЕ УТИЛИТЫ И КОНСТАНТЫ =======
const SalesETaxes = {
    // Константы
    PROGRESS_UPDATE_DELAY: 50,
    AUTH_POLL_INTERVAL: 6000,
    AUTH_MAX_ATTEMPTS: 20,
    
    // Глобальные переменные
    loadingDialog: null,
    cancelLoading: false,
    loadingErrors: [],
    
    // Кэш
    cache: {
        defaultLogin: null,
        cacheTime: null,
        cacheDuration: 300000 // 5 минут
    }
};

// ======= БАЗОВЫЕ УТИЛИТЫ =======
SalesETaxes.utils = {
    // Кэшированное получение настроек входа
    getDefaultLogin: function(callback, useCache = true) {
        const now = Date.now();
        
        if (useCache && SalesETaxes.cache.defaultLogin && SalesETaxes.cache.cacheTime && 
            (now - SalesETaxes.cache.cacheTime) < SalesETaxes.cache.cacheDuration) {
            callback(SalesETaxes.cache.defaultLogin);
            return;
        }
        
        frappe.call({
            method: 'invoice_az.auth.get_default_asan_login',
            callback: function(r) {
                if (r.message) {
                    SalesETaxes.cache.defaultLogin = r.message;
                    SalesETaxes.cache.cacheTime = now;
                }
                callback(r.message);
            },
            error: function() {
                callback({found: false, error: 'Network error'});
            }
        });
    },
    
    // Проверка валидности токена
    checkTokenValidity: function(callback) {
        frappe.call({
            method: 'invoice_az.auth.check_token_validity',
            callback: function(r) {
                callback(r.message && r.message.valid);
            },
            error: function() {
                callback(false);
            }
        });
    },
    
    // Форматирование валюты
    formatCurrency: function(amount) {
        return new Intl.NumberFormat('az-AZ', {
            style: 'currency',
            currency: 'AZN',
            minimumFractionDigits: 2
        }).format(amount || 0);
    },
    
    // Очистка кэша
    clearCache: function() {
        SalesETaxes.cache.defaultLogin = null;
        SalesETaxes.cache.cacheTime = null;
    }
};

// ======= ДИАЛОГИ ЗАГРУЗКИ =======
SalesETaxes.dialogs = {
    // Показать диалог загрузки
    showLoading: function(title, message, submessage) {
        if (SalesETaxes.loadingDialog) {
            this.updateLoading(title, message, submessage);
            return;
        }
        
        SalesETaxes.loadingDialog = new frappe.ui.Dialog({
            title: title,
            fields: [{
                fieldname: 'loading_html',
                fieldtype: 'HTML',
                options: this._getLoadingHTML(title, message, submessage)
            }],
            primary_action_label: __('Cancel'),
            primary_action: function() {
                SalesETaxes.cancelLoading = true;
                SalesETaxes.loadingDialog.$wrapper.find('.primary-action').prop('disabled', true);
                SalesETaxes.loadingDialog.$wrapper.find('.primary-action').html(__('Cancelling...'));
                $('#status_message p').text(__('Cancelling the operation.'));
            }
        });
        
        SalesETaxes.cancelLoading = false;
        SalesETaxes.loadingDialog.show();
        SalesETaxes.loadingDialog.$wrapper.find('.modal-dialog').css('max-width', '450px');
    },
    
    // Обновить сообщение в диалоге
    updateLoading: function(title, message, submessage) {
        if (!SalesETaxes.loadingDialog) return;
        
        if (title) $('#loading_title').text(title);
        if (message) $('#loading_message').text(message);
        if (submessage !== undefined) {
            $('#loading_submessage').text(submessage);
            $('#loading_submessage').toggle(!!submessage);
        }
    },
    
    // Показать код верификации
    showVerificationCode: function(code) {
        if (SalesETaxes.loadingDialog && code) {
            $('#verification_code').text(code);
            $('#verification_code_container').show();
        }
    },
    
    // Установить статус успеха
    setSuccess: function(message, submessage, callback, delay = 2000) {
        if (!SalesETaxes.loadingDialog) {
            if (callback) callback();
            return;
        }
        
        SalesETaxes.loadingDialog.$wrapper.find('.loading-animation').html(`
            <div style="width: 64px; height: 64px; display: flex; align-items: center; justify-content: center;">
                <i class="fa fa-check" style="font-size: 48px; color: #5cb85c;"></i>
            </div>
        `);
        
        $('#loading_message').text(message);
        if (submessage !== undefined) {
            $('#loading_submessage').text(submessage);
            $('#loading_submessage').toggle(!!submessage);
        }
        
        $('#verification_code_container').hide();
        SalesETaxes.loadingDialog.set_primary_action(null);
        SalesETaxes.loadingDialog.set_secondary_action(null);
        
        setTimeout(() => {
            this.hide();
            if (callback) callback();
        }, delay);
    },
    
    // Установить статус ошибки
    setError: function(message, submessage, showCloseButton = true) {
        if (!SalesETaxes.loadingDialog) return;
        
        SalesETaxes.loadingDialog.$wrapper.find('.loading-animation').html(`
            <div style="width: 64px; height: 64px; display: flex; align-items: center; justify-content: center;">
                <i class="fa fa-times" style="font-size: 48px; color: #d9534f;"></i>
            </div>
        `);
        
        $('#loading_message').text(message);
        if (submessage !== undefined) {
            $('#loading_submessage').text(submessage);
            $('#loading_submessage').toggle(!!submessage);
        }
        
        $('#verification_code_container').hide();
        
        if (showCloseButton) {
            SalesETaxes.loadingDialog.set_primary_action(__('Close'), () => this.hide());
        }
    },
    
    // Скрыть диалог
    hide: function() {
        if (SalesETaxes.loadingDialog) {
            try {
                SalesETaxes.loadingDialog.hide();
            } catch (e) {
                console.error("Error hiding loading dialog:", e);
            }
            SalesETaxes.loadingDialog = null;
        }
        SalesETaxes.cancelLoading = false;
    },
    
    // Получить HTML для диалога загрузки
    _getLoadingHTML: function(title, message, submessage) {
        return `
            <div class="text-center">
                <div class="loading-animation" style="display: inline-block; width: 64px; height: 64px;">
                    <div style="width: 64px; height: 64px; border: 6px solid #4e73df; border-radius: 50%; border-color: #4e73df transparent #4e73df transparent; animation: lds-dual-ring 1.2s linear infinite;"></div>
                </div>
                <style>
                    @keyframes lds-dual-ring {
                        0% { transform: rotate(0deg); }
                        100% { transform: rotate(360deg); }
                    }
                </style>
                <div class="mt-3" id="status_message">
                    <h4 id="loading_title">${title || __('Please wait...')}</h4>
                    <p id="loading_message">${message || __('The operation may take some time')}</p>
                    <p id="loading_submessage" style="${submessage ? '' : 'display:none'}">${submessage || ''}</p>
                </div>
                <div id="verification_code_container" style="display:none; margin-top: 15px;">
                    <div style="background: #f8f9fa; padding: 10px; display: inline-block; border-radius: 5px; font-size: 24px; font-weight: bold; letter-spacing: 2px; color: #333; border: 1px solid #ddd;">
                        <span id="verification_code">----</span>
                    </div>
                    <p style="margin-top: 5px; font-size: 12px; color: #666;">Verification Code</p>
                </div>
            </div>
        `;
    }
};

// ======= МОДУЛЬ АУТЕНТИФИКАЦИИ =======
SalesETaxes.auth = {
    // Проверить токен и обработать аутентификацию при необходимости
    checkAndProcess: function(callback) {
        SalesETaxes.utils.checkTokenValidity(function(isValid) {
            if (isValid) {
                callback();
            } else {
                frappe.confirm(
                    __('Your E-Taxes session has expired or authentication is required. Would you like to authenticate now?'),
                    function() {
                        SalesETaxes.auth.startProcess(callback);
                    },
                    function() {
                        frappe.show_alert({
                            message: __('Authentication canceled. Operation cannot be completed.'),
                            indicator: 'red'
                        }, 5);
                    }
                );
            }
        });
    },
    
    // Начать процесс аутентификации
    startProcess: function(callback) {
        SalesETaxes.dialogs.showLoading(
            __('Starting Authentication'),
            __('Getting Asan Login settings...'),
            __('Please wait')
        );
        
        SalesETaxes.utils.getDefaultLogin(function(loginData) {
            if (loginData && loginData.found) {
                const asanLoginName = loginData.name;
                SalesETaxes.dialogs.updateLoading(
                    null,
                    __('Sending authentication request...'),
                    __('This will send a request to your Asan Imza mobile app')
                );
                
                frappe.call({
                    method: 'invoice_az.auth.handle_authentication',
                    args: { 'asan_login_name': asanLoginName },
                    callback: function(r) {
                        if (r.message && r.message.success) {
                            const bearerToken = r.message.bearer_token;
                            
                            if (r.message.verification_code) {
                                SalesETaxes.dialogs.showVerificationCode(r.message.verification_code);
                            }
                            
                            SalesETaxes.dialogs.updateLoading(
                                null,
                                __('Waiting for confirmation on your phone'),
                                __('Please check your phone and confirm the authentication request')
                            );
                            
                            SalesETaxes.auth.pollStatus(asanLoginName, bearerToken, function(success) {
                                if (success) {
                                    SalesETaxes.auth.complete(asanLoginName, callback);
                                } else {
                                    SalesETaxes.dialogs.setError(
                                        __('Authentication Failed'),
                                        __('Could not authenticate with Asan Imza')
                                    );
                                }
                            });
                        } else {
                            SalesETaxes.dialogs.setError(
                                __('Authentication Error'),
                                r.message ? r.message.message : __('Authentication request failed')
                            );
                        }
                    }
                });
            } else {
                SalesETaxes.dialogs.setError(
                    __('No Asan Login Settings'),
                    __('Please configure Asan Login settings first')
                );
            }
        }, false); // Не использовать кэш для аутентификации
    },
    
    // Опрос статуса аутентификации
    pollStatus: function(asanLoginName, bearerToken, callback) {
        let attempts = 0;
        let stopPolling = false;
        
        function pollStatusStep() {
            if (attempts >= SalesETaxes.AUTH_MAX_ATTEMPTS || stopPolling) {
                if (attempts >= SalesETaxes.AUTH_MAX_ATTEMPTS) {
                    SalesETaxes.dialogs.setError(
                        __('Authentication Timeout'),
                        __('The authentication request has timed out. Please try again.')
                    );
                    callback(false);
                }
                return;
            }
            
            attempts++;
            
            SalesETaxes.dialogs.updateLoading(
                null,
                __('Waiting for confirmation on your phone'),
                __('Please check your phone and confirm the authentication request') + 
                ' (' + attempts + '/' + SalesETaxes.AUTH_MAX_ATTEMPTS + ')'
            );
            
            frappe.call({
                method: 'invoice_az.auth.poll_auth_status',
                args: {
                    'asan_login_name': asanLoginName,
                    'bearer_token': bearerToken
                },
                callback: function(r) {
                    if (r.message && r.message.success) {
                        if (r.message.authenticated) {
                            stopPolling = true;
                            SalesETaxes.dialogs.setSuccess(
                                __('Authentication Successful'),
                                __('You are now authenticated with Asan Imza'),
                                function() {
                                    callback(true);
                                }
                            );
                        } else {
                            setTimeout(pollStatusStep, SalesETaxes.AUTH_POLL_INTERVAL);
                        }
                    } else {
                        stopPolling = true;
                        SalesETaxes.dialogs.setError(
                            __('Authentication Error'),
                            r.message ? r.message.message : __('An unknown error occurred')
                        );
                        callback(false);
                    }
                },
                error: function(err) {
                    console.error('Error during status check:', err);
                    setTimeout(pollStatusStep, SalesETaxes.AUTH_POLL_INTERVAL);
                }
            });
        }
        
        pollStatusStep();
    },
    
    // Завершение аутентификации
    complete: function(asanLoginName, callback) {
        SalesETaxes.dialogs.showLoading(
            __('Completing Authentication'),
            __('Getting certificates...'),
            __('Please wait')
        );
        
        frappe.call({
            method: 'invoice_az.auth.get_auth_certificates',
            args: { 'asan_login_name': asanLoginName },
            callback: function(certR) {
                if (certR.message && certR.message.success) {
                    SalesETaxes.dialogs.updateLoading(
                        null,
                        __('Certificates retrieved'),
                        __('Selecting certificate and taxpayer')
                    );
                    
                    frappe.call({
                        method: 'frappe.client.get',
                        args: {
                            doctype: 'Asan Login',
                            name: asanLoginName
                        },
                        callback: function(r) {
                            if (r.message && r.message.selected_certificate_json) {
                                try {
                                    const certData = JSON.parse(r.message.selected_certificate_json);
                                    const certName = r.message.selected_certificate;
                                    
                                    SalesETaxes.dialogs.updateLoading(
                                        null,
                                        __('Selecting certificate'),
                                        certName
                                    );
                                    
                                    SalesETaxes.auth._selectCertificate(asanLoginName, certData, certName, callback);
                                } catch (e) {
                                    console.error('Error parsing certificate:', e);
                                    SalesETaxes.dialogs.hide();
                                    SalesETaxes.auth._showCertificateSelector(certR.message.certificates, asanLoginName, callback);
                                }
                            } else {
                                SalesETaxes.dialogs.hide();
                                SalesETaxes.auth._showCertificateSelector(certR.message.certificates, asanLoginName, callback);
                            }
                        }
                    });
                } else {
                    SalesETaxes.dialogs.setError(
                        __('Error'),
                        certR.message ? certR.message.message : __('Failed to get certificates')
                    );
                }
            }
        });
    },
    
    // Выбор сертификата
    _selectCertificate: function(asanLoginName, certData, certName, callback) {
        frappe.call({
            method: 'invoice_az.auth.select_certificate',
            args: {
                'asan_login_name': asanLoginName,
                'certificate_data': certData,
                'certificate_name': certName
            },
            callback: function(r) {
                if (r.message && r.message.success) {
                    SalesETaxes.dialogs.updateLoading(
                        null,
                        __('Selecting taxpayer'),
                        __('Using certificate: ') + certName
                    );
                    
                    frappe.call({
                        method: 'invoice_az.auth.select_taxpayer',
                        args: { 'asan_login_name': asanLoginName },
                        callback: function(r) {
                            if (r.message && r.message.success) {
                                SalesETaxes.utils.clearCache(); // Очищаем кэш после успешной аутентификации
                                SalesETaxes.dialogs.setSuccess(
                                    __('Authentication Complete'),
                                    __('You can now access E-Taxes services'),
                                    callback
                                );
                            } else {
                                SalesETaxes.dialogs.setError(
                                    __('Error'),
                                    r.message ? r.message.message : __('Failed to select taxpayer')
                                );
                            }
                        }
                    });
                } else {
                    SalesETaxes.dialogs.setError(
                        __('Error'),
                        r.message ? r.message.message : __('Failed to select certificate')
                    );
                }
            }
        });
    },
    
    // Показать селектор сертификатов
    _showCertificateSelector: function(certificates, asanLoginName, callback) {
        if (!certificates || !certificates.length) {
            frappe.msgprint(__('No certificates available'));
            return;
        }
        
        let certHtml = '<div style="max-height: 400px; overflow-y: auto;"><table class="table table-bordered">';
        certHtml += '<thead><tr><th>Type</th><th>Name</th><th>ID</th><th>Position</th><th>Status</th><th></th></tr></thead><tbody>';
        
        certificates.forEach(function(cert, index) {
            let name = '';
            let id = '';
            
            if (cert.taxpayerType === 'individual' && cert.individualInfo) {
                name = cert.individualInfo.name || '';
                id = cert.individualInfo.fin || '';
            } else if (cert.legalInfo) {
                name = cert.legalInfo.name || '';
                id = cert.legalInfo.tin || cert.legalInfo.voen || '';
            }
            
            certHtml += '<tr>' +
                '<td>' + (cert.taxpayerType || '') + '</td>' +
                '<td>' + name + '</td>' +
                '<td>' + id + '</td>' +
                '<td>' + (cert.position || '') + '</td>' +
                '<td>' + (cert.hasAccess ? 'Active' : 'Inactive') + (cert.liquidated ? ' (Liquidated)' : '') + '</td>' +
                '<td><button class="btn btn-xs btn-primary select-cert" data-index="' + index + '">Select</button></td>' +
                '</tr>';
        });
        
        certHtml += '</tbody></table></div>';
        
        const dialog = new frappe.ui.Dialog({
            title: __('Select Certificate'),
            fields: [{
                fieldtype: 'HTML',
                fieldname: 'certificates',
                options: certHtml
            }]
        });
        
        dialog.show();
        
        dialog.$wrapper.find('.select-cert').on('click', function() {
            const index = $(this).data('index');
            const cert = certificates[index];
            
            let certName = '';
            if (cert.taxpayerType === 'individual' && cert.individualInfo) {
                certName = `${cert.individualInfo.name} (${cert.individualInfo.fin})`;
            } else if (cert.legalInfo) {
                certName = `${cert.legalInfo.name} (${cert.legalInfo.voen || cert.legalInfo.tin})`;
            } else {
                certName = `Certificate ${index + 1}`;
            }
            
            dialog.hide();
            
            SalesETaxes.dialogs.showLoading(
                __('Selecting Certificate'),
                __('Processing your selection...'),
                certName
            );
            
            SalesETaxes.auth._selectCertificate(asanLoginName, cert, certName, callback);
        });
    }
};

// ======= УПРАВЛЕНИЕ ОШИБКАМИ =======
SalesETaxes.errors = {
    // Добавить ошибку в лог
    add: function(invoiceData, errorType, errorMessage, additionalData = {}) {
        const errorEntry = {
            invoice_id: invoiceData.id || 'Unknown',
            serial_number: invoiceData.serialNumber || 'Unknown',
            receiver_name: invoiceData.receiver ? invoiceData.receiver.name : 'Unknown',
            creation_date: invoiceData.creationDate || invoiceData.createdAt || invoiceData.date || 'Unknown',
            error_type: errorType,
            error_message: errorMessage,
            timestamp: new Date().toISOString(),
            ...additionalData
        };
        
        SalesETaxes.loadingErrors.push(errorEntry);
        console.error('E-Taxes Sales Import Error:', errorEntry);
    },
    
    // Очистить лог ошибок
    clear: function() {
        frappe.confirm(
            __('Are you sure you want to clear the error log?'),
            function() {
                SalesETaxes.loadingErrors = [];
                frappe.show_alert({
                    message: __('Error log cleared'),
                    indicator: 'green'
                }, 2);
            }
        );
    },
    
    // Показать детальный лог ошибок
    showDetails: function() {
        if (SalesETaxes.loadingErrors.length === 0) {
            frappe.msgprint(__('No errors to display'));
            return;
        }
        
        let errorsHtml = '<div class="error-log-container">';
        
        SalesETaxes.loadingErrors.forEach(function(error, index) {
            let documentDate = 'No date';
            if (error.creation_date && error.creation_date !== 'Unknown') {
                try {
                    documentDate = moment(error.creation_date).format('DD.MM.YYYY');
                } catch (e) {
                    documentDate = 'Invalid date';
                }
            }
            
            errorsHtml += '<div class="error-item" style="margin-bottom: 20px; padding: 15px; border: 1px solid var(--border-color); border-radius: 6px; background: var(--bg-color);">';
            
            // Заголовок ошибки
            errorsHtml += '<div class="error-header" style="margin-bottom: 10px; padding-bottom: 8px; border-bottom: 1px solid var(--border-color);">';
            errorsHtml += '<div style="display: flex; justify-content: space-between; align-items: center;">';
            errorsHtml += '<h5 style="margin: 0; color: var(--text-color);">' + 
                          '<strong>' + (error.serial_number || error.invoice_id) + '</strong></h5>';
            errorsHtml += '<span class="label label-danger">' + error.error_type + '</span>';
            errorsHtml += '</div>';
            errorsHtml += '<small style="color: var(--text-muted);">' + error.receiver_name + '</small>';
            errorsHtml += '</div>';
            
            // Сообщение об ошибке
            errorsHtml += '<div class="error-message" style="margin-bottom: 10px;">';
            errorsHtml += '<strong style="color: var(--text-color);">' + error.error_message + '</strong>';
            errorsHtml += '</div>';
            
            // Детали ошибки
            if (error.unmatched_items && error.unmatched_items.length > 0) {
                errorsHtml += '<div class="error-details">';
                errorsHtml += '<div style="font-weight: 600; margin-bottom: 5px; color: var(--text-color);">' + __('Unmapped items:') + '</div>';
                errorsHtml += '<ul style="margin: 0; padding-left: 20px; color: var(--text-muted);">';
                error.unmatched_items.forEach(function(item, idx) {
                    errorsHtml += '<li><strong>Row ' + (idx + 1) + ':</strong> ' + item.name;
                    if (item.code) {
                        errorsHtml += ' <em>(Code: ' + item.code + ')</em>';
                    }
                    errorsHtml += '</li>';
                });
                errorsHtml += '</ul></div>';
            } else if (error.unmatched_parties && error.unmatched_parties.length > 0) {
                errorsHtml += '<div class="error-details">';
                errorsHtml += '<div style="font-weight: 600; margin-bottom: 5px; color: var(--text-color);">' + __('Unmapped parties:') + '</div>';
                errorsHtml += '<ul style="margin: 0; padding-left: 20px; color: var(--text-muted);">';
                error.unmatched_parties.forEach(function(party, idx) {
                    errorsHtml += '<li><strong>Party ' + (idx + 1) + ':</strong> ' + party.name;
                    if (party.tin) {
                        errorsHtml += ' <em>(TIN: ' + party.tin + ')</em>';
                    }
                    if (party.type) {
                        errorsHtml += ' <span class="label label-info" style="font-size: 10px;">' + party.type + '</span>';
                    }
                    errorsHtml += '</li>';
                });
                errorsHtml += '</ul></div>';
            } else if (error.unmatched_units && error.unmatched_units.length > 0) {
                errorsHtml += '<div class="error-details">';
                errorsHtml += '<div style="font-weight: 600; margin-bottom: 5px; color: var(--text-color);">' + __('Unmapped units:') + '</div>';
                errorsHtml += '<ul style="margin: 0; padding-left: 20px; color: var(--text-muted);">';
                error.unmatched_units.forEach(function(unit, idx) {
                    errorsHtml += '<li><strong>Unit ' + (idx + 1) + ':</strong> ' + unit.name + '</li>';
                });
                errorsHtml += '</ul></div>';
            }
            
            errorsHtml += '<div style="text-align: right; margin-top: 10px;">';
            errorsHtml += '<small style="color: var(--text-muted);"><em>' + documentDate + '</em></small>';
            errorsHtml += '</div>';
            
            errorsHtml += '</div>';
        });
        
        errorsHtml += '</div>';
        
        // Статистика
        const errorTypes = {};
        SalesETaxes.loadingErrors.forEach(function(error) {
            errorTypes[error.error_type] = (errorTypes[error.error_type] || 0) + 1;
        });
        
        let statsHtml = '<div style="margin-bottom: 20px; padding: 15px; background: var(--bg-light); border-radius: 6px; border: 1px solid var(--border-color);">';
        statsHtml += '<div style="display: flex; justify-content: space-between; align-items: center;">';
        statsHtml += '<div>';
        statsHtml += '<strong style="color: var(--text-color);">' + __('Total Errors:') + '</strong> ' + SalesETaxes.loadingErrors.length + '<br>';
        statsHtml += '<span style="color: var(--text-muted);">';
        Object.keys(errorTypes).forEach(function(type, index) {
            if (index > 0) statsHtml += ' • ';
            statsHtml += type + ': ' + errorTypes[type];
        });
        statsHtml += '</span>';
        statsHtml += '</div>';
        statsHtml += '<div>';
        statsHtml += '<button class="btn btn-default btn-sm" id="export-csv-dialog-btn" style="margin-right: 5px;">' +
                     '<i class="fa fa-download"></i> ' + __('Export CSV') + '</button>';
        statsHtml += '<button class="btn btn-warning btn-sm" id="clear-log-dialog-btn">' +
                     '<i class="fa fa-trash"></i> ' + __('Clear') + '</button>';
        statsHtml += '</div></div>';
        
        const d = new frappe.ui.Dialog({
            title: __('Error Details') + ' (' + SalesETaxes.loadingErrors.length + ')',
            size: 'large',
            fields: [
                {
                    fieldname: 'stats_html',
                    fieldtype: 'HTML',
                    options: statsHtml
                },
                {
                    fieldname: 'errors_html',
                    fieldtype: 'HTML',
                    options: '<div style="max-height: 500px; overflow-y: auto;">' + errorsHtml + '</div>'
                }
            ],
            primary_action_label: __('Close'),
            primary_action: function() {
                d.hide();
            }
        });
        
        d.show();
        
        // Добавляем обработчики событий
        setTimeout(function() {
            $('#export-csv-dialog-btn').off('click').on('click', function() {
                SalesETaxes.errors.exportCSV();
            });
            
            $('#clear-log-dialog-btn').off('click').on('click', function() {
                SalesETaxes.errors.clear();
                d.hide();
            });
        }, 200);
    },
    
    // Экспорт в CSV
    exportCSV: function() {
        if (SalesETaxes.loadingErrors.length === 0) {
            frappe.msgprint(__('No errors to export'));
            return;
        }
        
        try {
            let csvContent = "data:text/csv;charset=utf-8,";
            csvContent += "Invoice ID,Serial Number,Date,Customer,Error Type,Error Message,Timestamp\n";
            
            SalesETaxes.loadingErrors.forEach(function(error) {
                const cleanMessage = error.error_message.replace(/"/g, '""').replace(/\n/g, ' ').replace(/\r/g, ' ');
                const cleanReceiver = error.receiver_name.replace(/"/g, '""');
                
                const row = [
                    error.invoice_id,
                    error.serial_number,
                    error.creation_date,
                    cleanReceiver,
                    error.error_type,
                    cleanMessage,
                    moment(error.timestamp).format('DD.MM.YYYY HH:mm:ss')
                ].map(function(field) {
                    return '"' + (field || '') + '"';
                }).join(',');
                
                csvContent += row + "\n";
            });
            
            const encodedUri = encodeURI(csvContent);
            const link = document.createElement("a");
            link.setAttribute("href", encodedUri);
            link.setAttribute("download", "etaxes_sales_import_errors_" + moment().format('YYYY-MM-DD_HH-mm-ss') + ".csv");
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            
            frappe.show_alert({
                message: __('Error log exported successfully'),
                indicator: 'green'
            }, 3);
        } catch (e) {
            console.error('Export error:', e);
            frappe.show_alert({
                message: __('Failed to export error log'),
                indicator: 'red'
            }, 3);
        }
    },
    
    // Показать сводку результатов
    showSummary: function(totalInvoices, processedCount, errorsCount) {
        let title = '';
        let indicator = '';
        let message = '';
        
        if (errorsCount === 0) {
            title = __('Import Completed Successfully');
            indicator = 'green';
            message = __('All ') + totalInvoices + __(' sales invoices were imported successfully.');
            
            frappe.msgprint({
                title: title,
                indicator: indicator,
                message: message
            });
        } else {
            title = errorsCount === totalInvoices ? __('Import Failed') : __('Import Completed with Errors');
            indicator = processedCount > 0 ? 'orange' : 'red';
            
            message = '<div style="margin-bottom: 15px;">';
            if (processedCount > 0) {
                message += __('Successfully imported: ') + '<strong>' + processedCount + '</strong>' + __(' sales invoices') + '<br>';
            }
            message += __('Failed: ') + '<strong>' + errorsCount + '</strong>' + __(' sales invoices');
            message += '</div>';
            
            message += '<div style="text-align: center;">' +
                      '<button class="btn btn-primary btn-sm" id="view-error-details-btn" style="margin-right: 10px;">' +
                      '<i class="fa fa-list"></i> ' + __('View Error Details') + '</button>' +
                      '<button class="btn btn-default btn-sm" id="export-error-log-btn">' +
                      '<i class="fa fa-download"></i> ' + __('Export CSV') + '</button>' +
                      '</div>';
            
            const summaryDialog = frappe.msgprint({
                title: title,
                indicator: indicator,
                message: message
            });
            
            // Добавляем обработчики событий
            setTimeout(function() {
                $('#view-error-details-btn').off('click').on('click', function() {
                    summaryDialog.hide();
                    SalesETaxes.errors.showDetails();
                });
                
                $('#export-error-log-btn').off('click').on('click', function() {
                    SalesETaxes.errors.exportCSV();
                });
            }, 200);
        }
    }
};

// ======= МОДУЛЬ ИМПОРТА ИНВОЙСОВ =======
SalesETaxes.import = {
    // Показать диалог импорта из E-Taxes
    showDialog: function() {
        SalesETaxes.auth.checkAndProcess(function() {
            const minDate = moment("2020-01-01", "YYYY-MM-DD");
            
            const d = new frappe.ui.Dialog({
                title: __('Import sales invoice from E-Taxes'),
                fields: [
                    {
                        fieldname: 'date_range_section',
                        fieldtype: 'Section Break',
                        label: __('Period')
                    },
                    {
                        fieldname: 'creationDateFrom',
                        fieldtype: 'Date',
                        label: __('Date from'),
                        default: moment().subtract(1, 'month').format('YYYY-MM-DD')
                    },
                    {
                        fieldname: 'creationDateTo',
                        fieldtype: 'Date',
                        label: __('Date to'),
                        default: moment().format('YYYY-MM-DD')
                    },
                    {
                        fieldname: 'settings_section',
                        fieldtype: 'Section Break',
                        label: __('Settings')
                    },
                    {
                        fieldname: 'warehouse',
                        fieldtype: 'Link',
                        label: __('Delivery warehouse'),
                        options: 'Warehouse',
                        reqd: true,
                        get_query: function() {
                            return {
                                filters: {
                                    'is_group': 0,
                                    'disabled': 0
                                }
                            };
                        }
                    }
                ],
                primary_action_label: __('Search'),
                primary_action: function() {
                    const values = d.get_values();
                    
                    // Validate date range
                    const fromDateMoment = moment(values.creationDateFrom, "YYYY-MM-DD");
                    const toDateMoment = moment(values.creationDateTo, "YYYY-MM-DD");
                    const todayMoment = moment();
                    
                    if (fromDateMoment.isBefore(minDate)) {
                        frappe.msgprint(__('From Date cannot be earlier than January 1, 2020'));
                        return;
                    }
                    
                    if (toDateMoment.isAfter(todayMoment)) {
                        frappe.msgprint(__('To Date cannot be later than today'));
                        return;
                    }
                    
                    if (!values.warehouse) {
                        frappe.msgprint({
                            title: __('Warning'),
                            indicator: 'orange',
                            message: __('Please select a delivery warehouse')
                        });
                        return;
                    }
                    
                    const fromDate = moment(values.creationDateFrom).format('DD-MM-YYYY 00:00');
                    const toDate = moment(values.creationDateTo).format('DD-MM-YYYY 23:59');
                    
                    d.hide();
                    SalesETaxes.import.loadInvoices(fromDate, toDate, values.warehouse);
                }
            });
            
            d.show();
        });
    },
    
    // Загрузить инвойсы с фильтрацией дубликатов
    loadInvoices: function(fromDate, toDate, warehouse, accumulatedInvoices = [], offset = 0) {
        SalesETaxes.cancelLoading = false;
        $(document).off('progress-cancel.etaxes_sales_import');
        
        if (offset === 0) {
            frappe.show_alert({
                message: __('Fetching E-Taxes sales invoices...'),
                indicator: 'blue'
            }, 3);
        }
        
        SalesETaxes.utils.getDefaultLogin(function(loginResponse) {
            if (SalesETaxes.cancelLoading) return;
            
            if (loginResponse && loginResponse.found) {
                const mainToken = loginResponse.main_token;
                
                if (!mainToken) {
                    frappe.msgprint({
                        title: __('Authentication Error'),
                        indicator: 'red',
                        message: __('Authentication token not found. Please complete the authentication process in E-Taxes settings.')
                    });
                    return;
                }
                
                const maxCount = 200;
                
                frappe.call({
                    method: 'invoice_az.sales_api.get_sales_invoices',
                    args: {
                        'token': mainToken,
                        'filters': JSON.stringify({
                            "creationDateFrom": fromDate,
                            "creationDateTo": toDate,
                            "maxCount": maxCount,
                            "offset": offset
                        })
                    },
                    callback: function(r) {
                        if (SalesETaxes.cancelLoading) return;
                        
                        if (r.message && !r.message.error) {
                            const currentInvoices = r.message.data || r.message.invoices || [];
                            const hasMore = r.message.hasMore || false;
                            const allInvoices = accumulatedInvoices.concat(currentInvoices);
                            
                            if (hasMore && currentInvoices.length > 0) {
                                const newOffset = offset + currentInvoices.length;
                                SalesETaxes.import.loadInvoices(fromDate, toDate, warehouse, allInvoices, newOffset);
                            } else {
                                if (allInvoices.length > 0) {
                                    frappe.show_alert({
                                        message: __('Processing ') + allInvoices.length + __(' invoices...'),
                                        indicator: 'blue'
                                    }, 3);
                                    
                                    SalesETaxes.import.filterDuplicates(allInvoices, mainToken, warehouse);
                                } else {
                                    frappe.msgprint({
                                        title: __('Information'),
                                        indicator: 'blue',
                                        message: __('No sales invoices found for the specified period')
                                    });
                                }
                            }
                        } else if (r.message && r.message.error === 'unauthorized') {
                            frappe.confirm(
                                __('Your E-Taxes session has expired. Would you like to authenticate now?'),
                                function() {
                                    SalesETaxes.auth.startProcess(function() {
                                        SalesETaxes.import.loadInvoices(fromDate, toDate, warehouse);
                                    });
                                },
                                function() {
                                    frappe.show_alert({
                                        message: __('Authentication canceled. Operation cannot be completed.'),
                                        indicator: 'red'
                                    }, 5);
                                }
                            );
                        } else {
                            frappe.msgprint({
                                title: __('Error'),
                                indicator: 'red',
                                message: r.message ? r.message.message : __('Error loading sales invoices')
                            });
                        }
                    },
                    error: function(xhr, status, error) {
                        console.error("Error fetching sales invoices:", error);
                        frappe.msgprint({
                            title: __('Network Error'),
                            indicator: 'red',
                            message: __('Error fetching data from server: ') + (error || 'Unknown error')
                        });
                    }
                });
            } else {
                frappe.msgprint({
                    title: __('Error'),
                    indicator: 'red',
                    message: __('E-Taxes authentication settings not found')
                });
            }
        });
    },
    
    // Фильтрация дубликатов
    filterDuplicates: function(allInvoices, token, warehouse) {
        frappe.call({
            method: 'invoice_az.sales_api.get_etaxes_sales',
            callback: function(etaxesR) {
                try {
                    if (SalesETaxes.cancelLoading) return;
                    
                    const importedInvoices = {};
                    
                    if (etaxesR.message && etaxesR.message.success && etaxesR.message.sales) {
                        etaxesR.message.sales.forEach(function(sale) {
                            if (sale.etaxes_id) {
                                const normId = String(sale.etaxes_id).trim();
                                importedInvoices[normId] = true;
                            }
                        });
                    }
                    
                    const filteredInvoices = [];
                    
                    for (let i = 0; i < allInvoices.length; i++) {
                        const invoice = allInvoices[i];
                        const invoiceId = String(invoice.id).trim();
                        
                        if (!importedInvoices.hasOwnProperty(invoiceId)) {
                            filteredInvoices.push(invoice);
                        }
                    }
                    
                    if (filteredInvoices.length > 0) {
                        SalesETaxes.import.showInvoiceSelection(filteredInvoices, token, warehouse);
                    } else {
                        frappe.msgprint({
                            title: __('Information'),
                            indicator: 'blue',
                            message: __('No new sales invoices found for the specified period (all ' + 
                                allInvoices.length + ' are already imported)')
                        });
                    }
                } catch (e) {
                    console.error("Error processing sales data:", e);
                    frappe.msgprint({
                        title: __('Error'),
                        indicator: 'red',
                        message: __('An error occurred while processing data: ') + e.message
                    });
                }
            },
            error: function(err) {
                console.error("Error fetching sales:", err);
                SalesETaxes.import.showInvoiceSelection(allInvoices, token, warehouse);
                frappe.show_alert({
                    message: __('Failed to check for duplicates. Showing all sales invoices.'),
                    indicator: 'orange'
                }, 5);
            }
        });
    },

    // Показать диалог выбора инвойсов
    showInvoiceSelection: function(invoices, token, warehouse) {
        let invoiceTable = '<div style="max-height: 500px; overflow-y: auto;"><table class="table table-bordered etaxes-sales-invoices-table" style="width: 100%; table-layout: fixed;">';
        invoiceTable += '<thead><tr>' +
                    '<th style="width: 6%;"><input type="checkbox" class="select-all-sales-invoices"></th>' +
                    '<th style="width: 24%;">' + __('Number') + '</th>' +
                    '<th style="width: 16%;">' + __('Date') + '</th>' +
                    '<th style="width: 38%;">' + __('Customer') + '</th>' +
                    '<th style="width: 16%;">' + __('Amount') + '</th>' +
                    '</tr></thead><tbody>';
        
        invoices.forEach(function(invoice) {
            const serialNumber = invoice.serialNumber || '';
            
            let creationDate = '';
            if (invoice.createdAt) {
                creationDate = moment(invoice.createdAt).format('DD.MM.YYYY');
            } else if (invoice.creationDate) {
                creationDate = moment(invoice.creationDate).format('DD.MM.YYYY');
            }
            
            const receiverName = invoice.receiver ? invoice.receiver.name : (invoice.receiverName || '');
            const amount = invoice.totalAmount || invoice.amount || 0;
            
            invoiceTable += '<tr>' +
                        '<td><input type="checkbox" class="select-sales-invoice" data-id="' + invoice.id + '"></td>' +
                        '<td style="word-break: break-word;">' + serialNumber + '</td>' +
                        '<td>' + creationDate + '</td>' +
                        '<td style="word-break: break-word;">' + receiverName + '</td>' +
                        '<td style="text-align: right;">' + SalesETaxes.utils.formatCurrency(amount) + '</td>' +
                        '</tr>';
        });
        
        invoiceTable += '</tbody></table></div>';
        
        const infoMessage = '<div class="alert alert-info">' +
                           __('Sales invoices found: ') + invoices.length + 
                           '</div>';
        
        const d = new frappe.ui.Dialog({
            title: __('Select sales invoice'),
            size: 'large',
            fields: [
                {
                    fieldname: 'info_html',
                    fieldtype: 'HTML',
                    options: infoMessage
                },
                {
                    fieldname: 'invoices_html',
                    fieldtype: 'HTML',
                    options: invoiceTable
                },
                {
                    fieldname: 'warehouse_display',
                    fieldtype: 'HTML',
                    options: '<div class="row"><div class="col-xs-12"><div class="alert alert-info">' + 
                             __('Selected delivery warehouse: ') + '<strong>' + warehouse + '</strong></div></div></div>'
                }
            ],
            primary_action_label: __('Load selected'),
            primary_action: function() {
                const selectedInvoiceIds = [];
                d.$wrapper.find('.select-sales-invoice:checked').each(function() {
                    selectedInvoiceIds.push($(this).data('id'));
                });
                
                if (selectedInvoiceIds.length === 0) {
                    frappe.msgprint({
                        title: __('Warning'),
                        indicator: 'orange',
                        message: __('No sales invoices selected')
                    });
                    return;
                }
                
                d.hide();
                SalesETaxes.cancelLoading = false;
                SalesETaxes.import.loadSelectedInvoices(selectedInvoiceIds, token, warehouse);
            },
            secondary_action_label: __('Cancel'),
            secondary_action: function() {
                d.hide();
            }
        });
        
        d.$wrapper.find('.modal-dialog').css({
            'max-width': '80%',
            'width': '80%',
            'margin': '30px auto'
        });
        
        d.$wrapper.find('.modal-body').css({
            'padding': '15px'
        });
        
        d.show();
        
        // Обработчик для чекбокса "выбрать все"
        d.$wrapper.find('.select-all-sales-invoices').on('change', function() {
            const isChecked = $(this).prop('checked');
            d.$wrapper.find('.select-sales-invoice').prop('checked', isChecked);
        });
    },
    
    // Загрузка выбранных инвойсов
    loadSelectedInvoices: function(invoiceIds, token, warehouse, processedCount = 0, currentIndex = 0) {
        if (processedCount === 0 && currentIndex === 0) {
            SalesETaxes.loadingErrors = [];
            window.totalSalesInvoicesToProcess = invoiceIds.length;
        }
        
        $(document).off('progress-cancel.loading_sales_invoices');
        
        if (invoiceIds.length === 0) {
            frappe.hide_progress();
            
            const errorsCount = SalesETaxes.loadingErrors.length;
            const totalInvoices = window.totalSalesInvoicesToProcess || processedCount;
            
            SalesETaxes.errors.showSummary(totalInvoices, processedCount, errorsCount);
            window.totalSalesInvoicesToProcess = null;
            
            if (cur_list) {
                cur_list.refresh();
            }
            
            return;
        }
        
        if (SalesETaxes.cancelLoading) {
            invoiceIds = [];
            frappe.hide_progress();
            SalesETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex);
            return;
        }
        
        const invoiceId = invoiceIds.shift();
        const isLastInvoice = invoiceIds.length === 0;
        const totalToProcess = window.totalSalesInvoicesToProcess || (processedCount + invoiceIds.length + 1);
        
        currentIndex++;
        
        frappe.show_progress(__('Importing Sales Invoices'), currentIndex - 1, totalToProcess, 
            __('Loading sales invoice ') + currentIndex + __(' of ') + totalToProcess, null, true);
        
        $(document).on('progress-cancel.loading_sales_invoices', function() {
            SalesETaxes.cancelLoading = true;
            frappe.show_alert({
                message: __('Cancelling import... Finishing current sales invoice.'),
                indicator: 'orange'
            }, 3);
            frappe.hide_progress();
        });
        
        frappe.call({
            method: 'invoice_az.sales_api.get_sales_invoice_details',
            args: {
                'token': token,
                'invoice_id': invoiceId
            },
            callback: function(r) {
                if (r.message && !r.message.error) {
                    const creationDate = r.message.creationDate || r.message.date || frappe.datetime.nowdate();
                    const scheduleDate = moment(creationDate).format('YYYY-MM-DD');
                    const serialNumber = r.message.serialNumber || '';
                    const receiverName = r.message.receiver ? r.message.receiver.name : '';
                    const total = r.message.totalAmount || r.message.amount || 0;
                    
                    frappe.show_progress(__('Importing Sales Invoices'), currentIndex - 1, totalToProcess, 
                        __('Importing sales invoice: ') + serialNumber);
                    
                    frappe.call({
                        method: 'invoice_az.sales_api.import_sales_invoice_with_mapping',
                        args: {
                            'invoice_data': r.message,
                            'sales_order_name': null,
                            'schedule_date': scheduleDate,
                            'warehouse': warehouse  // ДОБАВЛЕНО: передача warehouse
                        },
                        callback: function(importR) {
                            SalesETaxes.import._handleImportResult(importR, r.message, invoiceId, scheduleDate, receiverName, total, 
                                invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice);
                        },
                        error: function(xhr, status, error) {
                            const errorMessage = 'Network error during import: ' + (error || 'Unknown network error');
                            SalesETaxes.errors.add(r.message, 'Network Error', errorMessage, {
                                invoice_items: r.message.items || [],
                                xhr_status: xhr.status,
                                xhr_response: xhr.responseText
                            });
                            
                            SalesETaxes.import._continueOrFinish(invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice);
                        }
                    });
                } else if (r.message && r.message.error === 'unauthorized') {
                    frappe.hide_progress();
                    $(document).off('progress-cancel.loading_sales_invoices');
                    
                    frappe.confirm(
                        __('Your E-Taxes session has expired. Would you like to authenticate now?'),
                        function() {
                            SalesETaxes.auth.startProcess(function() {
                                SalesETaxes.utils.getDefaultLogin(function(loginR) {
                                    if (loginR && loginR.found && loginR.main_token) {
                                        invoiceIds.unshift(invoiceId);
                                        SalesETaxes.import.loadSelectedInvoices(invoiceIds, loginR.main_token, warehouse, processedCount, currentIndex - 1);
                                    } else {
                                        SalesETaxes.errors.add({id: invoiceId}, 'Authentication Error', 
                                            'Failed to get token after authentication');
                                        
                                        const errorsCount = SalesETaxes.loadingErrors.length;
                                        SalesETaxes.errors.showSummary(totalToProcess, processedCount, errorsCount);
                                    }
                                }, false);
                            });
                        },
                        function() {
                            SalesETaxes.errors.add({id: invoiceId}, 'Authentication Cancelled', 
                                'User cancelled authentication process');
                            
                            const errorsCount = SalesETaxes.loadingErrors.length;
                            SalesETaxes.errors.showSummary(totalToProcess, processedCount, errorsCount);
                        }
                    );
                } else {
                    const errorMessage = r.message ? r.message.message : 'Failed to load sales invoice details';
                    SalesETaxes.errors.add({id: invoiceId}, 'Sales Invoice Data Error', errorMessage, {
                        server_response: r.message
                    });
                    
                    SalesETaxes.import._continueOrFinish(invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice);
                }
            },
            error: function(xhr, status, error) {
                const errorMessage = 'Network error loading sales invoice details: ' + (error || 'Unknown network error');
                SalesETaxes.errors.add({id: invoiceId}, 'Network Error', errorMessage, {
                    xhr_status: xhr.status,
                    xhr_response: xhr.responseText
                });
                
                SalesETaxes.import._continueOrFinish(invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice);
            }
        });
    },
    
    // Обработка результата импорта - ОБНОВЛЕНО для Sales Order + Sales Invoice
    _handleImportResult: function(importR, invoiceMessage, invoiceId, scheduleDate, receiverName, total, 
                                invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice) {
        if (importR.message && importR.message.success) {
            frappe.show_alert({
                message: __('Sales invoice successfully imported: ') + (invoiceMessage.serialNumber || ''),
                indicator: 'green'
            }, 3);
            
            // ИЗМЕНЕНО: теперь получаем sales_order и sales_invoice из ответа
            const salesOrderName = importR.message.sales_order;
            const salesInvoiceName = importR.message.sales_invoice;
            
            // ИЗМЕНЕНО: создание E-Taxes Sales и связывание с Sales Order происходит на сервере
            // Поэтому просто увеличиваем счетчик и продолжаем
            processedCount++;
            SalesETaxes.import._continueOrFinish(invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice);
            
        } else if (importR.message && (importR.message.unmatched_items || importR.message.unmatched_parties || importR.message.unmatched_units)) {
            let errorType = '';
            const additionalData = { invoice_items: invoiceMessage.items || [] };
            
            if (importR.message.unmatched_items) {
                errorType = 'Unmapped Items';
                additionalData.unmatched_items = importR.message.unmatched_items.map(function(item, index) {
                    let itemName = '';
                    let itemCode = '';
                    
                    if (typeof item === 'string') {
                        itemName = item;
                    } else if (item && typeof item === 'object') {
                        itemName = item.name || item.productName || item.item_name || '';
                        itemCode = item.code || item.itemId || item.item_code || '';
                    } else {
                        if (invoiceMessage.items && invoiceMessage.items[index]) {
                            const originalItem = invoiceMessage.items[index];
                            itemName = originalItem.productName || originalItem.name || '';
                            itemCode = originalItem.itemId || originalItem.code || '';
                        }
                    }
                    
                    if (!itemName) {
                        itemName = 'Item ' + (index + 1) + ' (name not available)';
                    }
                    
                    return {
                        name: itemName,
                        code: itemCode
                    };
                });
            } else if (importR.message.unmatched_parties) {
                errorType = 'Unmapped Parties';
                additionalData.unmatched_parties = importR.message.unmatched_parties.map(function(party, index) {
                    let partyName = '';
                    let partyTin = '';
                    let partyType = '';
                    
                    if (typeof party === 'string') {
                        partyName = party;
                    } else if (party && typeof party === 'object') {
                        partyName = party.name || party.party_name || '';
                        partyTin = party.tin || party.tax_id || '';
                        partyType = party.type || party.party_type || '';
                    } else {
                        if (invoiceMessage.receiver) {
                            partyName = invoiceMessage.receiver.name || '';
                            partyTin = invoiceMessage.receiver.tin || '';
                            partyType = 'Receiver';
                        }
                    }
                    
                    if (!partyName) {
                        partyName = 'Party ' + (index + 1) + ' (name not available)';
                    }
                    
                    return {
                        name: partyName,
                        tin: partyTin,
                        type: partyType
                    };
                });
            } else if (importR.message.unmatched_units) {
                errorType = 'Unmapped Units';
                additionalData.unmatched_units = importR.message.unmatched_units.map(function(unit, index) {
                    let unitName = '';
                    
                    if (typeof unit === 'string') {
                        unitName = unit;
                    } else if (unit && typeof unit === 'object') {
                        unitName = unit.name || unit.unit_name || '';
                    } else {
                        if (invoiceMessage.items && invoiceMessage.items[index] && invoiceMessage.items[index].unit) {
                            unitName = invoiceMessage.items[index].unit;
                        }
                    }
                    
                    if (!unitName) {
                        unitName = 'Unit ' + (index + 1) + ' (name not available)';
                    }
                    
                    return {
                        name: unitName
                    };
                });
            }
            
            additionalData.server_response = importR.message;
            SalesETaxes.errors.add(invoiceMessage, errorType, importR.message.message, additionalData);
            
            SalesETaxes.import._continueOrFinish(invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice);
        } else {
            const errorMessage = importR.message ? importR.message.message : 'Unknown sales import error';
            const additionalData = {
                invoice_items: invoiceMessage.items || [],
                server_response: importR.message
            };
            
            if (importR.exc) {
                additionalData.stack_trace = importR.exc;
            }
            
            SalesETaxes.errors.add(invoiceMessage, 'Sales Import Error', errorMessage, additionalData);
            SalesETaxes.import._continueOrFinish(invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice);
        }
    },
    
    // Продолжить или завершить обработку
    _continueOrFinish: function(invoiceIds, token, warehouse, processedCount, currentIndex, isLastInvoice) {
        if (isLastInvoice) {
            frappe.hide_progress();
            $(document).off('progress-cancel.loading_sales_invoices');
            
            const totalToProcess = window.totalSalesInvoicesToProcess || processedCount;
            const errorsCount = SalesETaxes.loadingErrors.length;
            SalesETaxes.errors.showSummary(totalToProcess, processedCount, errorsCount);
            
            if (cur_list) {
                cur_list.refresh();
            }
            return;
        }
        
        setTimeout(function() {
            if (invoiceIds.length === 0) {
                frappe.hide_progress();
            }
            
            SalesETaxes.import.loadSelectedInvoices(invoiceIds, token, warehouse, processedCount, currentIndex);
        }, SalesETaxes.PROGRESS_UPDATE_DELAY);
    }
};

// ======= ОСНОВНЫЕ ОБРАБОТЧИКИ ФОРМ И СПИСКОВ =======

// Sales Order Form
frappe.ui.form.on('Sales Order', {
    refresh: function(frm) {
        if (frm.doc.is_taxes_doc) {
            frm.set_read_only(true);
            frm.page.set_indicator(__('Tax Document'), 'blue');
        }
    },
    
    onload: function(frm) {
        frm.set_df_property('is_taxes_doc', 'read_only', 1);
    }
});

frappe.listview_settings['Sales Order'] = {
    add_fields: ['customer', 'transaction_date', 'status', 'docstatus', 'is_taxes_doc', 'taxes_doc'],
    
    get_indicator: function(doc) {
        if (doc.status === 'Closed') {
            return [__('Closed'), 'green', 'status,=,Closed'];
        } else if (doc.status === 'On Hold') {
            return [__('On Hold'), 'orange', 'status,=,On Hold'];
        } else if (doc.status === 'Delivered') {
            return [__('Delivered'), 'green', 'status,=,Delivered'];
        } else if (doc.docstatus == 1) {
            return [__('To Deliver and Bill'), 'orange', 'docstatus,=,1'];
        } else if (doc.docstatus == 0) {
            return [__('Draft'), 'red', 'docstatus,=,0'];
        } else if (doc.docstatus == 2) {
            return [__('Cancelled'), 'grey', 'docstatus,=,2'];
        }
    },
    
    onload: function(listview) {
        // ДОБАВЛЕНО: кнопка импорта из E-Taxes для Sales Order
        listview.page.add_menu_item(__('Import from E-Taxes'), function() {
            SalesETaxes.import.showDialog();
        });
        
        listview.columns.push({
            type: 'Check',
            df: {
                label: __('Tax Doc'),
                fieldname: 'is_taxes_doc'
            },
            width: 120
        });
        
        listview.refresh();
    },
    
    formatters: {
        is_taxes_doc: function(value) {
            return value ? 
                `<span class="indicator-pill green"></span>` : 
                `<span class="indicator-pill gray"></span>`;
        }
    }
};

// Sales Invoice Form
frappe.ui.form.on('Sales Invoice', {
    refresh: function(frm) {
        if (frm.doc.is_taxes_doc) {
            frm.set_read_only(true);
            frm.page.set_indicator(__('Tax Document'), 'blue');
        }
    },
    
    onload: function(frm) {
        frm.set_df_property('is_taxes_doc', 'read_only', 1);
    }
});

// Sales Invoice List - УБРАНО: кнопка импорта (теперь только в Sales Order)
frappe.listview_settings['Sales Invoice'] = {
    add_fields: ['customer', 'posting_date', 'status', 'docstatus', 'is_taxes_doc'],
    
    onload: function(listview) {
        // УБРАНО: кнопка импорта - теперь импорт только через Sales Order
        
        listview.columns.push({
            type: 'Check',
            df: {
                label: __('Tax Doc'),
                fieldname: 'is_taxes_doc'
            },
            width: 120
        });
        
        listview.refresh();
    },
    
    formatters: {
        is_taxes_doc: function(value) {
            return value ? 
                `<span class="indicator-pill green"></span>` : 
                `<span class="indicator-pill gray"></span>`;
        }
    }
};