frappe.listview_settings['E-Taxes Unit'] = {
    add_fields: ['status', 'mapped_unit'],
    
    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 units from E-Taxes
        listview.page.add_menu_item(__('Load from E-Taxes'), function() {
            // Сначала проверяем актуальность токена без анимации загрузки
            check_and_process_token_units(function() {
                show_units_filter_dialog();
            });
        });
    }
};

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

// Функция для отображения диалога загрузки с анимацией для units
function show_loading_dialog_units(title, message, submessage) {
    // Если диалог уже открыт, обновляем только сообщение
    if (loading_dialog_units) {
        $('#loading_title_units').text(title);
        $('#loading_message_units').text(message);
        if (submessage) {
            $('#loading_submessage_units').text(submessage).show();
        } else {
            $('#loading_submessage_units').hide();
        }
        return;
    }
    
    // Создаем диалог с анимацией загрузки
    loading_dialog_units = 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_units">${title}</h4>
                            <p id="loading_message_units">${message}</p>
                            <p id="loading_submessage_units" style="${submessage ? '' : 'display:none'}">${submessage || ''}</p>
                            <div id="verification_code_container_units" 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_units">----</span>
                                </div>
                                <p style="margin-top: 5px; font-size: 12px; color: #666;">Verification Code</p>
                            </div>
                        </div>
                    </div>
                `
            }
        ]
    });
    
    loading_dialog_units.show();
    loading_dialog_units.$wrapper.find('.modal-dialog').css('max-width', '450px');
}

// Функция для отображения кода верификации для units
function show_verification_code_units(code) {
    if (loading_dialog_units && code) {
        $('#verification_code_units').text(code);
        $('#verification_code_container_units').show();
    }
}

// Функция для скрытия диалога загрузки для units
function hide_loading_dialog_units() {
    if (loading_dialog_units) {
        loading_dialog_units.hide();
        loading_dialog_units = null;
    }
}

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

// Функция для изменения статуса загрузки на успешный с автоматическим закрытием для units
function set_loading_success_units(message, submessage, callback, delay = 1500) {
    if (loading_dialog_units) {
        // Меняем анимацию на галочку
        loading_dialog_units.$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_units').text(message);
        if (submessage !== undefined) {
            $('#loading_submessage_units').text(submessage);
            $('#loading_submessage_units').toggle(!!submessage);
        }
        
        // Скрываем код верификации, если он был отображен
        $('#verification_code_container_units').hide();
        
        // Удаляем все существующие кнопки действий
        loading_dialog_units.set_primary_action(null);
        loading_dialog_units.set_secondary_action(null);
        
        // Автоматически закрываем через указанную задержку
        setTimeout(function() {
            if (loading_dialog_units) {
                loading_dialog_units.hide();
                loading_dialog_units = null;
            }
            if (callback) callback();
        }, delay);
    } else if (callback) {
        // Если диалог не открыт, но есть callback, вызываем его
        callback();
    }
}

// Функция для изменения статуса загрузки на ошибку для units
function set_loading_error_units(message, submessage, show_close_button = true) {
    if (loading_dialog_units) {
        // Меняем анимацию на крестик
        loading_dialog_units.$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_units').text(message);
        if (submessage !== undefined) {
            $('#loading_submessage_units').text(submessage);
            $('#loading_submessage_units').toggle(!!submessage);
        }
        
        // Скрываем код верификации, если он был отображен
        $('#verification_code_container_units').hide();
        
        // При необходимости добавляем кнопку закрытия
        if (show_close_button) {
            loading_dialog_units.set_primary_action(__('Close'), function() {
                hide_loading_dialog_units();
            });
        }
    }
}

// Функция для проверки токена и обработки аутентификации при необходимости для units
function check_and_process_token_units(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_units(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')
            });
        }
    });
}

// Функция для запуска полного процесса аутентификации для units
function start_authentication_process_units(callback) {
    show_loading_dialog_units(
        __('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_units(
                    __('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) {
                                show_verification_code_units(r.message.verification_code);
                            }
                            
                            // Изменяем сообщение для ожидания подтверждения
                            update_loading_message_units(
                                __('Waiting for confirmation on your phone'),
                                __('Please check your phone and confirm the authentication request')
                            );
                            
                            // Опрашиваем статус аутентификации
                            poll_authentication_status_units(asan_login_name, bearer_token, function(success) {
                                if (success) {
                                    // Если аутентификация успешна, продолжаем процесс
                                    complete_authentication_units(asan_login_name, callback);
                                } else {
                                    // Если аутентификация не удалась, показываем сообщение об ошибке
                                    set_loading_error_units(
                                        __('Authentication Failed'),
                                        __('Could not authenticate with Asan Imza')
                                    );
                                }
                            });
                        } else {
                            // Если запрос не удался, показываем сообщение об ошибке
                            set_loading_error_units(
                                __('Authentication Error'),
                                r.message ? r.message.message : __('Authentication request failed')
                            );
                        }
                    }
                });
            } else {
                // Если настройки не найдены, показываем сообщение об ошибке
                set_loading_error_units(
                    __('No Asan Login Settings'),
                    __('Please configure Asan Login settings first')
                );
            }
        }
    });
}

// Функция для опроса статуса аутентификации для units
function poll_authentication_status_units(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_units(
                    __('Authentication Timeout'),
                    __('The authentication request has timed out. Please try again.')
                );
                callback(false);
            }
            return;
        }
        
        attempts++;
        
        // Проверяем статус авторизации
        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_units(
                            __('Authentication Successful'),
                            __('You are now authenticated with Asan Imza'),
                            function() {
                                callback(true);
                            }
                        );
                    } else {
                        // Обновляем счетчик попыток в сообщении
                        update_loading_message_units(
                            __('Waiting for confirmation on your phone'),
                            __('Please check your phone and confirm the authentication request') + 
                            ' (' + attempts + '/' + maxAttempts + ')'
                        );
                        // Продолжаем опрос
                        setTimeout(pollStatus, 6000);
                    }
                } else {
                    // Если ошибка, останавливаем опрос и показываем сообщение
                    stopPolling = true;
                    set_loading_error_units(
                        __('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();
}

// Функция для завершения аутентификации - получения сертификатов и выбора налогоплательщика для units
function complete_authentication_units(asan_login_name, callback) {
    show_loading_dialog_units(
        __('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_units(
                    __('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_units(
                                    __('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_units(
                                                __('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_units(
                                                            __('Authentication Complete'),
                                                            __('You can now access E-Taxes services'),
                                                            callback,
                                                            2000 // Автоматически закроется через 2 секунды
                                                        );
                                                    } else {
                                                        hide_loading_dialog_units();
                                                        show_certificate_selector_units(cert_r.message.certificates, asan_login_name, callback);
                                                    }
                                                }
                                            });
                                        } else {
                                            hide_loading_dialog_units();
                                            show_certificate_selector_units(cert_r.message.certificates, asan_login_name, callback);
                                        }
                                    }
                                });
                            } catch (e) {
                                console.error('Error parsing certificate:', e);
                                hide_loading_dialog_units();
                                show_certificate_selector_units(cert_r.message.certificates, asan_login_name, callback);
                            }
                        } else {
                            hide_loading_dialog_units();
                            show_certificate_selector_units(cert_r.message.certificates, asan_login_name, callback);
                        }
                    }
                });
            } else {
                set_loading_error_units(
                    __('Error'),
                    cert_r.message ? cert_r.message.message : __('Failed to get certificates')
                );
            }
        }
    });
}

// Функция для отображения селектора сертификатов для units
function show_certificate_selector_units(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-units" 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-units').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_units(
            __('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_units(
                        __('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_units(
                                    __('Authentication Complete'),
                                    __('You can now access E-Taxes services'),
                                    callback,
                                    2000 // Автоматически закроется через 2 секунды
                                );
                            } else {
                                set_loading_error_units(
                                    __('Error'),
                                    r.message ? r.message.message : __('Failed to select taxpayer')
                                );
                            }
                        }
                    });
                } else {
                    set_loading_error_units(
                        __('Error'),
                        r.message ? r.message.message : __('Failed to select certificate')
                    );
                }
            }
        });
    });
}

function show_units_filter_dialog() {
    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: __('Unit 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 Units'),
        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_units_with_pagination(fromDate, toDate, 0, []);
        }
    });
    
    d.show();
}

function load_units_with_pagination(fromDate, toDate, offset = 0, accumulated_invoices = []) {
    const maxCount = 200;
    
    // Если это первый запрос, показываем начальное сообщение
    if (offset === 0 && accumulated_invoices.length === 0) {
        frappe.show_alert({
            message: __('Fetching units from both purchases and sales invoices...'),
            indicator: 'blue'
        }, 3);
    }
    
    frappe.call({
        method: 'invoice_az.api.load_units_from_invoices',
        args: {
            'date_from': fromDate,
            'date_to': toDate,
            'max_count': maxCount,
            'offset': offset
        },
        callback: function(r) {
            if (r.message && r.message.success) {
                // Добавляем полученные инвойсы к уже накопленным
                let currentInvoices = r.message.invoices || [];
                let allInvoices = accumulated_invoices.concat(currentInvoices);
                let hasMore = r.message.hasMore || false;
                let token = r.message.token;
                
                // Показываем информацию о загруженных данных
                if (r.message.inbox_count !== undefined && r.message.outbox_count !== undefined) {
                    const totalInbox = accumulated_invoices.filter(inv => inv._source === 'inbox').length + (r.message.inbox_count || 0);
                    const totalOutbox = accumulated_invoices.filter(inv => inv._source === 'outbox').length + (r.message.outbox_count || 0);
                    
                    if (offset > 0) {
                        frappe.show_alert({
                            message: __('Loaded batch {0}: {1} purchases, {2} sales (total: {3})', 
                                [(offset / maxCount) + 1, totalInbox, totalOutbox, allInvoices.length]),
                            indicator: 'blue'
                        }, 2);
                    }
                }
                
                if (hasMore && currentInvoices.length > 0) {
                    // Если есть еще инвойсы, загружаем следующую партию
                    let newOffset = offset + currentInvoices.length;
                    load_units_with_pagination(fromDate, toDate, newOffset, allInvoices);
                } else {
                    // Если больше нет инвойсов, переходим к обработке
                    if (allInvoices.length > 0) {
                        // Показываем итоговую статистику
                        const inboxCount = allInvoices.filter(inv => inv._source === 'inbox').length;
                        const outboxCount = allInvoices.filter(inv => inv._source === 'outbox').length;
                        
                        frappe.show_alert({
                            message: __('Found {0} invoices: {1} purchases, {2} sales. Processing units...', 
                                [allInvoices.length, inboxCount, outboxCount]),
                            indicator: 'green'
                        }, 3);
                        
                        // Начинаем обработку инвойсов с прогресс-баром
                        setTimeout(() => {
                            process_invoices_for_units(allInvoices, token, {
                                created_count: 0,
                                skipped_count: 0,
                                failed_count: 0,
                                total_invoices: allInvoices.length,
                                inbox_count: inboxCount,
                                outbox_count: outboxCount
                            });
                        }, 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_units(function() {
                            show_units_filter_dialog();
                        });
                    },
                    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 invoices')
                });
            }
        },
        error: function(xhr, status, error) {
            frappe.msgprint({
                title: __('Network Error'),
                indicator: 'red',
                message: __('Failed to connect to server: ') + (error || 'Unknown error')
            });
        }
    });
}

function process_invoices_for_units(invoices, token, accumulated_data, current_index = 0) {
    // Инициализация при первом вызове
    if (current_index === 0) {
        window.cancelUnitsLoading = false;
        window.totalUnitsToProcess = invoices.length;
        
        // Отладочная информация о источниках инвойсов
        let inboxCount = invoices.filter(inv => inv._source === 'inbox').length;
        let outboxCount = invoices.filter(inv => inv._source === 'outbox').length;
        let unknownCount = invoices.filter(inv => !inv._source || (inv._source !== 'inbox' && inv._source !== 'outbox')).length;
        
        // Показываем прогресс бар с дополнительной информацией
        const message = accumulated_data.inbox_count && accumulated_data.outbox_count ? 
            __('Processing {0} invoices ({1} purchases, {2} sales)...', 
                [invoices.length, accumulated_data.inbox_count, accumulated_data.outbox_count]) :
            __('Processing {0} invoices...', [invoices.length]);
            
        frappe.show_progress(__('Extracting Units'), 0, invoices.length, message, null, true);
        
        // Добавляем обработчик отмены
        $(document).off('progress-cancel.loading_units');
        $(document).on('progress-cancel.loading_units', function() {
            window.cancelUnitsLoading = true;
            frappe.show_alert({
                message: __('Cancelling unit extraction...'),
                indicator: 'orange'
            }, 3);
        });
    }
    
    // Проверка отмены
    if (window.cancelUnitsLoading) {
        frappe.hide_progress();
        $(document).off('progress-cancel.loading_units');
        frappe.show_alert({
            message: __('Unit extraction cancelled'),
            indicator: 'red'
        }, 3);
        return;
    }
    
    // Если все инвойсы обработаны
    if (current_index >= invoices.length) {
        frappe.hide_progress();
        $(document).off('progress-cancel.loading_units');
        
        // Показываем итоговый результат с разбивкой по источникам
        const inboxText = accumulated_data.inbox_count ? 
            __(' from {0} purchase invoices', [accumulated_data.inbox_count]) : '';
        const outboxText = accumulated_data.outbox_count ? 
            __(' and {0} sales invoices', [accumulated_data.outbox_count]) : '';
        
        frappe.msgprint({
            title: __('Units Loaded Successfully'),
            indicator: 'green',
            message: __('Created {0} unique units. Skipped {1} duplicates. Total invoices processed: {2}{3}{4}', 
                [accumulated_data.created_count, accumulated_data.skipped_count, 
                 accumulated_data.total_invoices, inboxText, outboxText])
        });
        
        // Refresh list
        if (cur_list) {
            cur_list.refresh();
        }
        return;
    }
    
    let invoice = invoices[current_index];
    let invoice_id = invoice.id;
    let serial_number = invoice.serialNumber || invoice_id;
    let source = invoice._source;
    
    // Улучшенная логика определения источника
    let sourceLabel;
    if (source === 'inbox') {
        sourceLabel = __('Purchase');
    } else if (source === 'outbox') {
        sourceLabel = __('Sales');
    } else {
        // Если _source не установлен или имеет неожиданное значение, считаем как Purchase
        sourceLabel = __('Purchase');
        // Добавляем отладочную информацию в консоль
        console.log('Warning: Invoice', serial_number, 'has unexpected _source:', source);
    }
    
    // Показываем прогресс
    frappe.show_progress(
        __('Extracting Units'), 
        current_index, 
        invoices.length, 
        __('Processing {0} invoice {1} of {2}: {3}', [sourceLabel, current_index + 1, invoices.length, serial_number])
    );
    
    // Обрабатываем текущий инвойс
    frappe.call({
        method: 'invoice_az.api.process_single_invoice_for_units',
        args: {
            'token': token,
            'invoice_id': invoice_id
        },
        callback: function(r) {
            if (r.message && r.message.success) {
                // Обновляем накопленные данные
                accumulated_data.created_count += r.message.created_count || 0;
                accumulated_data.skipped_count += r.message.skipped_count || 0;
                accumulated_data.failed_count += r.message.failed_count || 0;
                
                // Переходим к следующему инвойсу с небольшой задержкой
                setTimeout(function() {
                    process_invoices_for_units(invoices, token, accumulated_data, current_index + 1);
                }, 50); // 50ms задержка между инвойсами для предотвращения перегрузки
                
            } else if (r.message && r.message.error === 'unauthorized') {
                frappe.hide_progress();
                $(document).off('progress-cancel.loading_units');
                
                frappe.confirm(
                    __('Your E-Taxes session has expired. Would you like to authenticate now?'),
                    function() {
                        check_and_process_token_units(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_units(invoices, login_r.message.main_token, accumulated_data, current_index);
                                    } else {
                                        frappe.msgprint(__('Failed to get authentication token'));
                                    }
                                }
                            });
                        });
                    },
                    function() {
                        frappe.show_alert({
                            message: __('Authentication cancelled'),
                            indicator: 'red'
                        }, 5);
                    }
                );
            } else {
                // Ошибка обработки инвойса - пропускаем и переходим к следующему
                accumulated_data.failed_count += 1;
                
                setTimeout(function() {
                    process_invoices_for_units(invoices, token, accumulated_data, current_index + 1);
                }, 50);
            }
        },
        error: function(xhr, status, error) {
            // Сетевая ошибка - пропускаем и переходим к следующему
            accumulated_data.failed_count += 1;
            
            setTimeout(function() {
                process_invoices_for_units(invoices, token, accumulated_data, current_index + 1);
            }, 100); // Увеличенная задержка при ошибках
        }
    });
}