var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define(["require", "exports", "events", "uuid", "websocket", "rxjs", "rxjs/operators", "cron", "./config/logger/winston"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.getProductInfo = exports.setPingPongEnabled = exports.resetTransaction = exports.cancelOrderWithRemoveCheckLines = exports.cancelOrderAndRecoverBasket = exports.getClient = exports.getLoyaltyButtons = exports.getClientData = exports.fetchMenuKASU = exports.getDataModule = exports.on = exports.loyaltyOtpCode = exports.pressedButton = exports.processQrLoyalty = exports.startPay = exports.acceptOrder = exports.fpUnlock = exports.fpLock = exports.cancelOrder = exports.addPostPayFuel = exports.addFuelLine = exports.deleteProduct = exports.addProductScan = exports.addProductToCart = exports.connect = void 0;
    const events_1 = require("events");
    const uuid_1 = require("uuid");
    const WebSocket = require("websocket");
    const rxjs_1 = require("rxjs");
    const operators_1 = require("rxjs/operators");
    const cron_1 = require("cron");
    const winston_1 = require("./config/logger/winston");
    const ksoEmitter = new events_1.EventEmitter(); // Создаем новый экземпляр EventEmitter
    const arrUuidKey = []; // Массив с уникальными ключами, необходимы для подтверждения актуальности в запросах от клиента к серверу
    let sendBucketUpdate = true;
    let isPingPongEnabled = false;
    let ws = null; // Объявляем переменную ws здесь, чтобы она была доступна в других функциях
    let connectionEstablished = false; // Флаг на проверку ws соединения (костыль)
    let crmIdLoyalty; // Флаг на проверку ws соединения (костыль)
    let pingPongId;
    let isPingPongResponce = true;
    /** Объект со всеми данными */
    const dataModule = {
        menuCafeServiceData: null,
        imagesDataAllData: null,
        settingsDataStructureData: null,
        fuelStationDataData: null,
        // (id и массив с пистолетами), во втором баки с топливом(объекты с описанием бака)
        optionsDataStructureData: null,
        // отображения краткого сообщения, ожидания действий пользователя, сообщения “Продолжить ожидание?”)
        // и кол-ва биперов
        informationMessageFromKSO: '',
        //? Возможно сделать массивом с объектами, внутри которых будут записываться все сообщения
        remainingTimeValue: 0,
        confirmationPointsDebiting: '',
        answerButtons: null,
        arrStateTRK: [],
        acceptOrderValue: false,
        valueFuel: null,
        basketValue: null,
        idClient: null,
        clientData: null,
    };
    /** Функция для получения объект со всеми данными */
    const getDataModule = () => {
        return dataModule;
    };
    exports.getDataModule = getDataModule;
    /** Подключение оповещений(эмиттерев) */
    const on = (event, action) => {
        ksoEmitter.on(event, (data) => action(data));
    };
    exports.on = on;
    // Функция для отправки сообщения на вебсокет
    function sendMessage(wsc, message) {
        winston_1.logger.log('debug', message, ['request']);
        if (wsc.connected) {
            wsc.send(message);
        }
    }
    /** Функция будет обрабатывать сообщения, полученные через WebSocket соединение */
    function onMessage(msg) {
        var _a, _b, _c, _d;
        const data = JSON.parse(msg.utf8Data); //! String(msg)
        if (data) {
            winston_1.logger.debug(JSON.stringify(data), ['response']);
            switch (data.msgType) {
                case 'imagesDataAll':
                    winston_1.infoLogger.info(JSON.stringify(data), ['response']);
                    dataModule.imagesDataAllData = data.pictures;
                    //? Возможно переделка данных, в одно стороне изображения групп, в другой товаров
                    ksoEmitter.emit('info', 'Изображения товаров и групп получены');
                    ksoEmitter.emit('imagesDataAll', data.pictures);
                    break;
                case 'stationConfig':
                    dataModule.settingsDataStructureData = data.data;
                    //? Понять для чего нужны эти данные
                    ksoEmitter.emit('info', 'Конфигурация КСО получены');
                    ksoEmitter.emit('stationConfig', data.data);
                    break;
                case 'fpConfig':
                    console.log(data);
                    const objectConfig = {
                        fps: data.fps,
                        tankProducts: data.tankProducts,
                    };
                    dataModule.fuelStationDataData = objectConfig;
                    ksoEmitter.emit('fpConfig', objectConfig);
                    //? Возможно изменить структуру, в nozzles вместо tankId использовать непосредственно объект из tankProducts
                    ksoEmitter.emit('info', 'Конфигурация ТРК получены');
                    break;
                case 'fpLock':
                    winston_1.infoLogger.info(JSON.stringify(data), ['response']);
                    ksoEmitter.emit('info', 'ТРК заблокирована');
                    break;
                case 'optionsUpdate':
                    //? Понять для чего нужны эти данные
                    dataModule.optionsDataStructureData = data.data;
                    ksoEmitter.emit('info', 'Настройки АЗС получены');
                    ksoEmitter.emit('optionsUpdate', data.data);
                    break;
                case 'fpStatus':
                    // Избавляемся от лишнего сообщения(msgType)
                    const { msgType, data: objectWithoutMsgType } = data;
                    const index = dataModule.arrStateTRK.findIndex((el) => el.fpId === objectWithoutMsgType.fpId);
                    //? Проверить, отрабатывает ли
                    if (index !== -1) {
                        // Если статус был, для этой колонки(переписываем)
                        dataModule.arrStateTRK[index] = objectWithoutMsgType;
                    }
                    else {
                        // Если не было пушим новый
                        dataModule.arrStateTRK.push(objectWithoutMsgType);
                        ksoEmitter.emit('info', `Получено состояние ТРК ${data.data.fpId}`);
                    }
                    ksoEmitter.emit('fpStatus', dataModule.arrStateTRK);
                    // Создать новую подпись на имитацию налива
                    break;
                case 'basketUpdate':
                    winston_1.infoLogger.info(JSON.stringify(data), ['response']);
                    // Корзина обновляется после каждого добавления товара или налива, удаления\товара, отмены заказа
                    dataModule.basketValue = data.data;
                    if (!sendBucketUpdate) {
                        ksoEmitter.emit('info', 5);
                    }
                    if (data.data.basketState === 3 && dataModule.basketValue.cheque !== null) {
                        winston_1.loggerStatistic.log('statistics', JSON.stringify({
                            data,
                            timestamp: new Date().toUTCString(),
                        }));
                    }
                    // Проверка на пустой объект, если в массиве нет поля cheque, то не отправляем на клиент
                    if (((_a = dataModule === null || dataModule === void 0 ? void 0 : dataModule.basketValue) === null || _a === void 0 ? void 0 : _a.basketState) === 3 &&
                        dataModule.basketValue.cheque === null) {
                        break;
                    }
                    if (sendBucketUpdate) {
                        ksoEmitter.emit('info', 'Корзина обновлена');
                        ksoEmitter.emit('basketUpdate', data.data);
                    }
                    if (((_b = dataModule === null || dataModule === void 0 ? void 0 : dataModule.basketValue) === null || _b === void 0 ? void 0 : _b.basketState) === 3) {
                        ksoEmitter.emit('info', 'Оплата прошла успешно');
                        // Отключаем флаг подтверждения заказа
                        dataModule.acceptOrderValue = false;
                        ksoEmitter.emit('paymentSuccessful', true); //! Подписаться на изменения
                        arrUuidKey.length = 0;
                        const indexUnlockValue = dataModule.arrStateTRK.findIndex((el) => el.logicalNozzleId === dataModule.valueFuel);
                        if (dataModule.basketValue.cheque.lines.find((el) => el.nozzle !== null)) {
                            fpUnlock(dataModule.arrStateTRK[indexUnlockValue].fpId, dataModule.arrStateTRK[indexUnlockValue].lockId, dataModule.arrStateTRK[indexUnlockValue].logicalNozzleId);
                        }
                    }
                    break;
                case 'addFuelLine':
                    winston_1.infoLogger.info(JSON.stringify(data), ['response']);
                    if (data.data && arrUuidKey.includes(data.cmdId)) {
                        ksoEmitter.emit('info', `Получено подтверждение на добавление предоплатного налива`);
                        ksoEmitter.emit('fuelPre', true); //? Возможно подпись не нужна
                    }
                    else {
                        ksoEmitter.emit('error', `В подтверждение на добавление предоплатного налива произошла ошибка по cmdId ${data.cmdId}`);
                    }
                    break;
                case 'addPostpayFuel':
                    winston_1.infoLogger.info(JSON.stringify(data), ['response']);
                    if (data.data && arrUuidKey.includes(data.cmdId)) {
                        ksoEmitter.emit('info', `Получено подтверждение на добавление постоплатного налива по cmdId ${data.cmdId}`);
                        ksoEmitter.emit('fuelPost', true); //? Возможно подпись не нужна
                    }
                    else {
                        ksoEmitter.emit('error', `В подтверждение на добавление постоплатного налива произошла ошибка по cmdId ${data.cmdId}`);
                    }
                    break;
                case 'addProductLine':
                    winston_1.infoLogger.info(JSON.stringify(data), ['response']);
                    if (data.data === false) {
                        winston_1.logger.error(`Произошла ошибка при добавлении товара в корзину (Товар в корзину не добавлен)`);
                        ksoEmitter.emit('error', 'Произошла ошибка при добавлении товара в корзину (Товар в корзину не добавлен)');
                        return;
                    }
                    ksoEmitter.emit('info', `Получено подтверждение на добавление товара из меню КСО`);
                    ksoEmitter.emit('product', true); //? Возможно подпись не нужна
                    break;
                case 'addProductLineByBarCode':
                    winston_1.infoLogger.info(JSON.stringify(data), ['response']);
                    if (data.data === null) {
                        ksoEmitter.emit('info', `Получено подтверждение на добавление товара через сканер`);
                        break;
                    }
                    if (data.data) {
                        ksoEmitter.emit('info', data.data);
                        break;
                    }
                    ksoEmitter.emit('info', 'С касу пришло неизвестное сообщение');
                    ksoEmitter.emit('productScan', true); //? Возможно подпись не нужна
                    break;
                case 'acceptOrder':
                    winston_1.infoLogger.info(JSON.stringify(data), ['response']);
                    if (data.data) {
                        ksoEmitter.emit('info', `Получено подтверждение на добавление оплаты, номер заказа ${data.data}`);
                        ksoEmitter.emit('acceptOrderCheck', data.data);
                    }
                    else {
                        ksoEmitter.emit('error', `Заказ не добавлен, номер заказа не получен`);
                    }
                    break;
                case 'showMessage':
                    winston_1.loggerMessage.log('message', data.data);
                    winston_1.infoLogger.info(JSON.stringify(data), ['response']);
                    if (data.data) {
                        dataModule.informationMessageFromKSO = data.data;
                        ksoEmitter.emit('info', `Получено информационное сообщение - ${data.data}`);
                        ksoEmitter.emit('arrivalMessage', data.data); //! Здесь надо организовать правильный подход в работе всех сообщений под этой подписью
                    }
                    else {
                        ksoEmitter.emit('error', `Заказ не добавлен, номер заказа не получен`);
                    }
                    break;
                case 'requestCallback':
                    winston_1.infoLogger.info(JSON.stringify(data), ['response']);
                    if (data.data) {
                        dataModule.answerButtons = data;
                        dataModule.informationMessageFromKSO = data.data.title;
                        ksoEmitter.emit('info', `Получено массив с кнопками не/подтверждение списание баллов(btnYes,btnNo)`);
                        ksoEmitter.emit('addButtons', data.data.buttons);
                        ksoEmitter.emit('informationMessageFromKSO', (_c = data.data) === null || _c === void 0 ? void 0 : _c.title);
                        ksoEmitter.emit('informationMessageFromKSO', (_d = data.data) === null || _d === void 0 ? void 0 : _d.message);
                    }
                    else {
                        ksoEmitter.emit('error', `Массив с кнопками не получен`);
                    }
                    break;
                case 'loyaltyOtpCode':
                    winston_1.infoLogger.info(JSON.stringify(data), ['response']);
                    if (data.data) {
                        dataModule.informationMessageFromKSO = data.data;
                        crmIdLoyalty = data.cmdId;
                        ksoEmitter.emit('arrivalOtpCode', data.data);
                        ksoEmitter.emit('info', `Получено сообщение о необходимо подтверждение списания баллов`);
                    }
                    else {
                        ksoEmitter.emit('error', `Сообщение о необходимо подтверждение списания баллов не получено`);
                    }
                    break;
                case 'showMessageWindow':
                    winston_1.loggerMessage.log('message', data.data);
                    winston_1.infoLogger.info(JSON.stringify(data), ['response']);
                    if (data.data) {
                        dataModule.confirmationPointsDebiting = data.data;
                        ksoEmitter.emit('showMessageWindow', data.data);
                    }
                    break;
                case 'callbackClientData':
                    winston_1.infoLogger.info(JSON.stringify(data), ['response']);
                    if (data.data) {
                        dataModule.idClient = data.data.idClient;
                        dataModule.clientData = data.data;
                        ksoEmitter.emit('callbackClientData', data.data.idClient);
                        ksoEmitter.emit('info', data.data);
                    }
                    break;
                case 'resendOtpTimerValue':
                    winston_1.infoLogger.info(JSON.stringify(data), ['response']);
                    if (data.data) {
                        dataModule.remainingTimeValue = data.data;
                        ksoEmitter.emit('arrivalOtpTimerValue', data.data);
                        ksoEmitter.emit('info', `Получено значение с остатком времени в секундах, после которого можно запросить код повторно - ${dataModule.remainingTimeValue}`);
                    }
                    else {
                        ksoEmitter.emit('error', `Значение с остатком времени в секундах, после которого можно запросить код повторно не получено`);
                    }
                    break;
                case 'connected':
                    ksoEmitter.emit('info', `Connected with server`);
                    break;
                case 'serviceUnavailable':
                    ksoEmitter.emit('info', `СЕРВИС НЕДОСТУПЕН\u000d\u000aНЕТ СВЯЗИ С ККМ`);
                    ksoEmitter.emit('serviceAvailableCheck', false);
                    break;
                case 'serviceAvailable':
                    ksoEmitter.emit('info', `СЕРВИС ДОСТУПЕН`);
                    ksoEmitter.emit('serviceAvailableCheck', true);
                    break;
                case 'shiftOpened':
                    ksoEmitter.emit('shift', 'Смена открыта');
                    break;
                case 'shiftClosed':
                    ksoEmitter.emit('shift', `Смена закрыта`);
                    break;
                case 'pong':
                    if (pingPongId === data.cmdId)
                        isPingPongResponce = true;
                    break;
                case 'postProductInfo':
                    const { cmdId, price: { value }, data: { externalID }, quantity, name, } = data;
                    ksoEmitter.emit('postProductInfo', {
                        cmdId,
                        name,
                        externalId: externalID,
                        price: value,
                        quantity,
                    });
                    break;
                default:
                    ksoEmitter.emit('error', data);
                    break;
            }
        }
    }
    /** Функция для установления websocket соединения и получения всех первичных и основных данных , кроме меню*/
    function connect(urlWs, ClientProgramValue, ClientNameValue) {
        if (!validateConnectParams(urlWs, ClientNameValue)) {
            return;
        }
        const headers = {
            ClientProgram: ClientProgramValue,
            ClientName: ClientNameValue,
        };
        createWebSocket(urlWs, headers, ClientProgramValue, ClientNameValue);
    }
    exports.connect = connect;
    /** Функция для получения меню КАСУ с помощью HTTP запроса */
    function fetchMenuKASU(urlHttp) {
        if (!urlHttp) {
            ksoEmitter.emit('error', 'Не был передан urlHttp (url для Http соединения - получения меню)');
            return false;
        }
        fetch(urlHttp)
            .then((response) => {
            if (!response.ok) {
                throw new Error('Ошибка HTTP запроса: ' + response.status);
            }
            return response.json();
        })
            .then((data) => {
            dataModule.menuCafeServiceData = data;
            ksoEmitter.emit('menuData', {
                type: 'Menu',
                dataModule: dataModule.menuCafeServiceData,
            });
        })
            .catch((error) => {
            ksoEmitter.emit('error', `HTTP запрос на получение меню не удался: ${error}`);
        });
    }
    exports.fetchMenuKASU = fetchMenuKASU;
    /** Функция создает webSocket и слушает его события */
    function createWebSocket(urlWs, headers, ClientProgramValue, ClientNameValue) {
        // Создаем экземпляр WebSocket
        ws = new WebSocket.client();
        // Обработка события успешного подключения
        ws.on('connect', (connection) => {
            connectionEstablished = true;
            console.log('Успешное подключение');
            connection.on('close', () => {
                console.log('Connection close');
                ksoEmitter.emit('error', `Connection close`);
                ksoEmitter.off('sendMessageKSO', addSendMessage);
                // Переподключение, если произошёл разрыв
                connect(urlWs, ClientProgramValue, ClientNameValue);
            });
            connection.on('error', function (error) {
                winston_1.logger.error(`Ошибка в соединении: ${error.toString()}`);
                ksoEmitter.emit('error', `Ошибка в соединении: ${error.toString()}`);
            });
            connection.on('message', (message) => {
                onMessage(message);
            });
            ksoEmitter.on('sendMessageKSO', (message) => sendMessage(connection, message));
            addSendMessage({ msgType: 'imagesDataAll' });
        });
        // Обработка события неудачного подключения
        ws.on('connectFailed', (error) => {
            connectionEstablished = false;
            winston_1.logger.error(`Ошибка при подключении WebSocket: ${error.toString()}`);
            ksoEmitter.emit('error', `Ошибка при подключении WebSocket: ${error.toString()}`);
        });
        // Подключаемся к WebSocket с настройками
        ws.connect(urlWs, undefined, undefined, headers);
    }
    /** Функция для отправки сообщения на сервер(сразу переделывает в json) */
    function addSendMessage(message) {
        if (!connectionEstablished) {
            console.error('WebSocket-соединение не установлено');
            winston_1.logger.error('WebSocket-соединение не установлено');
            return;
        }
        if (!ws) {
            winston_1.logger.error('WebSocket-соединение не установлено');
            ksoEmitter.emit('error', 'WebSocket-соединение не установлено');
            return;
        }
        const sendMessage = JSON.stringify(message);
        console.log('sendMessage', sendMessage);
        ksoEmitter.emit('sendMessageKSO', sendMessage);
    }
    /** Функция будет проверять переданные параметры на наличие их значений */
    function validateConnectParams(urlWs, valueKCO) {
        if (!urlWs) {
            winston_1.logger.error('Не был передан urlWs (url для WebSocket соединения)');
            ksoEmitter.emit('error', 'Не был передан urlWs (url для WebSocket соединения)');
            return false;
        }
        if (!valueKCO) {
            winston_1.logger.error('Не был передан valueKCO (имя КСО)');
            ksoEmitter.emit('error', 'Не был передан valueKCO (имя КСО)');
            return false;
        }
        return true;
    }
    /** Функция для добавление уникальных ключей в массив*/
    function addIdIfNotExists(id) {
        if (!arrUuidKey.includes(id)) {
            arrUuidKey.push(id);
        }
        else {
            const newId = (0, uuid_1.v4)();
            arrUuidKey.push(newId);
        }
    }
    /** функция для добавления продукта из меню КСО в корзину */
    function addProductToCart(productId, price) {
        const id = (0, uuid_1.v4)();
        addIdIfNotExists(id);
        const objectToBeSent = {
            msgType: 'addProductLine',
            cmdId: id,
            data: {
                productId,
                price,
                inputType: 11, // Взято из протокола КСО-КАСУ
            },
        };
        winston_1.infoLogger.info(JSON.stringify(objectToBeSent), ['request']);
        addSendMessage(objectToBeSent);
    }
    exports.addProductToCart = addProductToCart;
    /** Функция добавления товара с помощью скана */
    function addProductScan(code) {
        const id = (0, uuid_1.v4)();
        addIdIfNotExists(id);
        const objectToBeSent = {
            msgType: 'addProductLineByBarCode',
            cmdId: id,
            data: {
                code,
                inputType: 10, // Взято из протокола КСО-КАСУ
            },
        };
        winston_1.infoLogger.info(JSON.stringify(objectToBeSent), ['request']);
        addSendMessage(objectToBeSent); // Отправляем сообщение на сервер
    }
    exports.addProductScan = addProductScan;
    /** Функция для удаления товара(Идентификатор строки заказа) */
    //? Пока не ясно, это только для топлива или ещё для товаров с кафе, т.к. extChequeId есть в объеках массива arrStateTRK, а это от сообщения сервера fpStatus
    function deleteProduct(chequeLineId) {
        const id = (0, uuid_1.v4)();
        addIdIfNotExists(id);
        const objectToBeSent = {
            msgType: 'deleteLine',
            cmdId: id,
            data: {
                chequeLineId,
            },
        };
        winston_1.infoLogger.info(JSON.stringify(objectToBeSent), ['request']);
        addSendMessage(objectToBeSent);
    }
    exports.deleteProduct = deleteProduct;
    /** Функция для предоплатного налива */
    function addFuelLine(nozzleId, isFuellingInMoney, quantity) {
        var _a;
        const id = (0, uuid_1.v4)();
        if (!dataModule.fuelStationDataData) {
            return null;
        }
        addIdIfNotExists(id);
        // Функция для нахождения id бака с топливом
        function findTankIdById(id) {
            if (!dataModule.fuelStationDataData) {
                return null;
            }
            for (const fps of dataModule.fuelStationDataData.fps) {
                for (const nozzle of fps.nozzles) {
                    if (nozzle.id == id) {
                        return nozzle.tankId;
                    }
                }
            }
            return null; // Если id не найден
        }
        // Здесь определяем сумму, если isFuellingInMoney === true, просто передаём сумму из amountDose, если нет вычисляем объём топливо * цену из ранее полученных данных о ТРК
        let valueSum;
        let finalQuantity;
        const tankId = findTankIdById(nozzleId);
        const priceFuel = (_a = dataModule.fuelStationDataData.tankProducts.find((el) => el.tankId === tankId)) === null || _a === void 0 ? void 0 : _a.product.price;
        if (isFuellingInMoney && priceFuel) {
            valueSum = quantity;
            finalQuantity = (quantity / priceFuel).toFixed(2);
        }
        else {
            if (priceFuel) {
                valueSum = (priceFuel * quantity).toFixed(2);
                finalQuantity = quantity;
            }
        }
        const objectToBeSent = {
            msgType: 'addFuelLine',
            cmdId: id,
            data: {
                nozzleId,
                quantity: finalQuantity,
                amountDose: valueSum,
                isFuellingInMoney,
            },
        };
        winston_1.infoLogger.info(JSON.stringify(objectToBeSent), ['request']);
        addSendMessage(objectToBeSent);
    }
    exports.addFuelLine = addFuelLine;
    /** Функция для постоплатного налива */
    function addPostPayFuel(fpId) {
        const id = (0, uuid_1.v4)();
        addIdIfNotExists(id);
        const objectToBeSent = {
            msgType: 'addPostpayFuel',
            cmdId: id,
            data: {
                fpId,
            },
        };
        winston_1.infoLogger.info(JSON.stringify(objectToBeSent), ['request']);
        addSendMessage(objectToBeSent);
    }
    exports.addPostPayFuel = addPostPayFuel;
    /** Функция для отмены всего заказа (очищает корзину) */
    function cancelOrder() {
        const id = (0, uuid_1.v4)();
        addIdIfNotExists(id);
        const objectToBeSent = {
            msgType: 'cancelOrder',
            cmdId: id,
        };
        winston_1.infoLogger.info(JSON.stringify(objectToBeSent), ['request']);
        addSendMessage(objectToBeSent);
    }
    exports.cancelOrder = cancelOrder;
    /** Функция блокировки ТРК */
    function fpLock(fpId, lockId, nozzleId) {
        const id = (0, uuid_1.v4)();
        addIdIfNotExists(id);
        const objectToBeSent = {
            msgType: 'fpLock',
            cmdId: id,
            data: {
                fpId,
                lockId,
                nozzleId,
            },
        };
        winston_1.infoLogger.info(JSON.stringify(objectToBeSent), ['request']);
        addSendMessage(objectToBeSent);
    }
    exports.fpLock = fpLock;
    /** Функция разблокировки ТРК */
    function fpUnlock(fpId, lockId, nozzleId) {
        const id = (0, uuid_1.v4)();
        addIdIfNotExists(id);
        const objectToBeSent = {
            msgType: 'fpUnlock',
            cmdId: id,
            data: {
                fpId,
                lockId,
                nozzleId,
            },
        };
        winston_1.infoLogger.info(JSON.stringify(objectToBeSent), ['request']);
        addSendMessage(objectToBeSent);
    }
    exports.fpUnlock = fpUnlock;
    /** Функция для подтверждения заказа */
    function acceptOrder(clientPhoneNumber, beeperNumber, takeAway) {
        const id = (0, uuid_1.v4)();
        addIdIfNotExists(id);
        const objectToBeSent = {
            msgType: 'acceptOrder',
            cmdId: id,
            data: {
                clientPhoneNumber,
                beeperNumber,
                takeAway,
            },
        };
        winston_1.infoLogger.info(JSON.stringify(objectToBeSent), ['request']);
        addSendMessage(objectToBeSent);
    }
    exports.acceptOrder = acceptOrder;
    /** Функция для отправки на сервер параметров оплаты заказа
     * @param {number} sellingTypeId - sellingTypeId.
     * @param {boolean} applyDiscount - true если необходимо применить карту лояльности.
     * @param {boolean} isLicardCard - true если оплата топливной картой.
     * @param {string} loyaltyCardNumber - Номер карты лояльности, запрошенной ранее через qr-код.
     * @param {0 | 1 | 2} loyaltyRequestType - Способ считывания qr-кода: 0 – неизвестно, 1 - сканер, 2 – терминал.
     * */
    function startPay(sellingTypeId, applyDiscount, isLicardCard, loyaltyCardNumber, loyaltyRequestType) {
        const id = (0, uuid_1.v4)();
        addIdIfNotExists(id);
        const objectToBeSent = {
            msgType: 'startPay',
            cmdId: id,
            data: {
                sellingTypeId,
                applyDiscount,
                isLicardCard,
                loyaltyCardNumber,
                loyaltyRequestType,
            },
        };
        winston_1.infoLogger.info(JSON.stringify(objectToBeSent), ['request']);
        addSendMessage(objectToBeSent);
    }
    exports.startPay = startPay;
    /** Функция для отправки на сервер сообщение о применении карты лояльности с QR кодом или clientId*/
    function processQrLoyalty({ qrCode, idClient }) {
        const id = (0, uuid_1.v4)();
        addIdIfNotExists(id);
        if (qrCode && idClient) {
            ksoEmitter.emit('error', 'Передан и qrCode и clintId');
            winston_1.logger.error('Передан и qrCode и clintId');
            return;
        }
        const objectToBeSent = {
            msgType: 'processQrLoyalty',
            cmdId: id,
            data: {
                qrCode,
                idClient,
            },
        };
        winston_1.infoLogger.info(JSON.stringify(objectToBeSent), ['request']);
        addSendMessage(objectToBeSent);
    }
    exports.processQrLoyalty = processQrLoyalty;
    /** Функция для отправки на сервер нажатой кнопки(не/подтверждающий списание баллов) */
    function pressedButton(pressButton) {
        if (!dataModule.answerButtons) {
            return;
        }
        const buttonsData = dataModule.answerButtons;
        const choiceButton = buttonsData.data.buttons.find((el) => el.name === pressButton);
        const objectToBeSent = {
            msgType: 'requestCallback',
            cmdId: buttonsData.cmdId,
            data: {
                pressedButton: {
                    name: choiceButton === null || choiceButton === void 0 ? void 0 : choiceButton.name,
                    text: choiceButton === null || choiceButton === void 0 ? void 0 : choiceButton.text,
                    default: choiceButton === null || choiceButton === void 0 ? void 0 : choiceButton.default,
                },
            },
        };
        winston_1.infoLogger.info(JSON.stringify(objectToBeSent), ['request']);
        addSendMessage(objectToBeSent);
    }
    exports.pressedButton = pressedButton;
    /** Функция для отправки на сервер сообщения с введённым кодом
     *  @param {Object} data - Объект
     *  @param {ButtonsOtp} data.pressedButtons - название нажатой кнопки.
     *  @param {number} data.otpCode - OTP код.
     */
    function loyaltyOtpCode(data) {
        const pressedButtons = (data === null || data === void 0 ? void 0 : data.pressedButtons) || "btnContinue" /* ButtonsOtp.BtnContinue */;
        const otpCode = data === null || data === void 0 ? void 0 : data.otpCode;
        const objectToBeSent = {
            msgType: 'loyaltyOtpCode',
            cmdId: crmIdLoyalty,
            data: {
                pressedButton: { name: pressedButtons },
                otpCode,
            },
        };
        winston_1.infoLogger.info(JSON.stringify(objectToBeSent), ['request']);
        addSendMessage(objectToBeSent);
    }
    exports.loyaltyOtpCode = loyaltyOtpCode;
    /** Функция для запроса данных клиента (отправляем qr-лояльности) */
    function getClientData(qrCode) {
        const id = (0, uuid_1.v4)();
        addIdIfNotExists(id);
        const objectToBeSent = {
            msgType: 'getClientData',
            cmdId: id,
            data: {
                qrCode: qrCode,
            },
        };
        winston_1.infoLogger.info(JSON.stringify(objectToBeSent), ['request']);
        addSendMessage(objectToBeSent);
    }
    exports.getClientData = getClientData;
    /** Функция для запроса полученных с КАСУ кнопок (из полученных кнопок отправляем name при помощи функции pressedButton) */
    function getLoyaltyButtons() {
        return dataModule.answerButtons;
    }
    exports.getLoyaltyButtons = getLoyaltyButtons;
    /** Функция для запроса полученных с КАСУ данных о пользователе */
    function getClient() {
        return dataModule.clientData;
    }
    exports.getClient = getClient;
    /** Функция для отмены всего заказа (очищает корзину) */
    function cancelOrderWithRemoveCheckLines() {
        var _a, _b;
        const id = (0, uuid_1.v4)();
        addIdIfNotExists(id);
        const checkLinesId = (_b = (_a = dataModule.basketValue) === null || _a === void 0 ? void 0 : _a.cheque) === null || _b === void 0 ? void 0 : _b.lines.reduce((prev, current) => {
            // if (current.nozzle?.id) {
            //   return prev;
            // }
            prev.push(current.id);
            return prev;
        }, []);
        checkLinesId === null || checkLinesId === void 0 ? void 0 : checkLinesId.forEach((lineId) => {
            deleteProduct(lineId);
        });
        const objectToBeSent = {
            msgType: 'cancelOrder',
            cmdId: id,
        };
        addSendMessage(objectToBeSent);
    }
    exports.cancelOrderWithRemoveCheckLines = cancelOrderWithRemoveCheckLines;
    /** Функция для отмены ожидания сканирования qr */
    function resetTransaction() {
        var _a;
        const objectToBeSent = {
            msgType: 'resetTransaction',
            data: {
                chequeId: (_a = dataModule.basketValue) === null || _a === void 0 ? void 0 : _a.cheque.id,
            },
        };
        addSendMessage(objectToBeSent);
    }
    exports.resetTransaction = resetTransaction;
    function getProductInfo(externalId) {
        const id = (0, uuid_1.v4)();
        const objectToBeSent = {
            msgType: 'getProductInfo',
            cmdId: id,
            data: {
                externalID: externalId,
            },
        };
        addSendMessage(objectToBeSent);
    }
    exports.getProductInfo = getProductInfo;
    /** Функция для удаления топлива из корзины, и восстановления остальных товаров в корзине */
    function cancelOrderAndRecoverBasket() {
        var _a, _b;
        const externalIds = (_b = (_a = dataModule.basketValue) === null || _a === void 0 ? void 0 : _a.cheque) === null || _b === void 0 ? void 0 : _b.lines.reduce((prev, current) => {
            var _a;
            if ((_a = current.nozzle) === null || _a === void 0 ? void 0 : _a.id) {
                return prev;
            }
            prev.push({
                id: current.product.id,
                price: current.product.price,
            });
            return prev;
        }, []);
        sendBucketUpdate = false;
        cancelOrder();
        ksoEmitter === null || ksoEmitter === void 0 ? void 0 : ksoEmitter.once('info', () => {
            const ids = (0, rxjs_1.from)(externalIds || []);
            return ids
                .pipe((0, operators_1.concatMap)(({ id, price }) => __awaiter(this, void 0, void 0, function* () {
                addProductToCart(id, price);
                yield waitBucketUpdateWithStatusTwo();
                (0, rxjs_1.catchError)((err) => {
                    return (0, rxjs_1.of)({ id, price });
                });
                (0, operators_1.timeout)(200);
            })), (0, operators_1.finalize)(() => {
                sendBucketUpdate = true;
            }))
                .subscribe();
        });
    }
    exports.cancelOrderAndRecoverBasket = cancelOrderAndRecoverBasket;
    function waitBucketUpdateWithStatusTwo() {
        return (0, rxjs_1.fromEvent)(ksoEmitter, 'info')
            .pipe((0, operators_1.filter)((value) => {
            return value === 5;
        }), (0, operators_1.take)(1))
            .toPromise();
    }
    function setPingPongEnabled(enabled) {
        isPingPongEnabled = enabled;
    }
    exports.setPingPongEnabled = setPingPongEnabled;
    new cron_1.CronJob('0,30 * * * * *', () => {
        if (isPingPongEnabled) {
            const id = (0, uuid_1.v4)();
            const objectToBeSent = {
                msgType: 'ping',
                cmdId: id,
                data: null,
            };
            pingPongId = id;
            isPingPongResponce = false;
            addSendMessage(objectToBeSent);
        }
    }, null, true);
    new cron_1.CronJob('15,45 * * * * *', () => {
        if (isPingPongEnabled) {
            if (!isPingPongResponce) {
                winston_1.logger.error(`Касу не ответило на ping`);
                ksoEmitter.emit('ping', `Касу не ответило на ping`);
            }
            else {
                winston_1.logger.error(`Касу ответило на ping`);
                ksoEmitter.emit('ping', `Касу ответило на ping`);
            }
        }
    }, null, true);
});
