'use strict';

import { getLang } from "../lang.js";

export const initFunctions = async (_store, cbext_path, when_init) => {

    return НЕ РАБОТАЕТ;


    let init_path = when_init === 'window' ? '../../' : './'
    let store = _store;
    let l = getLang(config["lang"] == "russian" ? config["lang"] : "english");

    /**
     * Функция обёртка для выполнения запросов
     *
     * @param string url
     * @returns Object
     */
    async function getData(url){
        let response = await fetch(url, {
            credentials: 'include',
            headers: {
                'X-Auth-Token': window.x_auth_token,
            },
        });
        let data = await response.json();

        return data;
    }

    // Получаем данные настроек модуля
    let settings_data = await getData(`${init_path}api/dev/settings/cbext.clientbase.iptel_uiscom`); // TODO uiscom
    // получаем данные аккаунтов из настроек
    let account_data = settings_data.data.attributes.value.personal_account_details;
    // устанавливаем данные пользователя телефонии для текущего пользователя
    let user_settings = settings_data.data.attributes.value.users.filter(item => item.cb_user == user.id)[0];
    // проверка на существование пользовательских настроек телефонии для текущего пользователя, иначе выдаём предупреждение и не авторизуем
    if(user_settings == void 0){
        store.set('user_status', {
            status: false,
            message: l["user_not_added_to_telephony"]
        });
        return;
    }

    // получаем всех пользователей конфигурации
    let cb_users_data = await getData(`${init_path}api/dev/users`);

    // Формируем объект пользователей КБ, которые присутствуют в настройках телефонии (для которых настроена телефония)
    let users_info = [];
    for(let user_sip of settings_data.data.attributes.value.users){
        if(user_sip.cb_user == user.id) continue;

        for(let user_cb of cb_users_data.data){
            if(user_sip.cb_user == user_cb.id){
                users_info.push({
                    id: user_cb.id,
                    name: user_cb.attributes.fio,
                    short_number: user_sip.short_sip_number
                });
            }
        }
    }

    /**
     * Функция очистки переменных store
     *
     * @param bool is_hang_up Окончание ли это звонка?
     * @param bool use_local_storage Переменная, которая отвечает за использование localStorage (true - использовать, false - нет)
     */
    function clearInfo(is_hang_up = false, use_local_storage = true){
        store.delete('phone_number___dtmf');
        store.delete('phone_number___changer');
        if(!is_hang_up){
            store.set('is_showed_call_block', false, use_local_storage);
            store.set('phone_number', '', use_local_storage);
        }
        else if(!document.hidden){
            store.set('is_showed_call_block', true, use_local_storage);
        }
        store.set('service_text', '', use_local_storage);
        store.set('notification_text', '', use_local_storage);
        store.set('is_call', false, use_local_storage);
        store.set('call_type', '', use_local_storage);
        store.set('asterisk_time', '00:00:00', use_local_storage);
        // callIndicator(true);
        store.set('timerId', clearInterval(store.get('timerId')), use_local_storage);
        store.get('go_time')(true);
        store.set('redirect_number', '', use_local_storage);
        store.set('show_redirect_block', false, use_local_storage);
        if(store.get('oldTitle') && (store.get('_ua') || store.get('session') ||store.get('iSession'))){
            document.title = store.get('oldTitle');
        }
        if(store.get('oldIcon') && (store.get('_ua') || store.get('session') ||store.get('iSession'))){
            document.querySelector("link[rel~='icon']").href = store.get('oldIcon');
        }
    }

    /**
     * Функция индикации звонка (deprecated) - Иконка и заголовок у вкладки.
     *
     * @param bool clear закончить индикацию
     * @returns
     */
    function callIndicator(clear = false){
        if(clear){
            store.set('timerId', clearInterval(store.get('timerId')));
            return;
        }
        store.set('oldTitle', document.title),
        store.set('oldIcon', document.querySelector("link[rel~='icon']").href);
        store.set('timerId', setInterval(function(){
            if(document.title != l["call___"]){
                document.title = l["call___"];
                document.querySelector("link[rel~='icon']").href = `./${cbext_path}/images/tel.png`;
            }
            else {
                document.title = store.get('oldTitle');
                document.querySelector("link[rel~='icon']").href = store.get('oldIcon');
            }
        }, 1000));
    }

    /**
     * Функция заполнения переменными store
     *
     * @param Array variables Массив объектов переменных (name - имя переменной и default - значение по умолчанию)
     */
    function fillVariables(variables = []){
        for(let variable of variables){
            if(!store.has(variable.name)){
                store.set(variable.name, variable.default);
            }
        }
    }

    /**
     * Функция, которая устанавливает в store время последнего звонка
     *
     * @param string time Длительность звонка
     */
    function showEndCallTime(time){
        store.set('show_call_notification', true);
        store.set('notification_title', l["the_call_is_over"]);
        store.set('notification_text', `${l["call_duration"]} ${time}`);
    }

    /**
     *  Функция заполняющая информацию в store о собеседнике по указанному номеру телефона
     *
     * @param string _phone_number Номер телефона
     */
    async function fillCardInfo(_phone_number){
        let response = await fetch(`${init_path}api/dev/cbext/clientbase/iptel_uiscom/find?number=${_phone_number}`, {    // TODO uiscom
            method: 'GET',
            credentials: 'include',
            redirect: 'follow',
            headers: {
                'X-Auth-Token': window.x_auth_token,
                "Accept": "application/vnd.api+json",
                "Content-Type": "application/vnd.api+json"
            }
        });
        let msg = await response.json();
        if (msg) {
            store.set('show_call_notification', true);
            var from =`${msg['name']['field_name']}: `
            var from_name = msg['name']['value'];
            if (from_name == 'NULL_NAME') from_name = '';
            var from_url = msg['url'];
            if (msg['issetClientCard']) {
                var addit_1 = (Object.keys(msg['additional_fields'][0]).length > 0) ? `${msg['additional_fields'][0]['field_name']}: ${msg['additional_fields'][0]['value']}` : '',
                    addit_2 = (Object.keys(msg['additional_fields'][1]).length > 0) ? `${msg['additional_fields'][1]['field_name']}: ${msg['additional_fields'][1]['value']}` : '',
                    addit_3 = (Object.keys(msg['additional_fields'][2]).length > 0) ? `${msg['additional_fields'][2]['field_name']}: ${msg['additional_fields'][2]['value']}` : '';
            }

            store.set('notification_info', {
                from_number: _phone_number,
                from,
                from_name,
                from_url,
                addit_1,
                addit_2,
                addit_3
            });

        }
    }

    /**
     * Функция, которая создаёт уведомление в КБ после окончания звонка
     *
     * @param string _phone_number Номер телефона собеседника
     */
    async function requestForCreateTip(_phone_number){
        await fetch(`${init_path}api/dev/cbext/clientbase/iptel_uiscom/createAnsweredTip?user_id=${user.id}&number=${_phone_number}`, {     // TODO uiscom
            method: 'GET',
            credentials: 'include',
            redirect: 'follow',
            headers: {
                'X-Auth-Token': window.x_auth_token,
                "Accept": "application/vnd.api+json",
                "Content-Type": "application/vnd.api+json"
            }
        });
    }

    /**
     * Handler для событий входящего звонка
     *
     * @param string type тип события входящего звонка
     * @param string _phone_number Номер телефона собеседника
     */
    function incomingCallHandler(type = '', _phone_number = ''){
        // Звонок принят
        if(type == 'accepted'){
            store.get('stopSound')();
            store.get('playSound')("answered.mp3", false);
            let Call = store.get('Call');
            Call['incoming']['incomingNumberGo'] = true;
            store.set('Call', Call);
            store.set('is_call', true);
            store.get('go_time')();
            store.set('phone_number___changer', () => {
                if(store.get('phone_number').match('#') == null){
                    let phone_number = store.get('phone_number').slice(0, -1) + '#' + store.get('phone_number').slice(-1);
                    store.set('phone_number', phone_number);
                }
            });
            store.set('phone_number___dtmf', () => {
                if(store.get('phone_number').match('#') != null && store.get('phone_number').split('#')[1]){
                    store.get('session').sendDTMF(store.get('phone_number').split('#')[1].slice(-1));
                }
            });
        }
        else if(type == 'confirmed'){

        }
        // произошла ошибка
        else if(type == 'failed'){
            store.get('stopSound')();
            let Call = store.get('Call');
            Call.isCall = false;
            Call['incoming'] = {};
            store.set('Call', Call);
            clearInfo(true);
            store.get('closeNotification')();
        }
        // Звонок закончен
        else if(type == 'ended'){
            store.get('stopSound')();
            let Call = store.get('Call');
            Call.isCall = false;
            Call['incoming'] = {};
            store.set('Call', Call);
            let time = store.get('asterisk_time');
            requestForCreateTip(store.get('phone_number'));
            clearInfo(true);
            showEndCallTime(time);
        }
        // При возникновении/инициации входящего звонка (когда кто-то тебе позвонил)
        else {
            store.get('stopSound')();
            store.get('playSound')("ringing.ogg", true);
            let Call = store.get('Call') || {};
            Call['isCall'] = true;
            Call['incoming'] = {};
            Call['incoming']['incomingNumber'] = _phone_number;
            store.set('Call', Call);
            /* Именение тайтла и иконки с периодичностью при звонке */
            // callIndicator();
            store.set('call_type', 'incoming');
            store.set('notification_title', l["incoming_call"]);
            store.set('phone_number', _phone_number);
            /* --- */
            store.set('is_showed_call_block', true);
            store.set('show_call_notification', true);
        }
    }

    /**
     * Обработчик для событий исходящего звонка
     *
     * @param string type тип события исходящего звонка
     * @param Object data данные исходящего звонка
     * @returns
     */
    function outgoingCallHandler(type = '', data = {}){
        // Процесс дозвона
        if(type == 'progress'){
            store.set('call_status', 'progress');
            store.set('service_text', l["progress___"]);
            store.get('playSound')("ringback.ogg", true);
        }
        // Звонок принят
        else if(type == 'accepted'){
            store.set('call_status', 'accepted');
            store.set('service_text', 'Accepted.');

            store.set('show_number_block', true);

            store.get('stopSound')();
            store.get('playSound')("answered.mp3", false);

            store.get('go_time')();

            /*
                Определяем middleware функции, которые срабатывают при изменении в store состояния наименование,
                которое равно части наименование middleware функции до ___.
                То есть функция phone_number___changer выполнится при изменении состояния phone_number store.
            */
            store.set('phone_number___changer', () => {
                if(store.get('phone_number').match('#') == null){
                    let phone_number = store.get('phone_number').slice(0, -1) + '#' + store.get('phone_number').slice(-1);
                    store.set('phone_number', phone_number);
                }
            });
            store.set('phone_number___dtmf', () => {
                if(store.get('phone_number').match('#') != null && store.get('phone_number').split('#')[1].length > 0){
                    store.get('session').sendDTMF(store.get('phone_number').split('#')[1].slice(-1));
                }
            });
        }
        // Произошла ошибка
        else if(type == 'failed'){
            JsSIP.Utils.closeMediaStream(store.get('_localClonedStream'));

            store.set('call_status', 'failed');
            store.set('service_text', data.cause);

            store.get('stopSound')();
            store.get('playSound')("rejected.mp3", false);

            let Call = store.get('Call');
            Call.isCall = false;
            Call['outgoing'] = {};
            store.set('Call', Call);

            clearInfo(true);
            store.get('closeNotification')();

            if(data.phone_numbers.length != 0){
                store.get('call')(data.phone_numbers);
                return;
            }
        }
        // Звонок окончен
        else if(type == 'ended'){
            JsSIP.Utils.closeMediaStream(store.get('_localClonedStream'));

            store.set('call_status', 'ended');
            store.set('service_text', l["ended"]);

            store.get('stopSound')();
            store.get('playSound')("rejected.mp3", false);

            let Call = store.get('Call');
            Call.isCall = false;
            Call['outgoing'] = {};
            store.set('Call', Call);

            let time = store.get('asterisk_time');
            requestForCreateTip(store.get('phone_number'));
            clearInfo(true);
            showEndCallTime(time);
            //this.session.terminate();
            if(data.phone_numbers.length != 0){
                store.get('call')(data.phone_numbers);
                return;
            }
        }
        // Инициализация исходящего звонка
        else {
            store.set('is_call', true);
            // Делаем ИСХОДЯЩИЙ звонок

            let Call = store.get('Call') || {};
            Call['isCall'] = true;
            Call['outgoing'] = {};
            Call['outgoing']['number'] = data.number;
            store.set('Call', Call);

            // callIndicator();

            store.set('notification_title', l["outgoing_call"]);
            store.set('call_type', 'outgoing');
            store.set('show_call_notification', true);
        }
    }

    // Заполнение переменных хранилища
    fillVariables([
        {
            name: 'can_login',
            default: true,
        },
        {
            name: 'service_text',
            default: '',
        },
        {
            name: 'phone_number',
            default: '',
        },
        {
            name: 'asterisk_time',
            default: '00:00:00',
        },
        {
            name: 'tone',
            default: '2',
        },
        {
            name: 'options',
            default: {
                pcConfig: {
                    hackStripTcp: true, // Важно для хрома, чтоб он не тупил при звонке
                    rtcpMuxPolicy: 'negotiate', // Важно для хрома, чтоб работал multiplexing. Эту штуку обязательно нужно включить на астере.
                    iceServers: [{
                        urls:['stun:stun.l.google.com:19302']
                    }],
                    iceTransportPolicy: "all"
                },
                mediaConstraints: {
                    audio: true, // Поддерживаем только аудио
                    video: false
                },
                rtcOfferConstraints: {
                    offerToReceiveAudio: 1, // Принимаем только аудио
                    offerToReceiveVideo: 0
                }
            },
        },
        {
            name: 'is_call',
            default: false,
        },
        {
            name: 'callInterval',
            default: undefined,
        },
        {
            name: 'show_call_notification',
            default: false,
        },
        {
            name: 'call_type',
            default: '',
        },
        {
            name: 'notification_info',
            default: {},
        },
    ]);
    // Устанавливаем состояние пользователя (есть настройки, или нет)
    store.set('user_status', {
        status: true,
        message: ''
    });
    // Устанавливаем информацию о текущем пользователе
    store.set('users_info', users_info);
    // store.set('is_showed_call_block', false);
    // Устанавливаем информацию о текущем провайдере
    store.set('provaiders' , {
        'Primatel':{      // TODO: Primatel
                'server': `${account_data.server}:${account_data.port}`,
                'domain': account_data.domain,
                'login': account_data.SIPnumber,
                'password': account_data.SIPpassword
        },
    });
    store.set('currentProvaider', 'Primatel'); // TODO: Primatel
    // Сервисная инфа при инициализации
    store.set('show_number_block', false); // показывать numpad
    store.set('timerId', undefined); // таймер для индикации
    store.set('iSession', undefined); // сессия входящего звонка
    store.set('localStream', undefined); // stream для передачи голоса
    store.set('params', {
        url: 'https://api.primatel.ru', // адрес API                                                        // TODO primatel
        rlogin: account_data.loginPBX,       // логин для доступа к API
        rkey: account_data.rkey,         // секретный ключ для формирования подписи к запросам
        login: account_data.loginPBX,        // логин личного кабинета
        password: account_data.passwordPBX,     // пароль личного кабинета
        sip_login: user_settings.sip_number,    // логин для авторизации SIP-телефона
        sip_password: user_settings.sip_password, // пароль для авторизации SIP-телефона
    });
    // параметры авторизации
    store.set('req', {
        login: store.get('params')['login'],
        password: store.get('params')['password'],
        sip_login: store.get('params')['sip_login'],
        sip_password: store.get('params')['sip_password']
    });
    // Функция генерации сигнатуры для выполнения запроса к провайдеру (типа безопасность)
    store.set('calcSignature', function (data, rkey){
        keys = [];

        for (i in data)
        if (i != 'svc'
            && i != 'lang'
            && i != 'mode'
            && i != 'charset'
            && i != 'sid'
            && i != 'uqk'
            && i != 'rsign'
                )
            keys.push(i);

        keys.sort();

        var s = '';

        for (i in keys) {

        var key = keys[i];
        var val = data[key];

        if (typeof val  === 'object')
            val = '[' + arrayToStrForSign ( val ) + ']';

        s = s + val + ';';
        }

        s = s + rkey;

        let sign = CryptoJS.MD5(s).toString(CryptoJS.enc.Hex);

        return sign;
    });

    // Функция генерации даты в нужном формате. Вроде нигде не используется, поэтому стоит проверить нужна ли она и если не нужна удалить
    store.set('getYMDHMS', function (d) {
        function zeroFill (number, width)
        {
            var input = number + "";  // make sure it's a string
            var zeroFillData = "0000000000";
            return(zeroFillData.slice(0, width - input.length) + input);
        }

        var dd = zeroFill(d.getDate(), 2);
        var mm = zeroFill(d.getMonth() + 1, 2); //Months are zero based
        var yyyy = d.getFullYear();

        var HH = zeroFill(d.getHours(), 2);
        var MM = zeroFill(d.getMinutes(), 2); //Months are zero based
        var SS = zeroFill(d.getSeconds(), 2);

        return yyyy + '-' + mm + '-' + dd + ' ' + HH + ':' + MM + ':' + SS;
    });


    // Запрос к апи провайдера (используется для получения стоимости звонка по определённому номеру)
    // Классический http запрос
    store.set('callRequest', async function (params, command, data = null, mode = 'json'){
        // Сформировать URL
        var url = params['url']
            + '?svc=' + command
            + '&mode=' + mode // не обязательный, по умолчанию будет 'xml'
            + '&lang=ru';      // не обязательный, по умолчанию будет 'en'

        var req = {
            method : 'POST',
            body: JSON.stringify(data, null, 4),
            credentials: 'same-origin', // enable cookies
        };

        let response = await fetch(url, req);

        var contentTypeRaw = response.headers.get("content-type");

        var A = contentTypeRaw.split(/;/);

        var contentType = A ? A[0] : contentTypeRaw;

        switch (contentType) {
            case 'application/json':
                let json = await response.json();
                if (response.ok) {
                    return json;
                } else {
                    throw new Error('[' + command + '] Call failed. HTTP status ' + response.status + ' ' + response.statusText);
                }
            case 'audio/mpeg':
                let blob = await response.blob();
                if (response.ok) {
                    return window.URL.createObjectURL(blob);
                } else {
                    throw new Error('[' + command + '] Call failed. HTTP status ' + response.status + ' ' + response.statusText);
                }
            default:
                return undefined;
        }
    });

    // Выполнить подписанный запрос к api провадера
    store.set('scall', async function (params, command, data = null, mode = 'json'){
        var keys = [];

        if (!data)
            data = {};

        data['rlogin'] = params['rlogin'];
        data['rsign'] = store.get('calcSignature')(data, params['rkey']);

        let result = await store.get('callRequest')(params, command, data, mode);

        return result;
    });

    // Функция, которую вызываем для показа блока звонилки (с номером, кнопками "Позвнить" и т.д.)
    store.set('showCallBlock', function (){
        let is_showed_call_block = store.get('is_showed_call_block');
        store.set('is_showed_call_block', !is_showed_call_block);
        if(!store.get('is_showed_call_block') && (store.get('Call') && !(!!store.get('Call').isCall))){
            //store.set('phone_number', '');
            store.set('service_text', '');
        }
        if (store.get('phone_number') != '') {
            let Call = store.get('Call') || {};
            Call['numberForCall'] = store.get('phone_number');
            store.set('Call', Call);
        }
        if(!is_showed_call_block){
            document.getElementById('call_block-tel_number').focus();
        }
    });

    // Лог загрузки страницы (нужно удалить)
    store.set('loadPage', function () {
        console.log('on loadPage');
    });

    // Функция логина
    store.set('login', function (){
        console.log("on login");
        // логинимся только когда позволяет флаг can_login, только на внешней странице (поднимается при инициализации), и если не пустые логин и пароль
        if(when_init === 'page' || !store.get('can_login') || store.get('params')['sip_login'].trim() == '' || store.get('params')['sip_password'].trim() == ''){
            return;
        }
        // Создаём новый сокет интерфейс библиотекой JSSip
        store.set('socket', new JsSIP.WebSocketInterface(store.get('provaiders')[store.get('currentProvaider')]['server']));
        // Авторизуемся в астере
        store.set('_ua', new JsSIP.UA(
            {
                uri: "sip:" + store.get('params')['sip_login'] + "@" + store.get('provaiders')[store.get('currentProvaider')]['domain'],
                password: store.get('params')['sip_password'],
                display_name: store.get('loginText'),
                sockets: [store.get('socket')],
                session_timers: false
            }));

        // соединяемся с астером
        store.get('_ua').on('connecting', () => {
            console.log("UA connecting");
        });

        // соединились с астером
        store.get('_ua').on('connected', () => {
            console.log("UA connected");
        });

        // астер нас зарегал, теперь можно звонить и принимать звонки
        store.get('_ua').on('registered', () => {
            // console.log("UA registered");
            store.set('can_login', false);
            //store.set('showed_call_buttons', true);
        });

        // астер про нас больше не знает
        store.get('_ua').on('unregistered', () => {
            console.log("UA unregistered");
        });

        // астер не зарегал нас, что то не то, скорее всего неверный логин или пароль
        store.get('_ua').on('registrationFailed', (data) => {
            console.error("UA registrationFailed", data.cause);
        });

        // заводим шарманку
        store.get('_ua').start();

        // Вызываем функцию, которая на заведённую шарманку и её события накинет обработчики
        store.get('incomingCall')(store.get('_ua'));
    })

    // Функция логаута из астера
    store.set('logout', function () {
        console.log("on logout");
        // закрываем всё, вылогиниваемся из астера, закрываем коннект
        store.get('_ua').unregister();
        // Удаляем из хранилища переменную входящей сессиии
        store.delete('iSession');
        // Удаляем из хранилища переменную исходящей сессиии
        store.delete('session');
        // Устанавливаем флаг can_login для возможного последующего логина
        store.set('can_login', true);
    });

    // Функция, которая накидывает обработчики на создание и другие события входящих звонков
    store.set('incomingCall', function (ua) {
        ua.on('newRTCSession', async function(data){ // событие создания сессии входящих звонков
            if(store.get('Call') && store.get('Call').isCall){ // если уже есть инфа о звонке текущем, завершаем работу
                return;
            }
            clearInfo(true);
            store.set('iSession', data.session); // записываем в хранилище сессию
            if (store.get('iSession').direction === "incoming") { // если направление звонка - входящий
                incomingCallHandler('', data.request.from._display_name); // вызываем функцию обработчика с пустым типом (для инициализации)
                try {
                    await fillCardInfo(data.request.from._display_name); // заполняем карточку клиента
                }
                catch (error) {
                    console.error(error);
                }
                store.get('iSession').on('peerconnection', function(data) { // крутим вертим всё по стримам звука, получаем стрим и кидаем его в элемент аудио на странице
                    data.peerconnection.addEventListener('addstream', function (e) {
                        // set remote audio stream
                        let remoteAudioControl = document.getElementById("remoteAudio");
                        remoteAudioControl.srcObject = e.stream;
                        remoteAudioControl.play();
                    });
                });

                // Звонок принят, можно начинать говорить
                store.get('iSession').on('accepted', () => {
                    // console.log("UA session accepted");
                    incomingCallHandler('accepted'); // Обработчик принятого входящего звонка
                });

                store.get('iSession').on("confirmed",function(data){
                    // console.log(data);
                    incomingCallHandler('confirmed'); // Событие непонятно когда наступает, да и обработчик пустой. По идее можно выпилить
                });

                store.get('iSession').on("ended",function(data){
                    // console.log("session ended");
                    incomingCallHandler('ended'); // Обработчик окончания входящего звонка
                });
                store.get('iSession').on("failed",function(data){
                    // console.log("session failed");
                    incomingCallHandler('failed'); // Обработчик ошибки входящего звонка
                });
            }
        });
    });

    // Функция окончания входящего звонка
    store.set('incomingHangUp', function () {
        if (store.get('iSession')){ // Если есть сессия на странице, значит тут говорили
            store.get('playSound')("rejected.mp3", false); // Проигрываем звук окончания
            store.get('iSession').terminate(); // Заканчиваем звонок
        } else { // если сессия звонка определена на другой вкладке, а мы нажали кнопку завершить на текущей
            // Все переменные очищаем, устанавливаем флаг, для сброса звонка и пытаемся залогиниться
            let Call = store.get('Call');
            Call.isCall = false;
            Call['incoming'] = {};
            Call['incoming']['dropIncomingCall'] = true; // Флаг для сброса звонка на той вкладке, где есть сессия входящего звонка
            store.set('Call', Call);

            Call['incoming'] = {};
            store.set('Call', Call);

            store.get('login')(); // пытаемся залогиниться
        }
    });

    // Функция для инициации исходящего звонка
    store.set('call', async (_phone_numbers = []) => {
        clearInfo(true);
        store.get('closeNotification')();

        let phone_numbers = _phone_numbers;
        if(phone_numbers.length != 0){
            store.set('phone_number', phone_numbers.shift().trim()); // получаем первый номер из массива переданных номеров (может быть несколько, для автообзвона)
        }

        let number = store.get('phone_number'); // Берём номер
        if(number.trim().length == 0){ // Проверяем номер на валидность
            store.set('service_text', 'Number is empty!');
            setTimeout(() => {
                store.set('service_text', '');
            }, 5000);
            return;
        }
        if(number.length >= 10 && number[0] == '+' && number[1] == '7'){
            number = '8' + number.slice(2);
        }

        try {
            await fillCardInfo(number); // Заполняем карточку клиента
        }
        catch (error) {
            console.error(error);
        }

        if (store.get('_ua')) { // если есть объект jssip для исходящих звонков (он при логине создаётся)
            store.set('session', store.get('_ua').call(number, store.get('options'))); // Вызываем метод call и если записываем полученную сессию исходящего звонка

            outgoingCallHandler('', {
                number
            }); // Обработчик при инициализации исходящего звонка
            /* --- */
            // Астер нас соединил с абонентом
            store.get('session').on('connecting', () => {
                // console.log("UA session connecting");
                store.set('service_text', 'Connecting...');
                //playSound("ringback.ogg", true);
                // Тут мы подключаемся к микрофону и цепляем к нему поток, который пойдёт в астер
                let peerconnection = store.get('session').connection;
                store.set('localStream', peerconnection.getLocalStreams()[0]);
                if (store.get('localStream')) {
                    let localStream = store.get('localStream');
                    store.set('_localClonedStream', localStream.clone());

                    // console.log('UA set local stream');

                    let localAudioControl = document.getElementById("localAudio");
                    localAudioControl.srcObject = store.get('_localClonedStream');
                }

                // Как только астер отдаст нам поток абонента, мы его засунем к себе в наушники
                peerconnection.addEventListener('addstream', (event) => {
                    // console.log("UA session addstream");

                    let remoteAudioControl = document.getElementById("remoteAudio");
                    remoteAudioControl.srcObject = event.stream;
                    remoteAudioControl.play();
                });
            });


            // В процессе дозвона
            store.get('session').on('progress', () => {
                // console.log("UA session progress");

                outgoingCallHandler('progress');
            });

            // Дозвон завершился неудачно, например, абонент сбросил звонок
            store.get('session').on('failed', (data) => {
                // console.log("UA session failed");

                outgoingCallHandler('failed', {
                    cause: data.cause,
                    phone_numbers
                });
            });

            // Поговорили, разбежались
            store.get('session').on('ended', (data) => {
                // console.log("UA session ended");

                outgoingCallHandler('ended', {
                    phone_numbers
                });
            });
            // Звонок принят, моно начинать говорить
            store.get('session').on('accepted', () => {
                // console.log("UA session accepted");

                outgoingCallHandler('accepted');
            });
        }
    });

    // Функция для сброса исходящего звонка
    store.set('hangUp', function(is_block_hang_up = false) {
        if (store.get('session')) { // есть сессия исходящего звонка
            store.set('is_call', false);

            let Call = {
                isCall: false,
                outgoing: {},
            };
            store.set('Call', Call);

            store.get('session').terminate();
        } else { // сбрасываем на другой вкладке, где нет сессии
            // Очищаем переменные хранилища и записываем флаг, чтобы на той вкладке, которой сессия есть, звонок сбросился и пытваемся залогиниться
            store.set('is_call', false);
            let Call = {
                isCall: false,
                outgoing: {
                    dropCall: true
                }
            };
            store.set('Call', Call);

            Call['outgoing'] = {};
            store.set('Call', Call);

            clearInfo(true, false);

            store.get('login')();
        }
    });

    // Функция проигрывания звуков звонка, есть не реализованы провайдером
    store.set('playSound', function(soundName, loop) {
        let sound_element = document.getElementById('sounds');
        sound_element.src = '';
        sound_element.loop = loop;
        sound_element.muted = true;
        sound_element.play();
        sound_element.muted = false;
    });

    // Функция остановки проигрывания звуков
    store.set('stopSound', function() {
        let sound_element = document.getElementById('sounds');
        sound_element.pause();
        sound_element.currentTime = 0.0;
    });

    // Функция запуска таймера для просчитывания длительности разговора
    store.set('go_time', function (clear = false) {
        var prev_sec = 0,
            sec_,
            min_,
            hours_,
            zeros,
            zerom,
            pos;
        if (clear) {
            if (store.get('callInterval')) {
                setTimeout(function () {
                    store.set('callInterval', clearInterval(store.get('callInterval')));
                }, 0);
            } else {
                return false;
            }
        } else {
            store.set('callInterval', setInterval(function () {
                sec_ = prev_sec % 60;
                min_ = parseInt(prev_sec / 60);
                hours_ = '00';

                zeros = '';
                if (sec_ < 10) zeros = '0';
                zerom = '';
                if (min_ < 10) zerom = '0';

                store.set('asterisk_time', hours_ + ':' + zerom + min_ + ':' + zeros + sec_);

                prev_sec++;
            }, 1000));
        }
    })

    // Обработчик принять входящий звонок
    store.set('callAnswer', function() {
        localStorage.setItem('needAnswerCall', JSON.stringify({data:true}))
    });

    // функция закрытия уведомления (можно убрать если нигде не используется)
    store.set('closeTipTimeout', function () {
        store.set('show_call_notification', false);
    });

    // Замутить звонок
    store.set('muteCall', function (needMute) {
        if (store.get('call_type') != 'outgoing') {
            if (needMute) {
                store.get('session').mute()
            } else {
                store.get('session').unmute()
            }
        } else {
            if (needMute) {
                store.get('iSession').mute();
            } else {
                store.get('iSession').unmute();
            }
        }
    });

    // Поставить звонок на ожидание
    store.set('holdCall', function (needHold) {
        if (store.get('call_type') != 'outgoing') {
            if (needHold) {
                store.get('session').sendDTMF('#')
            } else {
                store.get('session').sendDTMF('#')
            }
        } else {
            if (needHold) {
                store.get('iSession').sendDTMF('#')
            } else {
                store.get('iSession').sendDTMF('#')
            }
        }
    });

    // Начинаем процесс переадресации звонка его удержанием (убрать эту функцию и заменить её вызов функцией, которая выше)
    store.set('startForwardCall', function () {
        store.get('iSession').sendDTMF('#')
    });

    // Прокидываем в донабор нужный номер при переадресации
    store.set('forwardCall', function () {
        store.get('iSession').sendDTMF(localStorage.getItem('redirect_number'));
        //store.get('incomingHangUp')();
    });

    // Функция закрытия уведомления
    store.set('closeNotification', function (){
        store.set('show_call_notification', false);
        store.set('notification_title', '');
        store.set('notification_text', '');
        store.set('notification_info', {});
    });

    // Вешаем обработчик-слушатель на изменения localStorage - для межвкладочного взаимодействия
    window.addEventListener('storage', function(event) {
        if (event.key == 'goCall') { // совершить звонок на вкладке, где есть логин
            let call = JSON.parse(event.newValue).data
            if (call == true) {
                store.get('call')()
                localStorage.setItem('goCall', JSON.stringify({data:false}))
            }
        }
        if (event.key == 'needAnswerCall') {  // ответить на входящий звонок, где есть логин
            let call = JSON.parse(event.newValue).data
            if (call == true) {
                store.get('iSession').answer(store.get('options'));
                store.set('is_call', true);
                localStorage.setItem('needAnswerCall', JSON.stringify({data:false}))
            }
        }
        if (event.key == 'muteCall') {  // совершить mute звонка, где есть логин
            let call = JSON.parse(event.newValue).data
            store.get('muteCall')(call);
        }
        if (event.key == 'holdCall') { // совершить удержание звонка, где есть логин
            let call = JSON.parse(event.newValue).data
            store.get('holdCall')(call);
        }
        if (event.key == 'startReferCall') { // начать переадресацию звонка, где есть логин (поставить на удержание)
            let call = JSON.parse(event.newValue).data
            if (call) {
                store.get('startForwardCall')()
            } else {
                store.get('holdCall')(call);
            }
        }
        if (event.key == 'forwardCall') { // совершить переадресацию звонка, где есть логин (донабор и передресация звонка)
            store.get('forwardCall')()
        }
        if (event.key == 'Call') { // если изменился на другой вкладке объект звонка, изменяем и на текущей
            let callEvent = JSON.parse(event.newValue).data;
            if (callEvent.provaider) {  // провайдер
                store.set('currentProvaider', callEvent.provaider, true);
            }
            if (callEvent.numberForCall) { // номер телефона
                store.set('phone_number', callEvent.numberForCall, true);
            }
            if (callEvent.outgoing) { // информация об исходящем звонке
                if (callEvent.outgoing.dropCall) { // если есть флаг, что нужно сбросить
                    if (store.get('session')){ // если есть сессия, сбрасываем
                        JsSIP.Utils.closeMediaStream(store.get('_localClonedStream'));
                        store.get('session').terminate();

                        let new_call = callEvent;
                        new_call.outgoing = {};
                        store.set('Call', new_call, true);

                        store.get('logout')();
                    }
                    clearInfo(true, false); // очищаем инфу
                }
                else { // иначе просто записываем в хранилище объект звонка, без записи в localStorage
                    store.set('Call', callEvent, false);
                }
                if (callEvent['outgoing'].number) { // если номер исходящего звонка есть, то в свойство номер записываем его
                    store.set('phone_number', callEvent['outgoing'].number, false);
                }
            } else if (callEvent.incoming) { // информация об входящем звонке
                if (callEvent['incoming'].incomingNumber && !callEvent['incoming'].incomingNumberGo) { // если звонок принят
                    store.set('Call', callEvent, false);
                }
                if (callEvent.incoming.dropIncomingCall) { // если есть флаг, что нужно сбросить
                    if (store.get('iSession') && Object.keys(store.get('iSession')).length > 0){ // есть сессия на текущей вкладке
                        // Reject call (or hang up it)
                        store.get('playSound')("rejected.mp3", false);
                        // callIndicator(true);
                        let Call = {
                            isCall: false,
                            incoming: {},
                        };
                        store.set('Call', Call);
                        // Reject call (or hang up it)
                        store.get('iSession').terminate();
                        clearInfo(true, false);
                        store.get('logout')();
                    }
                }
                else {
                    store.set('Call', callEvent, false); // просто записываем данные о звонке
                }
            }
            if(
                !callEvent.isCall &&
                (callEvent.incoming && Object.keys(callEvent.incoming).length == 0 ||
                callEvent.outgoing && Object.keys(callEvent.outgoing).length == 0)
            ){ // очищаем инфу
                clearInfo(false, false);
            }
        }
        if(
            event.key == 'is_showed_call_block' &&
            !store.has('iSession') &&
            !store.has('session')
        ){ // скрываем блок звонилкм если изменился key is_showed_call_block при этом нет сходящей или исходящей сессии на вкладке
            store.set('is_showed_call_block', false, false);
        }
        if(event.key == 'can_login' && event.newValue == 'true'){
            if (store.has('iSession') &&
                store.has('session')) { // если can_login true и есть сессия или исходящая сессия то логаутимся
                    store.get('logout')();
                }
        }
        if (
            event.key == 'asterisk_time' ||
            event.key == 'show_call_notification' ||
            event.key == 'notification_info' ||
            event.key == 'notification_text' ||
            event.key == 'notification_title' ||
            event.key == 'phone_number' ||
            event.key == 'service_text' ||
            event.key == 'is_call' ||
            event.key == 'call_type' ||
            event.key == 'call_status'
        ) { // все указанные ключи просто записываем в хранилище, без обновления localStorage
            store.set(event.key, JSON.parse(event.newValue).data, false);
        }
    });

    // document.addEventListener("visibilitychange", function(){
    //     if (!store.get('Call') || !store.get('Call').isCall) {
    //         if (document.hidden) {
    //             //store.get('logout')();
    //         } else {
    //             if(!store.has('iSession') &&
    //                 !store.has('session')){
    //                 store.set('can_login', true);
    //                 store.get('login')();
    //             }
    //         }
    //     }
    // });

    $(document).ready(function(){
        store.get('loadPage')();
        store.get('login')();
    });


    // window.addEventListener('beforeunload', (event) => {
    //     if(store.get('session')){
    //         store.get('session').terminate();
    //     }
    // });
}
