// Настройки списка E-Taxes Customers с прогресс баром
frappe.listview_settings['E-Taxes Customers'] = {
    add_fields: ['status', 'mapped_customer'],
    
    get_indicator: function(doc) {
        if (doc.status === 'Mapped') {
            return [__('Mapped'), 'green', 'status,=,Mapped'];
        } else if (doc.status === 'Processing') {
            return [__('Processing'), 'orange', 'status,=,Processing'];
        } else {
            return [__('New'), 'red', 'status,=,New'];
        }
    },
    
    onload: function(listview) {
        // Add button to load customers from E-Taxes
        listview.page.add_menu_item(__('Load from E-Taxes'), function() {
            // Сначала проверяем актуальность токена перед загрузкой
            check_and_process_token_customers(function() {
                show_invoice_filter_dialog_customers();
            });
        });
    }
};

// Глобальная переменная для хранения диалога загрузки
var loading_dialog_customers = null;

// Очистка состояния при закрытии/перезагрузке страницы
$(window).on('beforeunload', function() {
    cleanup_customers_loading_state();
});

// Очистка состояния при переходе на другую страницу
$(document).on('page:before-change', function() {
    cleanup_customers_loading_state();
});

// НОВАЯ ФУНКЦИЯ: Очистка состояния загрузки customers
function cleanup_customers_loading_state() {
    try {
        // Скрываем прогресс бар
        frappe.hide_progress();
        
        // Удаляем event listeners
        $(document).off('progress-cancel.loading_customers');
        
        // Очищаем глобальные переменные
        if (typeof window.cancelCustomersLoading !== 'undefined') {
            delete window.cancelCustomersLoading;
        }
        if (typeof window.totalCustomersToProcess !== 'undefined') {
            delete window.totalCustomersToProcess;
        }
        
        // ВАЖНО: Скрываем все возможные диалоги загрузки
        hide_loading_dialog_customers();
        
        // Дополнительная очистка - удаляем все модальные окна, которые могут висеть
        $('.modal-backdrop').remove();
        $('body').removeClass('modal-open');
        
        // Очищаем любые блокировки интерфейса
        frappe.dom.unfreeze();
        
        console.log('Customers loading state cleaned up');
    } catch (e) {
        console.error('Error during customers cleanup:', e);
        // В крайнем случае, принудительно разблокируем интерфейс
        frappe.dom.unfreeze();
        $('.modal-backdrop').remove();
        $('body').removeClass('modal-open');
    }
}

// Функция для отображения диалога загрузки с анимацией
function show_loading_dialog_customers(title, message, submessage) {
    // Если диалог уже открыт, обновляем только сообщение
    if (loading_dialog_customers) {
        $('#loading_title_customers').text(title);
        $('#loading_message_customers').text(message);
        if (submessage) {
            $('#loading_submessage_customers').text(submessage).show();
        } else {
            $('#loading_submessage_customers').hide();
        }
        return;
    }
    
    // Создаем диалог с анимацией загрузки
    loading_dialog_customers = new frappe.ui.Dialog({
        title: title,
        fields: [
            {
                fieldname: 'loading_html',
                fieldtype: 'HTML',
                options: `
                    <div class="text-center">
                        <div class="lds-dual-ring" 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">
                            <h4 id="loading_title_customers">${title}</h4>
                            <p id="loading_message_customers">${message}</p>
                            <p id="loading_submessage_customers" style="${submessage ? '' : 'display:none'}">${submessage || ''}</p>
                            <!-- Блок для отображения кода верификации -->
                            <div id="verification_code_container_customers" 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_customers">----</span>
                                </div>
                                <p style="margin-top: 5px; font-size: 12px; color: #666;">Verification Code</p>
                            </div>
                        </div>
                    </div>
                `
            }
        ]
    });
    
    loading_dialog_customers.show();
    loading_dialog_customers.$wrapper.find('.modal-dialog').css('max-width', '450px');
}

// ИСПРАВЛЕННАЯ функция для скрытия диалога загрузки
function hide_loading_dialog_customers() {
    if (loading_dialog_customers) {
        try {
            loading_dialog_customers.hide();
            loading_dialog_customers = null;
        } catch (e) {
            console.error('Error hiding loading dialog customers:', e);
            loading_dialog_customers = null;
        }
    }
}

// Функция для обновления сообщения в диалоге загрузки
function update_loading_message_customers(message, submessage) {
    if (loading_dialog_customers) {
        $('#loading_message_customers').text(message);
        if (submessage !== undefined) {
            $('#loading_submessage_customers').text(submessage);
            $('#loading_submessage_customers').toggle(!!submessage);
        }
    }
}

// Функция для изменения статуса загрузки на успешный с автоматическим закрытием
function set_loading_success_customers(message, submessage, callback, delay = 2000) {
    if (loading_dialog_customers) {
        // Меняем анимацию на галочку
        loading_dialog_customers.$wrapper.find('.lds-dual-ring').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_customers').text(message);
        if (submessage !== undefined) {
            $('#loading_submessage_customers').text(submessage);
            $('#loading_submessage_customers').toggle(!!submessage);
        }
        
        // Скрываем код верификации при успешном завершении
        $('#verification_code_container_customers').hide();
        
        // Удаляем все существующие кнопки действий
        loading_dialog_customers.set_primary_action(null);
        loading_dialog_customers.set_secondary_action(null);
        
        // Автоматически закрываем через указанную задержку
        setTimeout(function() {
            if (loading_dialog_customers) {
                loading_dialog_customers.hide();
                loading_dialog_customers = null;
            }
            if (callback) callback();
        }, delay);
    } else if (callback) {
        // Если диалог не открыт, но есть callback, вызываем его
        callback();
    }
}

// Функция для изменения статуса загрузки на ошибку
function set_loading_error_customers(message, submessage, show_close_button = true) {
    if (loading_dialog_customers) {
        // Меняем анимацию на крестик
        loading_dialog_customers.$wrapper.find('.lds-dual-ring').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_customers').text(message);
        if (submessage !== undefined) {
            $('#loading_submessage_customers').text(submessage);
            $('#loading_submessage_customers').toggle(!!submessage);
        }
        
        // Скрываем код верификации при ошибке
        $('#verification_code_container_customers').hide();
        
        // При необходимости добавляем кнопку закрытия
        if (show_close_button) {
            loading_dialog_customers.set_primary_action(__('Close'), function() {
                hide_loading_dialog_customers();
            });
        }
    }
}

// Функция для проверки токена и обработки аутентификации при необходимости
function check_and_process_token_customers(callback) {
    // Проверяем, доступен ли новый модуль ETaxes
    if (typeof ETaxes !== 'undefined' && ETaxes.auth) {
        ETaxes.auth.checkAndProcess(callback);
        return;
    }
    
    // Fallback на старый код
    frappe.call({
        method: 'invoice_az.auth.check_token_validity',
        callback: function(r) {
            if (r.message && r.message.valid) {
                callback();
            } else {
                frappe.confirm(
                    __('Your E-Taxes session has expired or authentication is required. Would you like to authenticate now?'),
                    function() {
                        start_authentication_process_customers(callback);
                    },
                    function() {
                        frappe.show_alert({
                            message: __('Authentication canceled. Operation cannot be completed.'),
                            indicator: 'red'
                        }, 5);
                    }
                );
            }
        },
        error: function() {
            frappe.msgprint({
                title: __('Error'),
                indicator: 'red',
                message: __('Failed to check authentication status')
            });
        }
    });
}

// Функция для запуска полного процесса аутентификации
function start_authentication_process_customers(callback) {
    show_loading_dialog_customers(
        __('Starting Authentication'),
        __('Getting Asan Login settings...'),
        __('Please wait')
    );
    
    frappe.call({
        method: 'invoice_az.auth.get_default_asan_login',
        callback: function(r) {
            if (r.message && r.message.found) {
                var asan_login_name = r.message.name;
                update_loading_message_customers(
                    __('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': asan_login_name
                    },
                    callback: function(r) {
                        if (r.message && r.message.success) {
                            const bearer_token = r.message.bearer_token;
                            
                            // Отображаем код верификации, если он есть в ответе
                            if (r.message.verification_code) {
                                $('#verification_code_customers').text(r.message.verification_code);
                                $('#verification_code_container_customers').attr('style', 'display: block !important; margin-top: 15px;');
                            }
                            
                            // Изменяем сообщение для ожидания подтверждения
                            update_loading_message_customers(
                                __('Waiting for confirmation on your phone'),
                                __('Please check your phone and confirm the authentication request')
                            );
                            
                            // Опрашиваем статус аутентификации
                            poll_authentication_status_customers(asan_login_name, bearer_token, function(success) {
                                if (success) {
                                    // Если аутентификация успешна, продолжаем процесс
                                    complete_authentication_customers(asan_login_name, callback);
                                } else {
                                    // Если аутентификация не удалась, показываем сообщение об ошибке
                                    set_loading_error_customers(
                                        __('Authentication Failed'),
                                        __('Could not authenticate with Asan Imza')
                                    );
                                }
                            });
                        } else {
                            // Если запрос не удался, показываем сообщение об ошибке
                            set_loading_error_customers(
                                __('Authentication Error'),
                                r.message ? r.message.message : __('Authentication request failed')
                            );
                        }
                    }
                });
            } else {
                // Если настройки не найдены, показываем сообщение об ошибке
                set_loading_error_customers(
                    __('No Asan Login Settings'),
                    __('Please configure Asan Login settings first')
                );
            }
        }
    });
}

// Функция для опроса статуса аутентификации
function poll_authentication_status_customers(asan_login_name, bearer_token, callback) {
    // Счетчик попыток и флаг для остановки опроса
    let attempts = 0;
    const maxAttempts = 20; // 20 попыток с интервалом 6 секунд
    let stopPolling = false;
    
    // Функция опроса
    function pollStatus() {
        // Если достигнуто максимальное количество попыток или установлен флаг остановки
        if (attempts >= maxAttempts || stopPolling) {
            if (attempts >= maxAttempts) {
                // Показываем сообщение о таймауте
                set_loading_error_customers(
                    __('Authentication Timeout'),
                    __('The authentication request has timed out. Please try again.')
                );
                callback(false);
            }
            return;
        }
        
        attempts++;
        
        // Обновляем счетчик попыток в сообщении
        update_loading_message_customers(
            __('Waiting for confirmation on your phone'),
            __('Please check your phone and confirm the authentication request') + 
            ' (' + attempts + '/' + maxAttempts + ')'
        );
        
        // Проверяем статус авторизации
        frappe.call({
            method: 'invoice_az.auth.poll_auth_status',
            args: {
                'asan_login_name': asan_login_name,
                'bearer_token': bearer_token
            },
            callback: function(r) {
                if (r.message && r.message.success) {
                    if (r.message.authenticated) {
                        // Авторизация успешна
                        stopPolling = true;
                        set_loading_success_customers(
                            __('Authentication Successful'),
                            __('You are now authenticated with Asan Imza'),
                            function() {
                                callback(true);
                            }
                        );
                    } else {
                        // Продолжаем опрос
                        setTimeout(pollStatus, 6000);
                    }
                } else {
                    // Если ошибка, останавливаем опрос и показываем сообщение
                    stopPolling = true;
                    set_loading_error_customers(
                        __('Authentication Error'),
                        r.message ? r.message.message : __('An unknown error occurred')
                    );
                    callback(false);
                }
            },
            error: function(err) {
                // В случае ошибки продолжаем опрос
                console.error('Error during status check:', err);
                setTimeout(pollStatus, 6000);
            }
        });
    }
    
    // Начинаем опрос
    pollStatus();
}

// Функция для завершения аутентификации - получения сертификатов и выбора налогоплательщика
function complete_authentication_customers(asan_login_name, callback) {
    show_loading_dialog_customers(
        __('Completing Authentication'),
        __('Getting certificates...'),
        __('Please wait')
    );
    
    // Получаем сертификаты
    frappe.call({
        method: 'invoice_az.auth.get_auth_certificates',
        args: {
            'asan_login_name': asan_login_name
        },
        callback: function(cert_r) {
            if (cert_r.message && cert_r.message.success) {
                update_loading_message_customers(
                    __('Certificates retrieved'),
                    __('Selecting certificate and taxpayer')
                );
                
                // Получаем текущий документ для проверки выбранного сертификата
                frappe.call({
                    method: 'frappe.client.get',
                    args: {
                        doctype: 'Asan Login',
                        name: asan_login_name
                    },
                    callback: function(r) {
                        if (r.message && r.message.selected_certificate_json) {
                            try {
                                const cert_data = JSON.parse(r.message.selected_certificate_json);
                                const cert_name = r.message.selected_certificate;
                                
                                update_loading_message_customers(
                                    __('Selecting certificate'),
                                    cert_name
                                );
                                
                                // Выбираем сертификат
                                frappe.call({
                                    method: 'invoice_az.auth.select_certificate',
                                    args: {
                                        'asan_login_name': asan_login_name,
                                        'certificate_data': cert_data,
                                        'certificate_name': cert_name
                                    },
                                    callback: function(select_r) {
                                        if (select_r.message && select_r.message.success) {
                                            update_loading_message_customers(
                                                __('Selecting taxpayer'),
                                                __('Using certificate: ') + cert_name
                                            );
                                            
                                            // Выбираем налогоплательщика
                                            frappe.call({
                                                method: 'invoice_az.auth.select_taxpayer',
                                                args: {
                                                    'asan_login_name': asan_login_name
                                                },
                                                callback: function(tax_r) {
                                                    if (tax_r.message && tax_r.message.success) {
                                                        set_loading_success_customers(
                                                            __('Authentication Complete'),
                                                            __('You can now access E-Taxes services'),
                                                            callback,
                                                            2000 // Автоматически закроется через 2 секунды
                                                        );
                                                    } else {
                                                        hide_loading_dialog_customers();
                                                        show_certificate_selector_customers(cert_r.message.certificates, asan_login_name, callback);
                                                    }
                                                }
                                            });
                                        } else {
                                            hide_loading_dialog_customers();
                                            show_certificate_selector_customers(cert_r.message.certificates, asan_login_name, callback);
                                        }
                                    }
                                });
                            } catch (e) {
                                console.error('Error parsing certificate:', e);
                                hide_loading_dialog_customers();
                                show_certificate_selector_customers(cert_r.message.certificates, asan_login_name, callback);
                            }
                        } else {
                            hide_loading_dialog_customers();
                            show_certificate_selector_customers(cert_r.message.certificates, asan_login_name, callback);
                        }
                    }
                });
            } else {
                set_loading_error_customers(
                    __('Error'),
                    cert_r.message ? cert_r.message.message : __('Failed to get certificates')
                );
            }
        }
    });
}

// Функция для отображения селектора сертификатов
function show_certificate_selector_customers(certificates, asan_login_name, callback) {
    if (!certificates || !certificates.length) {
        frappe.msgprint(__('No certificates available'));
        return;
    }
    
    // Создаем таблицу сертификатов
    var cert_html = '<div style="max-height: 400px; overflow-y: auto;"><table class="table table-bordered">';
    cert_html += '<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) {
        var name = '';
        var 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 || '';
        }
        
        cert_html += '<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-customers" data-index="' + index + '">Select</button></td>' +
            '</tr>';
    });
    
    cert_html += '</tbody></table></div>';
    
    var dialog = new frappe.ui.Dialog({
        title: __('Select Certificate'),
        fields: [{
            fieldtype: 'HTML',
            fieldname: 'certificates',
            options: cert_html
        }]
    });
    
    dialog.show();
    
    // Обработчик нажатия на кнопку выбора сертификата
    dialog.$wrapper.find('.select-cert-customers').on('click', function() {
        var index = $(this).data('index');
        var 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();
        
        // Показываем прогресс
        show_loading_dialog_customers(
            __('Selecting Certificate'),
            __('Processing your selection...'),
            certName
        );
        
        // Отправляем запрос на выбор сертификата
        frappe.call({
            method: 'invoice_az.auth.select_certificate',
            args: {
                'asan_login_name': asan_login_name,
                'certificate_data': cert,
                'certificate_name': certName
            },
            callback: function(r) {
                if (r.message && r.message.success) {
                    update_loading_message_customers(
                        __('Certificate selected'),
                        __('Now selecting taxpayer information')
                    );
                    
                    // Выбираем налогоплательщика
                    frappe.call({
                        method: 'invoice_az.auth.select_taxpayer',
                        args: {
                            'asan_login_name': asan_login_name
                        },
                        callback: function(r) {
                            if (r.message && r.message.success) {
                                set_loading_success_customers(
                                    __('Authentication Complete'),
                                    __('You can now access E-Taxes services'),
                                    callback,
                                    2000 // Автоматически закроется через 2 секунды
                                );
                            } else {
                                set_loading_error_customers(
                                    __('Error'),
                                    r.message ? r.message.message : __('Failed to select taxpayer')
                                );
                            }
                        }
                    });
                } else {
                    set_loading_error_customers(
                        __('Error'),
                        r.message ? r.message.message : __('Failed to select certificate')
                    );
                }
            }
        });
    });
}

function show_invoice_filter_dialog_customers() {
    const minDate = moment("2020-01-01", "YYYY-MM-DD");
    const prevYear = moment().subtract(1, 'year').year();
    const startDate = prevYear + "-01-01";
    const endDate = moment().format('YYYY-MM-DD');
    
    var d = new frappe.ui.Dialog({
        title: __('Customer Filters'),
        fields: [
            {
                fieldname: 'date_range_section',
                fieldtype: 'Section Break',
                label: __('Date Range')
            },
            {
                fieldname: 'creationDateFrom',
                fieldtype: 'Date',
                label: __('From Date'),
                default: startDate
            },
            {
                fieldname: 'creationDateTo',
                fieldtype: 'Date',
                label: __('To Date'),
                default: endDate
            }
        ],
        primary_action_label: __('Load Customers'),
        primary_action: function() {
            var values = d.get_values();
            
            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;
            }
            
            d.hide();
            
            let fromDate = values.creationDateFrom ? moment(values.creationDateFrom).format('DD-MM-YYYY 00:00') : moment(startDate).format('DD-MM-YYYY 00:00');
            let toDate = values.creationDateTo ? moment(values.creationDateTo).format('DD-MM-YYYY 23:59') : moment(endDate).format('DD-MM-YYYY 23:59');
            
            // Запускаем загрузку с прогресс-баром
            load_customers_with_pagination(fromDate, toDate, 0, []);
        }
    });
    
    d.show();
}

// ИСПРАВЛЕННАЯ функция загрузки customers с пагинацией
function load_customers_with_pagination(fromDate, toDate, offset = 0, accumulated_data = null) {
    const maxCount = 200;
    
    // Инициализируем accumulated_data если это первый вызов
    if (!accumulated_data) {
        accumulated_data = {
            customers_created: 0,
            suppliers_created: 0,
            skipped_count: 0,
            failed_count: 0,
            total_invoices: 0
        };
        
        frappe.show_alert({
            message: __('Fetching customers from E-Taxes...'),
            indicator: 'blue'
        }, 3);
    }
    
    frappe.call({
        method: 'invoice_az.api.load_parties_from_invoices',
        args: {
            'date_from': fromDate,
            'date_to': toDate,
            'max_count': maxCount,
            'offset': offset,
            'invoice_type': 'purchase'
        },
        callback: function(r) {
            if (r.message && r.message.success) {
                // Добавляем полученные инвойсы к уже накопленным
                let currentInvoices = r.message.invoices || [];
                let allInvoices = accumulated_data.invoices ? accumulated_data.invoices.concat(currentInvoices) : currentInvoices;
                let hasMore = r.message.hasMore || false;
                let token = r.message.token;
                
                // Сохраняем накопленные инвойсы
                accumulated_data.invoices = allInvoices;
                accumulated_data.token = token;
                
                if (hasMore && currentInvoices.length > 0) {
                    // Если есть еще инвойсы, загружаем следующую партию
                    let newOffset = offset + currentInvoices.length;
                    load_customers_with_pagination(fromDate, toDate, newOffset, accumulated_data);
                } else {
                    // Если больше нет инвойсов, переходим к обработке
                    if (allInvoices.length > 0) {
                        frappe.show_alert({
                            message: __('Found {0} invoices. Processing customers...', [allInvoices.length]),
                            indicator: 'green'
                        }, 3);
                        
                        // Теперь обрабатываем инвойсы батчами с прогресс баром
                        setTimeout(() => {
                            process_invoices_for_customers_with_progress(allInvoices, token);
                        }, 1000);
                    } else {
                        frappe.msgprint({
                            title: __('Information'),
                            indicator: 'blue',
                            message: __('No 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() {
                        check_and_process_token_customers(function() {
                            show_invoice_filter_dialog_customers();
                        });
                    },
                    function() {
                        frappe.show_alert({
                            message: __('Authentication cancelled'),
                            indicator: 'red'
                        }, 5);
                    }
                );
            } else {
                frappe.msgprint({
                    title: __('Error'),
                    indicator: 'red',
                    message: r.message ? r.message.message : __('An error occurred while loading customers')
                });
            }
        },
        error: function(xhr, status, error) {
            // ИСПРАВЛЕНО: Очищаем состояние при ошибке
            cleanup_customers_loading_state();
            frappe.msgprint({
                title: __('Network Error'),
                indicator: 'red',
                message: __('Failed to connect to server: ') + (error || 'Unknown error')
            });
        }
    });
}

// ИСПРАВЛЕННАЯ функция обработки инвойсов для customers с прогресс баром
function process_invoices_for_customers_with_progress(invoices, token, processedCount = 0, currentIndex = 0, batchSize = 50) {
    // Инициализация при первом вызове
    if (processedCount === 0 && currentIndex === 0) {
        window.cancelCustomersLoading = false;
        window.totalCustomersToProcess = invoices.length;
        
        // Показываем прогресс бар
        frappe.show_progress(__('Processing Customers'), 0, invoices.length, 
            __('Extracting customers from invoices...'), null, true);
        
        // Добавляем обработчик отмены
        $(document).off('progress-cancel.loading_customers');
        $(document).on('progress-cancel.loading_customers', function() {
            window.cancelCustomersLoading = true;
            frappe.show_alert({
                message: __('Cancelling customer extraction...'),
                indicator: 'orange'
            }, 3);
        });
    }
    
    // Проверка отмены
    if (window.cancelCustomersLoading) {
        cleanup_customers_loading_state();
        frappe.show_alert({
            message: __('Customer extraction cancelled'),
            indicator: 'red'
        }, 3);
        return;
    }
    
    // Если все инвойсы обработаны
    if (currentIndex >= invoices.length) {
        cleanup_customers_loading_state();
        
        // Показываем итоговый результат
        frappe.msgprint({
            title: __('Customers Loaded Successfully'),
            indicator: 'green',
            message: __('Created {0} customers and {1} suppliers. Total invoices processed: {2}', 
                [processedCount, 0, invoices.length]) // suppliers считается на сервере
        });
        
        // ИСПРАВЛЕНО: Обновляем список с задержкой для уверенности в очистке состояния
        setTimeout(function() {
            if (cur_list) {
                cur_list.refresh();
            }
        }, 500);
        return;
    }
    
    // Определяем размер текущего батча
    const remainingInvoices = invoices.length - currentIndex;
    const currentBatchSize = Math.min(batchSize, remainingInvoices);
    const currentBatch = invoices.slice(currentIndex, currentIndex + currentBatchSize);
    
    // Обновляем прогресс
    frappe.show_progress(__('Processing Customers'), currentIndex, invoices.length, 
        __('Processing batch {0}-{1} of {2} invoices', [currentIndex + 1, currentIndex + currentBatchSize, invoices.length]));
    
    // Обрабатываем текущий батч
    frappe.call({
        method: 'invoice_az.api.process_invoice_parties_from_list',
        args: {
            'invoice_list_data': currentBatch,
            'token': token
        },
        callback: function(r) {
            if (r.message && r.message.success) {
                // Обновляем накопленные данные
                processedCount += (r.message.customers_created || 0) + (r.message.suppliers_created || 0);
                
                // Переходим к следующему батчу с небольшой задержкой
                setTimeout(function() {
                    if (!window.cancelCustomersLoading) {  // Дополнительная проверка
                        process_invoices_for_customers_with_progress(invoices, token, processedCount, 
                            currentIndex + currentBatchSize, batchSize);
                    }
                }, 100); // 100ms задержка между батчами
                
            } else if (r.message && r.message.error === 'unauthorized') {
                cleanup_customers_loading_state();
                
                frappe.confirm(
                    __('Your E-Taxes session has expired. Would you like to authenticate now?'),
                    function() {
                        check_and_process_token_customers(function() {
                            // Получаем новый токен и продолжаем с текущего индекса
                            frappe.call({
                                method: 'invoice_az.auth.get_default_asan_login',
                                callback: function(login_r) {
                                    if (login_r.message && login_r.message.found && login_r.message.main_token) {
                                        process_invoices_for_customers_with_progress(invoices, login_r.message.main_token, 
                                            processedCount, currentIndex, batchSize);
                                    } else {
                                        frappe.msgprint(__('Failed to get authentication token'));
                                    }
                                }
                            });
                        });
                    },
                    function() {
                        frappe.show_alert({
                            message: __('Authentication cancelled'),
                            indicator: 'red'
                        }, 5);
                    }
                );
            } else {
                // Ошибка обработки батча - продолжаем со следующим
                setTimeout(function() {
                    if (!window.cancelCustomersLoading) {  // Дополнительная проверка
                        process_invoices_for_customers_with_progress(invoices, token, processedCount, 
                            currentIndex + currentBatchSize, batchSize);
                    }
                }, 200); // Увеличенная задержка при ошибках
            }
        },
        error: function(xhr, status, error) {
            // Сетевая ошибка - продолжаем со следующим батчом
            setTimeout(function() {
                if (!window.cancelCustomersLoading) {  // Дополнительная проверка
                    process_invoices_for_customers_with_progress(invoices, token, processedCount, 
                        currentIndex + currentBatchSize, batchSize);
                }
            }, 500); // Еще большая задержка при сетевых ошибках
        }
    });
}