$j.fn.socket_events = function(options)
{ var settings = $j.extend(
           {  'debug' : 0,
              'group' : 0,
              'ws_check_domain': 0,
              'ws_protocol': 'wss',
              'ws_address_port': 'localhost'
           }, options);

var ws;
var page_url = document.location.href;
var is_monitor_page = page_url.includes("/cab/monitor/") || page_url.includes("/cab/monitor/pl/");

// WebSocket работает только на страницах мониторинга
if (!is_monitor_page) {
    console.log('WebSocket отключен: это не страница мониторинга (URL: ' + page_url + ')');
    return; // Выходим, не инициализируем WebSocket
}

console.log('WebSocket включен для страницы мониторинга (URL: ' + page_url + ')');

var tabId = 'ws_tab_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
var isActiveTab = false;
var wsLockKey = 'ws_active_tab_' + settings.group;
var wsLockTimestampKey = 'ws_active_tab_timestamp_' + settings.group;
var wsLockIsMonitorKey = 'ws_active_tab_is_monitor_' + settings.group;
var broadcastChannel = null;
var heartbeatInterval = null;
var lockCheckInterval = null;

// Инициализация BroadcastChannel для общения между вкладками
if (typeof BroadcastChannel !== 'undefined') {
    broadcastChannel = new BroadcastChannel('ws_tab_coordination_' + settings.group);
    broadcastChannel.onmessage = function(event) {
        if (event.data.type === 'tab_activated' && event.data.tabId !== tabId) {
            var otherIsMonitor = event.data.isMonitor === true;

            // Если другая вкладка - мониторинг, а мы нет, освобождаем слот
            // Если мы мониторинг, а другая нет - не освобождаем (у нас приоритет)
            if (otherIsMonitor && !is_monitor_page) {
                console.log('Вкладка мониторинга стала активной: ' + event.data.tabId + '. Освобождаем слот.');
                releaseConnection();
                // Если мы были неактивны, запускаем проверку слота
                if (!isActiveTab) {
                    startLockCheck();
                }
            } else if (otherIsMonitor && is_monitor_page) {
                // Обе вкладки мониторинг - освобождаем, если мы не активны
                if (isActiveTab) {
                    // Проверяем, не мы ли стали активными
                    var currentActive = localStorage.getItem(wsLockKey);
                    if (currentActive !== tabId) {
                        console.log('Другая вкладка мониторинга стала активной: ' + event.data.tabId);
                        releaseConnection();
                    }
                } else {
                    // Мы неактивны, запускаем проверку слота
                    startLockCheck();
                }
            } else if (!otherIsMonitor && is_monitor_page) {
                // Мы мониторинг, другая нет - не освобождаем, пытаемся захватить
                console.log('Вкладка мониторинга получает приоритет. Пытаемся захватить слот.');
                if (!isActiveTab && tryBecomeActive()) {
                    connect_ws();
                }
            } else {
                // Обе не мониторинг - обычное поведение
                console.log('Другая вкладка стала активной: ' + event.data.tabId);
                releaseConnection();
                // Если мы были неактивны, запускаем проверку слота
                if (!isActiveTab) {
                    startLockCheck();
                }
            }
        }
    };
}

// Проверка, может ли эта вкладка быть активной
function tryBecomeActive() {
    var activeTabId = localStorage.getItem(wsLockKey);
    var activeTimestamp = parseInt(localStorage.getItem(wsLockTimestampKey) || '0');
    var activeIsMonitor = localStorage.getItem(wsLockIsMonitorKey) === 'true';
    var now = Date.now();

    // Если нет активной вкладки или прошло больше 5 секунд с последнего heartbeat
    if (!activeTabId || (now - activeTimestamp > 5000)) {
        // Захватываем слот
        localStorage.setItem(wsLockKey, tabId);
        localStorage.setItem(wsLockTimestampKey, now.toString());
        localStorage.setItem(wsLockIsMonitorKey, is_monitor_page ? 'true' : 'false');
        isActiveTab = true;

        // Уведомляем другие вкладки
        if (broadcastChannel) {
            broadcastChannel.postMessage({
                type: 'tab_activated',
                tabId: tabId,
                isMonitor: is_monitor_page
            });
        }

        console.log('Эта вкладка стала активной для WebSocket. Tab ID: ' + tabId + ', Мониторинг: ' + is_monitor_page);
        return true;
    } else if (activeTabId === tabId) {
        // Мы уже активны, обновляем timestamp и флаг мониторинга (на случай смены URL)
        localStorage.setItem(wsLockTimestampKey, now.toString());
        localStorage.setItem(wsLockIsMonitorKey, is_monitor_page ? 'true' : 'false');
        isActiveTab = true;
        return true;
    } else {
        // Другая вкладка активна - проверяем приоритет страницы мониторинга
        if (is_monitor_page && !activeIsMonitor) {
            // Текущая вкладка - мониторинг, активная - нет -> вытесняем
            console.log('Вкладка мониторинга получает приоритет. Вытесняем вкладку: ' + activeTabId);

            // Захватываем слот
            localStorage.setItem(wsLockKey, tabId);
            localStorage.setItem(wsLockTimestampKey, now.toString());
            localStorage.setItem(wsLockIsMonitorKey, 'true');
            isActiveTab = true;

            // Уведомляем другие вкладки
            if (broadcastChannel) {
                broadcastChannel.postMessage({
                    type: 'tab_activated',
                    tabId: tabId,
                    isMonitor: true
                });
            }

            console.log('Вкладка мониторинга стала активной. Tab ID: ' + tabId);
            return true;
        } else {
            // Другая вкладка активна, приоритета нет
            console.log('Другая вкладка активна для WebSocket. Активная: ' + activeTabId + ', Мониторинг: ' + activeIsMonitor);
            isActiveTab = false;
            return false;
        }
    }
}

// Освобождение соединения
function releaseConnection() {
    if (isActiveTab) {
        console.log('Освобождение WebSocket соединения');
        isActiveTab = false;
        if (ws && ws.readyState === WebSocket.OPEN) {
            ws.close();
        }
        if (heartbeatInterval) {
            clearInterval(heartbeatInterval);
            heartbeatInterval = null;
        }
        var currentActiveTab = localStorage.getItem(wsLockKey);
        if (currentActiveTab === tabId) {
            localStorage.removeItem(wsLockKey);
            localStorage.removeItem(wsLockTimestampKey);
            localStorage.removeItem(wsLockIsMonitorKey);
        }
        // Запускаем проверку слота для попытки стать активной
        startLockCheck();
    }
}

// Heartbeat для подтверждения активности
function startHeartbeat() {
    if (heartbeatInterval) {
        clearInterval(heartbeatInterval);
    }
    heartbeatInterval = setInterval(function() {
        if (isActiveTab) {
            var now = Date.now();
            localStorage.setItem(wsLockTimestampKey, now.toString());
            // Обновляем флаг мониторинга (на случай смены URL)
            localStorage.setItem(wsLockIsMonitorKey, is_monitor_page ? 'true' : 'false');
        }
    }, 2000); // Обновляем каждые 2 секунды
}

// Периодическая проверка, не освободился ли слот
function startLockCheck() {
    if (lockCheckInterval) {
        clearInterval(lockCheckInterval);
    }
    lockCheckInterval = setInterval(function() {
        if (!isActiveTab) {
            // Пытаемся стать активными, если слот свободен
            if (tryBecomeActive()) {
                connect_ws();
            }
        }
    }, 3000); // Проверяем каждые 3 секунды
}

// При закрытии вкладки
window.addEventListener('beforeunload', function() {
    releaseConnection();
});

// При потере фокуса страницы
document.addEventListener('visibilitychange', function() {
    if (document.hidden) {
        // Страница скрыта - можно отключить WebSocket, но не освобождаем слот
        // (другие вкладки могут получить фокус)
        // Исключение: если страница мониторинга, сохраняем соединение
        if (!is_monitor_page && isActiveTab) {
            // Для не-мониторинга при скрытии можно освободить слот (опционально)
            // Пока оставляем как есть - слот сохраняется
        }
    } else {
        // Страница видима - пытаемся стать активными
        // Если это страница мониторинга, она получает приоритет
        if (!isActiveTab) {
            if (tryBecomeActive()) {
                if (!ws || ws.readyState === WebSocket.CLOSED) {
                    connect_ws();
                }
            }
        } else if (is_monitor_page) {
            // Если мониторинг уже активен, обновляем флаг приоритета
            var activeIsMonitor = localStorage.getItem(wsLockIsMonitorKey) === 'true';
            if (!activeIsMonitor) {
                localStorage.setItem(wsLockIsMonitorKey, 'true');
            }
        }
    }
});

// Первоначальная проверка при загрузке
if (!tryBecomeActive()) {
    console.log('WebSocket не будет подключен в этой вкладке. Другая вкладка уже активна.');
    // Начинаем проверку на освобождение слота
    startLockCheck();
}

    function connect_ws() {
        // Проверяем, можем ли мы подключаться
        if (!tryBecomeActive()) {
            console.log('Невозможно подключить WebSocket: другая вкладка активна');
            return;
        }
        //settings.group='test_ws' ;
        // была проблема с ws_connect, сделал ws_connect2 - заработало
        let connect_url=settings.ws_protocol + '://' + settings.ws_address_port +'/ws_connect2?group_id=' + settings.group ;
        //console.log(settings) ;
        console.log('page cab connect_url:'+connect_url) ;
        ws = new WebSocket(connect_url);

        ws.onopen = function() {
            console.log("Socket connect to group "+settings.group);
            $j('div#panel_WS_status').html('WS').addClass('active') ;
            // Начинаем heartbeat для подтверждения активности
            startHeartbeat();
        };

        ws.onmessage = function (evt) {
            // Проверяем, что мы все еще активная вкладка
            if (!isActiveTab) {
                console.log('Получено сообщение, но вкладка не активна. Игнорируем.');
                return;
            }
            let mess=JSON.parse(evt.data) ;
            //console.log('Получено сообщение: '+mess.type) ;
            notifyUser(mess);

        };

        ws.onclose = function(evt) {
            //console.log(new Date());
            console.log('Socket is closed. Reconnect will be attempted in 1 second.', evt.reason);
            $j('div#panel_WS_status').html('WS').removeClass('active') ;
            // Останавливаем heartbeat
            if (heartbeatInterval) {
                clearInterval(heartbeatInterval);
                heartbeatInterval = null;
            }
            // Переподключаемся только если мы все еще активная вкладка
            if (isActiveTab) {
                setTimeout(function() {
                    if (isActiveTab && tryBecomeActive()) {
                        connect_ws();
                    }
                }, 1000);
            }
        };

        ws.onerror = function(err) {
            console.error('Socket encountered error: ', err.message, 'Closing socket');
            ws.close();
            $j('div#panel_WS_status').html('WS').addClass('error') ;
        };
    }

    // Подключаемся только если эта вкладка стала активной
    if (isActiveTab) {
        connect_ws();
    }

    function notifyUser(obj)
    {
        // Проверяем, что мы активная вкладка
        if (!isActiveTab) {
            console.log('notifyUser: вкладка не активна, игнорируем сообщение');
            return;
        }

        console.log('notifyUser: '+obj.host) ;
        //console.log('obj.host: '+obj.host) ;
        //console.log('location.hostname: '+location.hostname) ;
        if (settings.ws_check_domain && obj.host!==undefined && obj.host!=location.hostname && obj.host!="localhost") return ;

        //console.log('Получена сокет-команда: '+obj.type) ;

       // если сотрудник не авторизован, и получаем команду check_account_login - отправляем ajax-запрос на проверку авторизации
       // если сотрудник авторизован с предыдущими кукисами - ajax пройдет под го авторизаций и будут возвращен успешный ответ на перезагрузку страницы
       if (obj.type==='check_account_login' && member_id===0)
       {
           console.log('exec check_account_login') ;
           console.log('document[hidden]='+document[hidden]) ;

           if (document[hidden])
           { send_ajax_request({cmd:'account/check_account_login'}) ;
             console.log('выполняем сокет-команду проверки авторизации пользователя check_account_login') ;
           }
           else console.log('Вкладка активна, проверку авторизации пользователя не выполняем') ;
       }

       if (obj.account_id!==undefined && obj.account_id!=member_id)
       {
           //console.log('Сообщение предназачено другому сотруднику, member_id='+member_id+', obj.account_id='+obj.account_id) ;
           return ;
       }
       //console.log(obj) ;
       if (obj.to_rol!==undefined && obj.to_rol && member_rol_id!=obj.to_rol) return ;
       if (obj.to_member_id!==undefined && obj.to_member_id>0 && member_id!=obj.to_member_id) return ;

       //console.log(obj) ;
        // сообзещения пока показываем только в окне мониторинга
        // далее разделим сообщения на сообщения для мониторинга и для основнного интерфейса медика
       /*if (obj.notife_text)
       { if (obj.notife=='error')      new jBox('Notice', {content: obj.notife_text,color:'red'});
         else if (obj.notife=='alert') new jBox('Notice', {content: obj.notife_text,color:'yellow'});
         else if (obj.notife=='info')  new jBox('Notice', {content: obj.notife_text,color:'green'});
         else new jBox('Notice', {content: obj.notife_text});
       }*/

      if (!is_monitor_page && obj.type==='alco_alert')
      { //console.log(obj.uid) ;
        ajax_to_modal_window({cmd:'alco_alert',title:'Обнаружен алкоголь',html:obj.html}) ;
      }

      if (!is_monitor_page && obj.type==='close_modal_window')
      { //console.log(obj.id) ;
        if (jBox_window!=undefined) jBox_window.close() ;
      }

        /*if (obj.type==='account_active')
       {  let time_autologout=Number(obj.time_autologout) ;
           // останавливаем таймер активной сессии и начинаем новую сесиию
           //console.log('session_timer_id='+session_timer) ;
           //console.log('time_autologout='+obj.time_autologout) ;
           if (session_timer!=undefined) clearTimeout(session_timer);
           if (time_autologout>0)
           { session_timer=setTimeout(send_logout_cmd,time_autologout);
             //console.log('session_timer_id='+session_timer) ;
             //console.log('time_autologout='+time_autologout) ;
           }

       }*/

      // если приходит сообщение что текущий акк вышел - обновляем страницу
      // сообщение прищет в двух случаях
      // выхода через интерфейс
      // срабатывания таймера session_timer
      if (obj.type==='account_logout')
      {
          document.location.reload() ;
      }

      if (obj.type==='update_content')
      {
          //console.log(obj) ;
          $j.each(obj.content,function(id,content)
          {
              //console.log('content.account_id='+content.account_id+', id='+content.element_id+' , value='+content.value) ;
              console.log(content.mode+' '+content.element_id+' => '+content.value) ;
              if (content.account_id==0 || content.account_id==member_id)
              {
                   // если передан content.session_uid - надо проверить, нет ли у element_id в родителях session_card
                   // если нет - действуем как обычно
                   // если есть - проверяем атритут session_uid этого элемента
                   // если пустой - set el.session_uid=session_uid
                   // если =session_uid - действуем как обычно
                   // если !=session_uid - ничего не делаем
                   /*let allow_update=1 ;
                   if (content.session_uid)
                   { var el_parent=$j('#'+content.element_id).closest('#session_card') ;
                     console.log('$j(el_parent).length()='+$j(el_parent).length()) ;
                     if ($j(el_parent).length())
                     {
                         let cur_session=$j(el_parent).attr('session_uid') ;
                         console.log('cur_session='+cur_session) ;
                         if (cur_session!=="" || cur_session!==content.session_uid) allow_update=0 ;
                         if (cur_session==="")
                         { $j(el_parent).attr('session_uid',content.session_uid);
                           console.log('set session_uid='+content.session_uid) ;
                         }
                     }
                   }

                  console.log('allow_update='+allow_update) ;*/

                  //if (allow_update)
                  {
                      if (content.mode=='update') $j('#'+content.element_id).html(content.value) ;
                      if (content.mode=='prepend')
                      {
                          $j('#'+content.element_id).prepend(content.value) ;
                      }

                      if (content.mode=='append')
                      { $j('#'+content.element_id).append(content.value) ;
                        // auto_scroll - у background process
                        if ($j('#'+content.element_id).hasClass('auto_scroll')) $j('#'+content.element_id)[0].scrollTop = 99999999999;

                        // конец background процесса - надо загрузить лог, если на странице есть соответствующая панель
                        if (content.element_id=='upload_back_process_result' && $j('#panel_'+content.value)!==undefined)
                        {
                            $j('body').oneTime('2s', function()
                            {   console.log(new Date().toLocaleTimeString()+'Получаем содержимое файла '+'/temp/result_page_'+content.value+'.html') ;
                                jQuery.get( '/temp/result_page_'+content.value+'.html',{},
                                    function exec_get_html_report(data, textStatus, jqXHR)
                                                { //console.log('exec_get_html_report') ;
                                                  //console.log('textStatus='+textStatus) ;
                                                  //console.log('data='+data) ;

                                                   if (textStatus=='success' && data!=null)
                                                    {  $j('#panel_result_form').remove();
                                                       $j('#panel_'+content.value).html(data);
                                                       // если у нас не модальное окно - удаляем ограничения по высоте
                                                       $j('div:not(.jBox-container) #panel_'+content.value).css('height','auto');
                                                       $j('div:not(.jBox-container) #panel_'+content.value).css('border','none');
                                                       $j('div:not(.jBox-container) #panel_'+content.value).css('overflow','auto');
                                                       $j('div.jBox-container #panel_'+content.value).css('height','400px');
                                                       // кнопка "закрыть" тут не нужна, она есть в исходном окне, где был запущен фоновый процесс
                                                       //$j('div.jBox-container #panel_log_uplod').after('<button class="cancel button">Закрыть</button>');
                                                    }
                                                }


                                    ,'text'); // показываем в окне лог работы
                            }) ;
                        }
                      }

                      if (content.mode=='reload_page')
                      {
                          console.log('content.url='+content.url) ;
                          console.log('document.location='+document.location) ;
                          //if (content.url==document.location) document.location.reload() ;
                          if (document.location.href.includes(content.url)) document.location.reload() ;
                      }
                  }
              }

          }) ;
      }


       //if (obj.update_page)  location.reload() ;
       //if (obj.update_page)  location.href='/cab/monitor/?event_id='+last_send_mess_id ;


       // обновляем статусы у иконок терминалов
       if($j.isArray(obj.terminal_status) || typeof(obj.terminal_status) == 'object') for(var i in obj.terminal_status)
       {
          $j('#panel_terminal_status div#t_'+i).attr('status',obj.terminal_status[i]) ;
       }

       // вывод сообщений
       if (obj.notife_text)
       { if (obj.notife=='error')      new jBox('Notice', {content: obj.notife_text,color:'red'});
          else if (obj.notife=='alert') new jBox('Notice', {content: obj.notife_text,color:'yellow'});
          else if (obj.notife=='info')  new jBox('Notice', {content: obj.notife_text,color:'green'});
          else                          new jBox('Notice', {content: obj.notife_text});
       }


        if (obj.type=='mo_to_sign' && doctor_id==obj.doctor_id)
         {
       //console.log(obj) ;
       signMoAfterRequest(cert_Thumbprint,obj.mo_id,0,emulate_sign) ;
   }

           if (obj.type=='data_to_sign' && doctor_id==obj.doctor_id)
           {
               signData(cert_Thumbprint,obj.uid2,obj.content,0,emulate_sign,function(result)
               {
                    //console.log('Получен ответ signData: '+JSON.stringify(result));
                    if (result.status=='success')
                    {
                        //new jBox('Notice', {content: 'Успешно подписан '+obj.notife_of_data,color:'green'});
                        send_ajax_request({cmd:'pl/set_packet_sign_status',packet_uid:obj.uid2}) ;
                    }
                    else console.error('Ошибка подписи: ' + (result.message || 'Не удалось подписать'));
               }) ;
           }

           if (obj.type=='data_to_sign_pl' && doctor_id==obj.doctor_id)
           {

               console.log('Получен пакет data_to_sign_pl: uid2=' + obj.uid2 + ', packet_id=' + obj.packet_id + ', очередь: ' + packetsQueue.length);

               // Проверяем, не было ли ошибки подписи ранее
               if (hasSigningError)
               {
                   console.log('Подпись пропущена из-за предыдущей ошибки CryptoPro');
                   new jBox('Notice', {content: 'Подпись отменена из-за предыдущей ошибки CryptoPro', color:'red'});
                   return;
               }

               // Добавляем пакет в очередь
               packetsQueue.push({
                   uid2: obj.uid2,
                   content: obj.content,
                   notife_of_data: obj.notife_of_data,
                   packet_id: obj.packet_id || null
               });

               console.log('Пакет добавлен в очередь. Размер очереди: ' + packetsQueue.length);

               // Запускаем обработку очереди (если еще не запущена)
               processNextPacket();
           }



       if (isFunction(window['ws_events_local']) ) ws_events_local(obj) ;

       if (settings.debug)
       {   obj.mo_tr='...' ;
           show_debug_info('notifyUser',obj) ;
       }

       return true;
    }



} ;

function htmlspecialchars(string){ return $j('<span>').text(string).html() ;}

// isFunction взято со стэка
function isFunction(functionToCheck)
{
    var getType = {};
    return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
}

// функция-обработчик ответа на получение результата фонового процесса
function exec_get_html_report(data, textStatus, jqXHR)
{ //console.log('exec_get_html_report') ;
  //console.log('textStatus='+textStatus) ;
  //console.log('data='+data) ;

   if (textStatus=='success' && data!=null)
    {  $j('#panel_result_form').remove();
       $j('.panel_log_uplod').html(data);
       // если у нас не модальное окно - удаляем ограничения по высоте
       $j('div:not(.jBox-container) .panel_log_uplod').css('height','auto');
       $j('div:not(.jBox-container) .panel_log_uplod').css('border','none');
       $j('div:not(.jBox-container) .panel_log_uplod').css('overflow','auto');
       $j('div.jBox-container .panel_log_uplod').css('height','400px');
       // кнопка "закрыть" тут не нужна, она есть в исходном окне, где был запущен фоновый процесс
       //$j('div.jBox-container #panel_log_uplod').after('<button class="cancel button">Закрыть</button>');
    }
}


// ws_events_local вызывает socket_events
// Флаг для отслеживания ошибок подписи ЭЦП
var hasSigningError = false;
// Флаг для отслеживания процесса подписи (устанавливается сразу перед вызовом signData)
var isSigningInProgress = false;
// Очередь пакетов на подпись
var packetsQueue = [];

// Функция обновления UI карточки пакета после подписи
function updatePacketUI(packet_id)
{
    if (!packet_id) return;

    //console.log('Обновление UI для пакета #' + packet_id);

    var $card = $j('.packet-card[data-packet-id="' + packet_id + '"]');
    if ($card.length) {
        // Меняем статус карточки на "подписан"
        $card.removeClass('ready pending error').addClass('signed');

        // Меняем статус-бейдж
        var $badge = $card.find('.packet-status-badge');
        $badge.removeClass('ready pending error').addClass('signed');
        $badge.html('<i class="fa fa-check-circle"></i> Подписан');

        // Добавляем анимацию успеха
        $card.addClass('signing-success');

        // Скрываем карточку с анимацией через 2 секунды
        setTimeout(function() {
            $card.fadeOut(600, function() {
                $j(this).remove();
            });
        }, 2000);
    }
}

// Функция обновления dashboard (только прогресс)
function updateDashboard()
{
    //console.log('Обновление прогресс-бара');

    var $dashboard = $j('.progress-dashboard');

    // Получаем начальное общее количество (константа)
    var total = parseInt($dashboard.attr('data-total')) || 0;

    // Получаем текущее количество подписанных и увеличиваем на 1
    var signed = parseInt($dashboard.attr('data-signed')) || 0;
    signed++; // Увеличиваем на 1

    // Сохраняем новое значение
    $dashboard.attr('data-signed', signed);

    // Обновляем прогресс
    var progress = total > 0 ? Math.round((signed / total) * 100) : 0;
    $j('.progress-percentage').text(progress + '%');
    $j('.progress-fill').css('width', progress + '%');
    $j('.progress-text').text(signed + ' из ' + total + ' пакетов подписано');

    //console.log('Прогресс-бар обновлен: signed=' + signed + '/' + total + ', progress=' + progress + '%');

    // Показываем кнопку возврата, если все пакеты подписаны
    if (progress >= 100) {
        console.log('Все пакеты подписаны! Показываем кнопку возврата');
        $j('.completion-actions').fadeIn(500);
    }
}

// Функция сброса состояния подписи (полезно для отладки и ручного сброса)
function resetSigningState()
{
    console.log('Сброс состояния подписи');
    hasSigningError = false;
    isSigningInProgress = false;
    packetsQueue = [];
    console.log('Состояние сброшено: hasSigningError=false, isSigningInProgress=false, очередь очищена');
}

// Функция обработки следующего пакета из очереди
function processNextPacket()
{
    //console.log('processNextPacket: packetsQueue.length=' + packetsQueue.length);

    if (packetsQueue.length === 0) {
        console.log('Очередь пуста, ничего не обрабатываем');
        return;
    }

    if (isSigningInProgress) {
        console.log('Подпись уже в процессе, ждем завершения');
        return;
    }

    if (hasSigningError) {
        console.log('Есть ошибка подписи, очищаем очередь');
        packetsQueue = [];
        return;
    }

    // Берем первый пакет из очереди
    var packet = packetsQueue.shift();
    console.log('Обрабатываем пакет из очереди: uid2=' + packet.uid2 + ', осталось в очереди: ' + packetsQueue.length);

    // Устанавливаем флаг ПЕРЕД вызовом асинхронной функции
    isSigningInProgress = true;

    signData(cert_Thumbprint, packet.uid2, packet.content, 0, emulate_sign, function(result)
    {
        //console.log('Получен ответ signData: ' + JSON.stringify(result));
        console.log('packet.uid2: ' + packet.uid2);
        if (result.status === 'success')
        {
            isSigningInProgress = false;
            //new jBox('Notice', {content: 'Успешно подписан ' + packet.notife_of_data, color:'green'});

            // отправляем запрос на проверку того, что подпись действительно сформирована - через 1 сек после подписи
            setTimeout(function() {
                    send_ajax_request({cmd:'pl/set_packet_sign_status',packet_uid:packet.uid2}) ;
            }, 1000);


            // Обновляем UI карточки пакета
            updatePacketUI(packet.packet_id);

            // Обновляем dashboard через небольшую задержку (для анимации)
            setTimeout(function() {
                updateDashboard();
            }, 100);

            // Обрабатываем следующий пакет из очереди
            setTimeout(function() {
                processNextPacket();
            }, 500); // Небольшая задержка для корректной обработки



        } else
        {
            // Устанавливаем флаг ошибки, но не показываем уведомление (оно уже показано в esmo_sign.js)
            isSigningInProgress = false;
            hasSigningError = true;
            console.log('Устанавливаем флаг ошибки, очищаем очередь');
            console.error('Ошибка подписи: ' + result.message);
            packetsQueue = []; // Очищаем очередь при ошибке

            // Обновляем dashboard при ошибке
            updateDashboard();
        }
    });
}




