/*
  Сервис интеграции ПП Парус 8 с WEB API    
  Модуль ядра: обработчик mqtt сообщений
*/

//----------------------
// Подключение библиотек
//----------------------

const { makeErrorText } = require("./utils"); //Вспомогательные функции
const mqtt = require("mqtt"); //Работа с MQTT
const { SERR_MQTT, SINFO_MQTT } = require("./constants"); //Глобальные константы

//----------
// Константы
//----------

//Общие константы работы MQTT
const SLOG_ERROR = "ERROR"; //Уровень протоколирования - ошибки
const SLOG_INFO = "INFO"; //Уровень протоколирования - информация

//------------
// Тело модуля
//------------

//Отправка MQTT сообщения
const publishMQTT = async ({ settings, url, auth, topic, message, logger }) => {
    //Инициализируем подключение
    const client = await mqtt.connectAsync(url, {
        clientId: settings.sClientIdSender,
        clean: true,
        connectTimeout: settings.nConnectTimeout,
        username: auth.user,
        password: auth.pass,
        reconnectPeriod: settings.nReconnectPeriod
    });
    //Прослушиваем ошибки
    client.on("error", e => {
        //Если требуется выдавать ошибку
        if ([SLOG_ERROR, SLOG_INFO].includes(settings.sLogLevel)) {
            //Выводим ошибку
            logger.error(`${SERR_MQTT}: ${makeErrorText(e)}`);
        }
    });
    //Отправляем сообщение
    await client.publishAsync(topic, message);
    //Закрываем подключение
    await client.endAsync();
    //Возвращаем статус успешной отправки
    return { statusCode: 200 };
};

//Получение MQTT сообщений
const subscribeMQTT = async ({ settings, service, processMessage, logger }) => {
    try {
        //Инициализируем строку подключения
        let sBroker = service.sSrvRoot;
        //Инициализируем подключение
        const client = await mqtt.connectAsync(sBroker, {
            clientId: settings.sClientIdRecipient,
            clean: true,
            connectTimeout: settings.nConnectTimeout,
            username: service.sSrvUser,
            password: service.sSrvPass,
            reconnectPeriod: settings.nReconnectPeriod
        });
        //Обходим функции сервиса
        service.functions.forEach(fn => {
            client.subscribe(fn.sFnURL);
        });
        //Прослушиваем сообщения
        client.on("message", (topic, message) => {
            //Обрабатываем сообщение
            processMessage({
                message: { value: message, headers: {} },
                service,
                fn: service.functions.find(fn => {
                    return fn.sFnURL === topic;
                })
            });
        });
        //Прослушиваем отключение от сервера
        client.on("offline", () => {
            //Если требуется выдавать ошибку
            if (settings.sLogLevel === SLOG_INFO) {
                //Выводим ошибку
                logger.error(`${SERR_MQTT}: Соединение потеряно (${sBroker})`);
            }
        });
        //Прослушиваем восстановление соединения
        client.on("connect", () => {
            //Если требуется выдавать предупреждение
            if (settings.sLogLevel === SLOG_INFO) {
                //Сообщим о восстановлении соединения
                logger.info(`${SINFO_MQTT}: Соединение восстановлено (${sBroker})`);
            }
        });
        //Прослушиваем ошибки
        client.on("error", e => {
            //Если требуется выдавать ошибку
            if ([SLOG_ERROR, SLOG_INFO].includes(settings.sLogLevel)) {
                //Выводим ошибку
                logger.error(`${SERR_MQTT}: ${makeErrorText(e)}`);
            }
        });
        //Возвращаем подключение
        return client;
    } catch (e) {
        logger.error(`${SERR_MQTT}: Ошибка запуска обработчика очереди входящих сообщений: ${makeErrorText(e)}`);
    }
};

//-----------------
// Интерфейс модуля
//-----------------

exports.publishMQTT = publishMQTT;
exports.subscribeMQTT = subscribeMQTT;
