"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
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());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.botSendMessage = exports.mediaTypeWhatsappOfficial = exports.isValidMsg = exports.verifyContact = exports.verifyMediaMessage = exports.verifyMessage = exports.lst = exports.handleMsgAck = exports.handleMessage = exports.wbotMessageListener = void 0;
const path_1 = require("path");
const util_1 = require("util");
const fs_1 = require("fs");
const Sentry = __importStar(require("@sentry/node"));
const TicketConfig_1 = require("../../helpers/TicketConfig");
const Contact_1 = __importDefault(require("../../models/Contact"));
const Message_1 = __importDefault(require("../../models/Message"));
const socket_1 = require("../../libs/socket");
const CreateMessageService_1 = __importDefault(require("../MessageServices/CreateMessageService"));
const logger_1 = require("../../utils/logger");
const CreateOrUpdateContactService_1 = __importDefault(require("../ContactServices/CreateOrUpdateContactService"));
const FindOrCreateTicketService_1 = __importDefault(require("../TicketServices/FindOrCreateTicketService"));
const ShowWhatsAppService_1 = __importDefault(require("../WhatsappService/ShowWhatsAppService"));
const Debounce_1 = require("../../helpers/Debounce");
const UpdateTicketService_1 = __importDefault(require("../TicketServices/UpdateTicketService"));
const ShowQueueService_1 = __importDefault(require("../QueueService/ShowQueueService"));
const BotIsOnQueue_1 = __importDefault(require("../../helpers/BotIsOnQueue"));
const ura_final_message_1 = __importDefault(require("./ura_final_message"));
const SendWhatsAppMessage_1 = __importDefault(require("./SendWhatsAppMessage"));
const Whatsapp_1 = __importDefault(require("../../models/Whatsapp"));
const SendWhatsappMessageSocket_1 = __importDefault(require("../../helpers/SendWhatsappMessageSocket"));
const WhatsappIdMultiSessionControl_1 = require("../../helpers/WhatsappIdMultiSessionControl");
const AppError_1 = __importDefault(require("../../errors/AppError"));
const SetMessageAsRead_1 = require("../../helpers/SetMessageAsRead");
const WhaticketSettings_1 = require("../../helpers/WhaticketSettings");
const MostRepeatedPhrase_1 = __importDefault(require("../../helpers/MostRepeatedPhrase"));
const RedisClient_1 = require("../../helpers/RedisClient");
const FindOrCreateTicketServiceBot_1 = __importDefault(require("../TicketServices/FindOrCreateTicketServiceBot"));
const ShowTicketService_1 = __importDefault(require("../TicketServices/ShowTicketService"));
const ListWhatsappQueuesByUserQueue_1 = __importDefault(require("../UserServices/ListWhatsappQueuesByUserQueue"));
const CreateContactService_1 = __importDefault(require("../ContactServices/CreateContactService"));
const AssociateContatctQueue_1 = __importDefault(require("../ContactServices/AssociateContatctQueue"));
const ContactQueues_1 = __importDefault(require("../../models/ContactQueues"));
var lst = WhatsappIdMultiSessionControl_1.getWhatsappIds();
exports.lst = lst;
const writeFileAsync = util_1.promisify(fs_1.writeFile);
const verifyContact = (msgContact, whatsAppOfficial) => __awaiter(void 0, void 0, void 0, function* () {
    let contactData = {};
    if (msgContact) {
        contactData = {
            name: msgContact.name || msgContact.pushname || msgContact.id.user,
            number: msgContact.id.user,
            profilePicUrl: msgContact.getProfilePicUrl,
            isGroup: msgContact.isGroup
        };
    }
    else {
        contactData = {
            name: (whatsAppOfficial === null || whatsAppOfficial === void 0 ? void 0 : whatsAppOfficial.name) ? whatsAppOfficial.name
                : whatsAppOfficial.number,
            number: whatsAppOfficial.number,
            isGroup: false
        };
    }
    const contact = CreateOrUpdateContactService_1.default(contactData);
    return contact;
});
exports.verifyContact = verifyContact;
const verifyQuotedMessage = (msg, _quotedMsg) => __awaiter(void 0, void 0, void 0, function* () {
    if (!msg.hasQuotedMsg)
        return null;
    // const wbotQuotedMsg = await msg.getQuotedMessage();
    const wbotQuotedMsg = _quotedMsg;
    const quotedMsg = yield Message_1.default.findOne({
        where: { id: wbotQuotedMsg.id.id }
    });
    if (!quotedMsg)
        return null;
    return quotedMsg;
});
const verifyMediaMessage = (msg, ticket, contact, media, quotedMsg) => __awaiter(void 0, void 0, void 0, function* () {
    var _a;
    if (!media) {
        throw new Error("ERR_WAPP_DOWNLOAD_MEDIA");
    }
    let mediaAuthorized = true;
    let messageData = {
        id: msg.id.id,
        ticketId: ticket.id,
        contactId: msg.fromMe ? undefined : contact.id,
        body: msg.body || media.filename,
        fromMe: msg.fromMe,
        read: msg.fromMe,
        mediaUrl: media.filename,
        mediaType: media.mimetype.split("/")[0],
        quotedMsgId: quotedMsg,
        phoneNumberId: msg === null || msg === void 0 ? void 0 : msg.phoneNumberId,
        fromAgent: false
    };
    if (messageData.mediaType === 'video' || messageData.mediaType === 'audio' && ((_a = WhaticketSettings_1.getSettingValue('blockAudioVideoMedia')) === null || _a === void 0 ? void 0 : _a.value) === 'enabled') {
        mediaAuthorized = false;
    }
    if (msg === null || msg === void 0 ? void 0 : msg.fromMe) {
        messageData = Object.assign(Object.assign({}, messageData), { fromAgent: true });
    }
    if (!(ticket === null || ticket === void 0 ? void 0 : ticket.phoneNumberId)) {
        if (!media.filename) {
            const ext = media.mimetype.split("/")[1].split(";")[0];
            media.filename = `${new Date().getTime()}.${ext}`;
            messageData = Object.assign(Object.assign({}, messageData), { mediaUrl: media.filename, body: media.filename });
        }
        if (mediaAuthorized) {
            try {
                yield writeFileAsync(path_1.join(__dirname, "..", "..", "..", "..", "..", "public", media.filename), media.data, "base64");
            }
            catch (err) {
                Sentry.captureException(err);
                logger_1.logger.error(`There was an error: wbotMessageLitener.ts: ${err}`);
            }
        }
    }
    if (mediaAuthorized) {
        yield ticket.update({ lastMessage: msg.body || media.filename });
        const newMessage = yield CreateMessageService_1.default({ messageData });
        return newMessage;
    }
    else {
        if (ticket.status !== "queueChoice") {
            botSendMessage(ticket, `Atenção! Mensagem ignorada, tipo de mídia não suportado.`);
        }
        messageData.body = `Mensagem de *${messageData.mediaType}* ignorada, tipo de mídia não suportado.`;
        messageData.mediaUrl = '';
        yield ticket.update({ lastMessage: `Mensagem de *${messageData.mediaType}* ignorada, tipo de mídia não suportado.` });
        const newMessage = yield CreateMessageService_1.default({ messageData });
        console.log(`--------->>> Mensagem do tipo: ${messageData.mediaType}, ignorada!`);
    }
});
exports.verifyMediaMessage = verifyMediaMessage;
// const verifyMediaMessage = async (
//   msg: any,
//   ticket: Ticket,
//   contact: Contact,
//   media: any,
//   quotedMsg?: any
// ): Promise<Message | any> => {
//   // const quotedMsg = await verifyQuotedMessage(msg);
//   // const media = await msg.downloadMedia();
//   if (!media) {
//     throw new Error("ERR_WAPP_DOWNLOAD_MEDIA");
//   }
//   console.log(
//     "MEDIA.FILENAME: ",
//     media.fileName,
//     "  |  msg.fromMe: ",
//     msg.fromMe
//   );
//   if (!media.filename) {
//     console.log("No file name -----------------------------------------");
//     const ext = media.mimetype.split("/")[1].split(";")[0];
//     media.filename = `${new Date().getTime()}.${ext}`;
//   }
//   try {
//     // await writeFileAsync(
//     //   join(__dirname, "..", "..", "..", "public", media.filename),
//     //   media.data,
//     //   "base64"
//     // );
//     console.log("FROM wbotMessageListener.ts media.filename: ", media.filename);
//     await writeFileAsync(
//       join(__dirname, "..", "..", "..", "..", "..", "public", media.filename),
//       media.data,
//       "base64"
//     );
//   } catch (err) {
//     Sentry.captureException(err);
//     logger.error(`There was an error: wbotMessageLitener.ts: ${err}`);
//   }
//   const messageData = {
//     id: msg.id.id,
//     ticketId: ticket.id,
//     contactId: msg.fromMe ? undefined : contact.id,
//     body: msg.body || media.filename,
//     fromMe: msg.fromMe,
//     read: msg.fromMe,
//     mediaUrl: media.filename,
//     mediaType: media.mimetype.split("/")[0],
//     quotedMsgId: quotedMsg
//     // quotedMsgId: quotedMsg?.id
//   };
//   await ticket.update({ lastMessage: msg.body || media.filename });
//   const newMessage = await CreateMessageService({ messageData });
//   return newMessage;
// };
const verifyMessage = (msg, ticket, contact, quotedMsg) => __awaiter(void 0, void 0, void 0, function* () {
    var _b, _c;
    let messageData = {
        id: msg.id.id,
        ticketId: ticket.id,
        contactId: msg.fromMe ? undefined : contact.id,
        body: msg.body,
        fromMe: msg.fromMe,
        fromAgent: false,
        mediaType: msg.type,
        read: msg.fromMe,
        quotedMsgId: quotedMsg,
        phoneNumberId: msg === null || msg === void 0 ? void 0 : msg.phoneNumberId
    };
    if (msg === null || msg === void 0 ? void 0 : msg.fromMe) {
        const botInfo = yield BotIsOnQueue_1.default("botqueue");
        if (botInfo.isOnQueue) {
            const ura = yield RedisClient_1.get({ key: "ura" });
            if (ura && !ura.includes(JSON.stringify(msg === null || msg === void 0 ? void 0 : msg.body))) {
                messageData = Object.assign(Object.assign({}, messageData), { fromAgent: true });
            }
        }
        else if (((_b = msg === null || msg === void 0 ? void 0 : msg.body) === null || _b === void 0 ? void 0 : _b.trim().length) > 0 && !/\u200e/.test(msg.body[0])) {
            messageData = Object.assign(Object.assign({}, messageData), { fromAgent: true });
        }
    }
    yield ticket.update({ lastMessage: msg.body });
    if (!(msg === null || msg === void 0 ? void 0 : msg.fromMe) && (msg === null || msg === void 0 ? void 0 : msg.vCards) && ((_c = msg === null || msg === void 0 ? void 0 : msg.vCards) === null || _c === void 0 ? void 0 : _c.length) > 0) {
        if (msg.vCards.length == 1) {
            messageData = Object.assign(Object.assign({}, messageData), { body: msg.vCards[0] });
        }
        else {
            messageData = Object.assign(Object.assign({}, messageData), { body: JSON.stringify(msg.vCards) });
        }
    }
    yield CreateMessageService_1.default({ messageData });
});
exports.verifyMessage = verifyMessage;
const verifyQueue = (wbot, msg, ticket, contact) => __awaiter(void 0, void 0, void 0, function* () {
    const { queues, greetingMessage } = yield ShowWhatsAppService_1.default(wbot.id);
    let selectedOption = null;
    let choosenQueue = null;
    //Habilitar esse caso queira usar o bot
    const botInfo = yield BotIsOnQueue_1.default("botqueue");
    // const botInfo = { isOnQueue: false, botQueueId: 0, userIdBot: 0 };
    if (botInfo.isOnQueue) {
        choosenQueue = yield ShowQueueService_1.default(botInfo.botQueueId);
    }
    else if (queues.length === 1) {
        selectedOption = 1;
        choosenQueue = queues[+selectedOption - 1];
    }
    else {
        selectedOption = msg === null || msg === void 0 ? void 0 : msg.body;
        if (selectedOption && selectedOption.trim().length > 0) {
            //////////////// EXTRAIR APENAS O NÚMERO ///////////////////
            selectedOption = selectedOption.match(/\d+/);
            ///////////////////////////////////
            if (selectedOption)
                choosenQueue = queues[+selectedOption - 1];
        }
    }
    if (choosenQueue) {
        // Atualizando o status do ticket para mostrar notificação para o atendente da fila escolhida pelo usuário. De queueChoice para pending
        if (queues.length > 1 && !botInfo.isOnQueue) {
            yield ticket.update({ status: "pending" });
        }
        //
        yield UpdateTicketService_1.default({
            ticketData: { queueId: choosenQueue.id },
            ticketId: ticket.id
        });
        let botOptions = "";
        // O bot abre a mensagem na fila para atender o usuario
        if (botInfo.isOnQueue) {
            yield UpdateTicketService_1.default({
                ticketData: { status: "open", userId: botInfo.userIdBot },
                ticketId: ticket.id
            });
            const data = yield RedisClient_1.get({ key: "ura", parse: true });
            yield RedisClient_1.createObject({
                whatsappId: `${ticket.whatsappId}`,
                contactId: `${ticket.contactId}`,
                identifier: "ura",
                value: data[1].id,
                history: `|${data[1].id}`
            });
            botSendMessage(ticket, data[1].value);
            return;
        }
        //
        yield assingContactByQueue(ticket, choosenQueue.id);
        let whatsapp = yield whatsappInfo(ticket === null || ticket === void 0 ? void 0 : ticket.whatsappId);
        const outService = yield outOfService(whatsapp === null || whatsapp === void 0 ? void 0 : whatsapp.number);
        if (outService.length > 0) {
            const { type, msg: msgOutService } = outService[0];
            console.log(`${type} message ignored on queue`);
            botSendMessage(ticket, `\u200e${msgOutService}`);
            return;
        }
        let body = "";
        const io = socket_1.getIO();
        if (botOptions.length > 0) {
            body = `\u200e${choosenQueue.greetingMessage}\n\n${botOptions}\n${ura_final_message_1.default.msg}`;
        }
        else {
            body = `\u200e${choosenQueue.greetingMessage}`;
        }
        io.emit('notifyPeding', { data: { ticket, queue: choosenQueue } });
        SendWhatsappMessageSocket_1.default(ticket, body);
    }
    else {
        //test del transfere o  atendimento se entrar na ura infinita
        const repet = yield MostRepeatedPhrase_1.default(ticket.id);
        if (repet.occurrences > 5) {
            yield UpdateTicketService_1.default({
                ticketData: { status: "pending", queueId: queues[0].id },
                ticketId: ticket.id
            });
            yield SendWhatsAppMessage_1.default({
                body: `Seu atendimento foi transferido para um agente!
        `,
                ticket,
                number: `${contact.number}@c.us`
            });
        }
        else {
            let options = "";
            queues.forEach((queue, index) => {
                options += `*${index + 1}* - ${queue.name}\n`;
            });
            const body = `\u200e${greetingMessage}\n${options}`;
            const { phoneNumberId } = ticket;
            const debouncedSentMessage = Debounce_1.debounce(() => __awaiter(void 0, void 0, void 0, function* () {
                SendWhatsappMessageSocket_1.default(ticket, body);
            }), phoneNumberId ? 0 : 3000, ticket.id);
            debouncedSentMessage();
        }
    }
});
const mediaTypeWhatsappOfficial = (mimetype) => {
    const document = [
        "text/plain",
        "text/csv",
        "application/pdf",
        "application/vnd.ms-powerpoint",
        "application/msword",
        "application/vnd.ms-excel",
        "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        "application/vnd.openxmlformats-officedocument.presentationml.presentation",
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    ];
    const image = ["image/jpeg", "image/png"];
    const video = ["video/mp4", "video/3gp"];
    const sticker = ["image/webp"];
    const audio = [
        "audio/mp3",
        "audio/aac",
        "audio/mp4",
        "audio/mpeg",
        "audio/amr",
        "audio/ogg"
    ];
    const types = [
        { name: "document", values: document, mbMaxSize: 15 },
        { name: "image", values: image, mbMaxSize: 5 },
        { name: "video", values: video, mbMaxSize: 15 },
        { name: "sticker", values: sticker, mbMaxSize: 0.5 },
        { name: "audio", values: audio, mbMaxSize: 15 }
    ];
    for (let i in types) {
        if (types[i].values.includes(mimetype)) {
            return { type: types[i].name, mbMaxSize: types[i].mbMaxSize };
        }
    }
    return { type: null, mbsize: 0 };
};
exports.mediaTypeWhatsappOfficial = mediaTypeWhatsappOfficial;
const isValidMsg = (msg) => {
    if (msg.from === "status@broadcast")
        return false;
    if (msg.type === "template" ||
        msg.type === "text" ||
        msg.type === "hsm" ||
        msg.type === "chat" ||
        msg.type === "audio" ||
        msg.type === "ptt" ||
        msg.type === "video" ||
        msg.type === "image" ||
        msg.type === "document" ||
        msg.type === "vcard" ||
        msg.type === "multi_vcard" ||
        msg.type === "sticker")
        return true;
    return false;
};
exports.isValidMsg = isValidMsg;
const queuesOutBot = (wbot, botId) => __awaiter(void 0, void 0, void 0, function* () {
    const { queues, greetingMessage } = yield ShowWhatsAppService_1.default(wbot.id);
    const indexQueue = queues.findIndex(q => q.id == botId);
    if (indexQueue != -1) {
        queues.splice(indexQueue, 1);
    }
    return { queues, greetingMessage };
});
const transferTicket = (queueName, wbot, ticket, sendGreetingMessage) => __awaiter(void 0, void 0, void 0, function* () {
    const botInfo = yield BotIsOnQueue_1.default("botqueue");
    const io = socket_1.getIO();
    const queuesWhatsGreetingMessage = yield queuesOutBot(wbot, botInfo.botQueueId);
    let queue;
    const queues = queuesWhatsGreetingMessage.queues;
    if (typeof queueName == "string") {
        queue = queues.find((q) => { var _a; return ((_a = q === null || q === void 0 ? void 0 : q.name) === null || _a === void 0 ? void 0 : _a.toLowerCase()) == queueName.trim().toLowerCase(); });
    }
    else if (typeof queueName == "number") {
        queue = queues[queueName];
    }
    if (queue) {
        yield assingContactByQueue(ticket, queue.id);
        yield botTransferTicket(queue, ticket, sendGreetingMessage);
    }
    io.emit("notifyPeding", { data: { ticket, queue } });
});
const botTransferTicket = (queues, ticket, sendGreetingMessage) => __awaiter(void 0, void 0, void 0, function* () {
    var _d;
    yield ticket.update({ userId: null });
    yield UpdateTicketService_1.default({
        ticketData: { status: "pending", queueId: queues.id },
        ticketId: ticket.id
    });
    if (sendGreetingMessage && ((_d = queues === null || queues === void 0 ? void 0 : queues.greetingMessage) === null || _d === void 0 ? void 0 : _d.length) > 0) {
        botSendMessage(ticket, queues.greetingMessage);
    }
});
const botTransferTicketToUser = (userId, ticket, queueId) => __awaiter(void 0, void 0, void 0, function* () {
    console.log("USER ID: ", userId);
    // await ticket.update({ userId: userId });
    yield UpdateTicketService_1.default({
        ticketData: { status: "open", userId, queueId },
        ticketId: ticket.id
    });
});
const botSendMessage = (ticket, msg) => {
    const { phoneNumberId } = ticket;
    const debouncedSentMessage = Debounce_1.debounce(() => __awaiter(void 0, void 0, void 0, function* () {
        yield SendWhatsAppMessage_1.default({ body: msg, ticket });
    }), phoneNumberId ? 0 : 3000, ticket.id);
    debouncedSentMessage();
};
exports.botSendMessage = botSendMessage;
const _clear_lst = () => {
    console.log("THE lst.length: ", lst.length);
    if (lst.length <= 199)
        return;
    const chunk = Math.floor(lst.length / 2);
    exports.lst = lst = lst.slice(chunk, chunk + lst.length);
    let whatsappIdsSplited = lst.map(e => `${e.id}`).toString();
    WhatsappIdMultiSessionControl_1.setWhatsappId(whatsappIdsSplited, true);
};
const handleMessage = (msg, wbot, whatsAppOfficial) => __awaiter(void 0, void 0, void 0, function* () {
    var _e;
    if (!whatsAppOfficial) {
        _clear_lst();
        let index = lst.findIndex((x) => x.id == msg.id.id);
        console.log("INDEX: ", index);
        if (index == -1) {
            lst.push({ id: msg.id.id });
            WhatsappIdMultiSessionControl_1.setWhatsappId(msg.id.id);
        }
        else {
            console.log("IGNORED ID: ", msg.id.id);
            return;
        }
    }
    if (!isValidMsg(msg)) {
        return;
    }
    try {
        let msgContact = wbot.msgContact;
        // let groupContact: Contact | undefined;
        if (msg.fromMe) {
            // messages sent automatically by wbot have a special character in front of it
            // if so, this message was already been stored in database;
            if (/\u200e/.test(msg.body[0]))
                return;
            // media messages sent from me from cell phone, first comes with "hasMedia = false" and type = "image/ptt/etc"
            // in this case, return and let this message be handled by "media_uploaded" event, when it will have "hasMedia = true"
            if (!msg.hasMedia &&
                msg.type !== "chat" &&
                msg.type !== "vcard" &&
                msg.type !== "multi_vcard")
                return;
        }
        else {
            console.log(`\n <<<<<<<<<< RECEIVING MESSAGE: 
      Parcial msg and msgContact info: 
      msgContact.name: ${msgContact.name}
      msgContact.pushname: ${msgContact.pushname}
      msgContact.shortName: ${msgContact.shortName}
      msg.id.fromMe: ${msg.id.fromMe}
      msg.id.id: ${msg.id.id}
      msg.body: ${msg.body}
      msg.type: ${msg.type}
      msg.from: ${msg.from}
      msg.to: ${msg.to}\n`);
        }
        const chat = wbot.chat;
        // if(chat.isGroup){
        //   console.log('This message is from a Group and will be ignored!')
        //   return
        // }
        // console.log('----------> chat: ', JSON.parse(JSON.stringify(chat)))
        // if (chat.isGroup) {
        //   let msgGroupContact;
        //   if (msg.fromMe) {
        //     msgGroupContact = await wbot.getContactById(msg.to);
        //   } else {
        //     msgGroupContact = await wbot.getContactById(msg.from);
        //   }
        //   groupContact = await verifyContact(msgGroupContact);
        // }
        const whatsapp = yield ShowWhatsAppService_1.default(wbot.id);
        const unreadMessages = msg.fromMe ? 0 : chat.unreadCount;
        const contact = !whatsAppOfficial
            ? yield verifyContact(msgContact)
            : yield verifyContact(null, {
                number: wbot.msgContact.number,
                name: wbot.msgContact.name
            });
        if (unreadMessages === 0 &&
            whatsapp.farewellMessage &&
            whatsapp.farewellMessage === msg.body)
            return;
        let ticket;
        const _botInfo = yield BotIsOnQueue_1.default("botqueue");
        if (_botInfo.isOnQueue) {
            let ticket_obj = yield FindOrCreateTicketServiceBot_1.default(contact, wbot.id, unreadMessages
            // groupContact
            );
            ticket = ticket_obj.ticket;
            if (ticket_obj.created) {
                let queue = yield ShowQueueService_1.default(_botInfo.botQueueId);
                yield UpdateTicketService_1.default({
                    ticketData: { queueId: queue.id },
                    ticketId: ticket.id
                });
                ticket = yield ShowTicketService_1.default(ticket.id);
            }
        }
        else {
            ticket = yield FindOrCreateTicketService_1.default(contact, wbot.id, unreadMessages
            // groupContact
            );
        }
        if (((_e = WhaticketSettings_1.getSettingValue("oneContactChatWithManyWhats")) === null || _e === void 0 ? void 0 : _e.value) == "disabled") {
            // Para responder para o cliente pelo mesmo whatsapp que ele enviou a mensagen
            if (wbot.id != ticket.whatsappId) {
                try {
                    yield ticket.update({ whatsappId: wbot.id });
                }
                catch (error) {
                    console.error("===> Error on wbotMessageListener.ts into handleMessage fuction file: \n", error);
                    throw new AppError_1.default(error.message);
                }
            }
            //
        }
        if (msg.hasMedia) {
            yield verifyMediaMessage(msg, ticket, contact, wbot.media, wbot.quotedMsg);
        }
        else {
            // console.log('>>>>>>> msg.fromMe: ',msg.fromMe )
            yield verifyMessage(msg, ticket, contact, wbot.quotedMsg);
        }
        if (!ticket.queue &&
            !chat.isGroup &&
            !msg.fromMe &&
            !ticket.userId &&
            whatsapp.queues.length >= 1) {
            yield verifyQueue(wbot, msg, ticket, contact);
        }
        if (msg.type === "vcard" || msg.type === "multi_vcard") {
            yield vcard(msg);
        }
        const botInfo = yield BotIsOnQueue_1.default("botqueue");
        // Transfer to agent
        // O bot interage com o cliente e encaminha o atendimento para fila de atendende quando o usuário escolhe a opção falar com atendente
        if (!msg.fromMe &&
            ((ticket.status == "open" &&
                botInfo &&
                ticket.userId == +botInfo.userIdBot) ||
                ticket.status == "pending" ||
                ticket.status == "queueChoice")) {
            const filteredUsers = yield RedisClient_1.findByContain("user:*", "name", msg === null || msg === void 0 ? void 0 : msg.body);
            if (filteredUsers && filteredUsers.length > 0) {
                if (botInfo.isOnQueue) {
                    transferTicket(filteredUsers[0].name, wbot, ticket, true);
                    return;
                }
                const whatsappQueues = yield ListWhatsappQueuesByUserQueue_1.default(+filteredUsers[0].id);
                const obj = whatsappQueues.find((ob) => ob.whatsappId == wbot.id);
                if (obj) {
                    yield botTransferTicketToUser(+filteredUsers[0].id, ticket, +obj.queueId);
                    yield botSendMessage(ticket, `Você foi transferido para falar com o agente ${filteredUsers[0].name}, aguarde.`);
                }
                return;
            }
        }
        //
        if (botInfo.isOnQueue &&
            !msg.fromMe &&
            ticket.userId == botInfo.userIdBot) {
            const repet = yield MostRepeatedPhrase_1.default(ticket.id);
            console.log("repet.occurrences: ", repet.occurrences);
            if (repet.occurrences > 10) {
                yield transferTicket(0, wbot, ticket);
                yield SendWhatsAppMessage_1.default({
                    body: `Seu atendimento foi transferido para um agente!\n\nPara voltar ao menu principal digite *0*
        `,
                    ticket,
                    number: `${contact.number}@c.us`
                });
            }
            else {
                console.log("MSG body: ", msg.body);
                if (msg.type != "chat") {
                    botSendMessage(ticket, `Desculpe, nao compreendi!\nEnvie apenas texto quando estiver interagindo com o bot!\n _Digite *0* para voltar ao menu principal._`);
                    return;
                }
                if (msg.type == "chat" && String(msg.body).length > 120) {
                    botSendMessage(ticket, `Desculpe, nao compreendi!\nTexto acima de 120 caracteres!\n _Digite *0* para voltar ao menu principal._`);
                    return;
                }
                const menuMsg = yield menu(msg.body, wbot.id, contact.id);
                console.log("menuMsg: ", menuMsg);
                yield botSendMessage(ticket, menuMsg.value);
                if ((menuMsg === null || menuMsg === void 0 ? void 0 : menuMsg.transferToQueue) &&
                    menuMsg.transferToQueue.trim().length > 0) {
                    transferTicket(menuMsg.transferToQueue.trim(), wbot, ticket);
                }
            }
            return;
        }
        else if (!msg.fromMe &&
            msg.body == "0" &&
            ticket.status == "pending" &&
            ticket.queueId) {
            if (botInfo.isOnQueue) {
                let choosenQueue = yield ShowQueueService_1.default(botInfo.botQueueId);
                yield UpdateTicketService_1.default({
                    ticketData: {
                        status: "open",
                        userId: botInfo.userIdBot,
                        queueId: choosenQueue.id
                    },
                    ticketId: ticket.id
                });
                const menuMsg = yield menu(msg.body, wbot.id, contact.id);
                yield botSendMessage(ticket, menuMsg.value);
            }
            return;
        }
        else if (!msg.fromMe &&
            msg.body == "#" &&
            ticket.status == "pending" &&
            ticket.queueId &&
            botInfo.isOnQueue) {
            let choosenQueue = yield ShowQueueService_1.default(botInfo.botQueueId);
            yield UpdateTicketService_1.default({
                ticketData: {
                    status: "open",
                    userId: botInfo.userIdBot,
                    queueId: choosenQueue.id
                },
                ticketId: ticket.id
            });
            const menuMsg = yield menu(msg.body, wbot.id, contact.id);
            yield botSendMessage(ticket, menuMsg.value);
            // return;
        }
        if (msg && !msg.fromMe && ticket.status == "pending") {
            yield SetMessageAsRead_1.setMessageAsRead(ticket);
        }
        let ticketHasQueue = false;
        if (ticket === null || ticket === void 0 ? void 0 : ticket.queueId) {
            ticketHasQueue = true;
        }
        if (ticketHasQueue && ticket.status != "open") {
            let whatsapp = yield whatsappInfo(ticket === null || ticket === void 0 ? void 0 : ticket.whatsappId);
            const outService = yield outOfService(whatsapp.number);
            if (outService.length > 0) {
                const { type, msg: msgOutService } = outService[0];
                if (msg.fromMe && msgOutService == msg.body) {
                    console.log(`${type} message ignored`);
                    return;
                }
                botSendMessage(ticket, `\u200e${msgOutService}`);
                return;
            }
        }
    }
    catch (err) {
        Sentry.captureException(err);
        console.log("Error handling whatsapp message: Err: ", err);
        logger_1.logger.error(`Error handling whatsapp message: Err: ${err}`);
    }
});
exports.handleMessage = handleMessage;
const menu = (userTyped, whatsappId, contactId) => __awaiter(void 0, void 0, void 0, function* () {
    let lastId = yield RedisClient_1.findObject(whatsappId, contactId, "ura");
    const data = yield RedisClient_1.get({ key: "ura", parse: true });
    console.log("lastId[0]: ", lastId[0]);
    if (!lastId[0]) {
        yield RedisClient_1.createObject({
            whatsappId,
            contactId,
            identifier: "ura",
            value: data[1].id,
            history: `|${data[1].id}`
        });
    }
    lastId = yield RedisClient_1.findObject(whatsappId, contactId, "ura");
    console.log("LAST ID: ", lastId);
    let option;
    if (lastId &&
        (lastId.length == 4 || lastId.length == 5) &&
        lastId[3] &&
        lastId[3].trim().length > 0) {
        option = data.find((o) => o.idmaster == lastId[3] &&
            o.value.toLowerCase() == userTyped.toLowerCase());
        if (!option && userTyped != "0" && userTyped != "#") {
            if (!existSubMenu()) {
                const response = yield mainOptionsMenu(userTyped);
                if (response)
                    return response;
                else {
                    let uraOptionSelected = yield RedisClient_1.findObject(whatsappId, contactId, "ura");
                    uraOptionSelected = uraOptionSelected[4].split("|");
                    if (uraOptionSelected.length == 1) {
                        yield RedisClient_1.createObject({
                            whatsappId,
                            contactId,
                            identifier: "ura",
                            value: data[1].id,
                            history: `|${data[1].id}`
                        });
                        return data[1];
                    }
                    else if (uraOptionSelected.length > 1) {
                        const id = uraOptionSelected[uraOptionSelected.length - 1];
                        console.log(" ID FROM THE MENU/SUBMENU: ", id);
                        const history = yield historyUra(whatsappId, contactId, id);
                        yield RedisClient_1.createObject({
                            whatsappId,
                            contactId,
                            identifier: "ura",
                            value: id,
                            history
                        });
                        let response = data.find((o) => o.id == id);
                        return response;
                    }
                }
            }
        }
        //
        if (option) {
            let response = data.find((o) => o.idmaster == option.id);
            // console.log(" RESPONSE OPTION: ", response, " | OPTION: ", option);
            let history = yield historyUra(whatsappId, contactId, response.id);
            yield RedisClient_1.createObject({
                whatsappId,
                contactId,
                identifier: "ura",
                value: response.id,
                history
            });
            return response;
        }
        else if (userTyped == "0") {
            yield RedisClient_1.createObject({
                whatsappId,
                contactId,
                identifier: "ura",
                value: data[1].id,
                history: `|${data[1].id}`
            });
            return data[1];
        }
        else if (userTyped == "#") {
            return yield backUra(whatsappId, contactId, data);
        }
    }
    function existSubMenu() {
        let existSubMenu = data.find((o) => o.idmaster == lastId[3]);
        if (existSubMenu)
            true;
        return false;
    }
    function mainOptionsMenu(userTyped) {
        return __awaiter(this, void 0, void 0, function* () {
            let currentMenu = yield RedisClient_1.findObject(whatsappId, contactId, "ura");
            const menuValues = data
                .filter((m) => m.idmaster == currentMenu[3])
                .map((m) => m.value);
            let menuOption = data.find((o) => o.value.toLowerCase() == userTyped.toLowerCase() &&
                menuValues.includes(userTyped.toLowerCase()));
            if (menuOption) {
                let response = data.find((o) => o.idmaster == menuOption.id);
                if (response) {
                    let history = yield historyUra(whatsappId, contactId, response.id);
                    yield RedisClient_1.createObject({
                        whatsappId,
                        contactId,
                        identifier: "ura",
                        value: response.id,
                        history
                    });
                    return response;
                }
            }
        });
    }
});
const handleMsgAck = (msg_id, ack, whatsAppOfficial) => __awaiter(void 0, void 0, void 0, function* () {
    if (whatsAppOfficial) {
        if (ack == "sent")
            ack = 1;
        else if (ack == "delivered")
            ack = 2;
        else if (ack == "read")
            ack = 3;
    }
    else
        yield new Promise(r => setTimeout(r, 4000));
    const io = socket_1.getIO();
    try {
        const messageToUpdate = yield Message_1.default.findByPk(msg_id, {
            include: [
                "contact",
                {
                    model: Message_1.default,
                    as: "quotedMsg",
                    include: ["contact"]
                }
            ]
        });
        if (!messageToUpdate) {
            console.log(`Not found the MESSAGE ID ${msg_id}to change the ACK into the Message table`);
            return;
        }
        console.log("messageToUpdate.ack: ", messageToUpdate.ack, " | ack: ", ack);
        if (messageToUpdate.ack > ack)
            return;
        yield messageToUpdate.update({ ack });
        io.to(messageToUpdate.ticketId.toString()).emit("appMessage", {
            action: "update",
            message: messageToUpdate
        });
    }
    catch (err) {
        Sentry.captureException(err);
        logger_1.logger.error(`Error handling message ack. Err: ${err}`);
    }
});
exports.handleMsgAck = handleMsgAck;
const wbotMessageListener = (wbot) => {
    wbot.on("message_create", (msg) => __awaiter(void 0, void 0, void 0, function* () {
        handleMessage(msg, wbot);
    }));
    wbot.on("media_uploaded", (msg) => __awaiter(void 0, void 0, void 0, function* () {
        handleMessage(msg, wbot);
    }));
    wbot.on("message_ack", (msg, ack) => __awaiter(void 0, void 0, void 0, function* () {
        handleMsgAck(msg, ack);
    }));
};
exports.wbotMessageListener = wbotMessageListener;
const outOfService = (number) => __awaiter(void 0, void 0, void 0, function* () {
    // MESSAGE TO HOLIDAY
    const holiday = yield TicketConfig_1.isHoliday(number);
    let objs = [];
    if (holiday && holiday.set) {
        objs.push({ type: "holiday", msg: holiday.msg });
    }
    // MESSAGE TO SATURDAY BUSINESS TIME
    const businessTimeSaturday = yield TicketConfig_1.isOutBusinessTimeSaturday(number);
    if (businessTimeSaturday && businessTimeSaturday.set) {
        objs.push({ type: "saturdayBusinessTime", msg: businessTimeSaturday.msg });
    }
    // MESSAGES TO SATURDAY OR SUNDAY
    const weekend = yield TicketConfig_1.isWeekend(number);
    if (weekend && weekend.set) {
        objs.push({ type: "weekend", msg: weekend.msg });
    }
    // MESSAGE TO BUSINESS TIME
    const businessTime = yield TicketConfig_1.isOutBusinessTime(number);
    if (businessTime && businessTime.set) {
        objs.push({ type: "businessTime", msg: businessTime.msg });
    }
    return objs;
});
function assingContactByQueue(ticket, queueId) {
    var _a;
    return __awaiter(this, void 0, void 0, function* () {
        if (((_a = WhaticketSettings_1.getSettingValue("contactByqueues")) === null || _a === void 0 ? void 0 : _a.value) == "enabled") {
            const contact = yield Contact_1.default.findByPk(ticket.contact.id);
            if (contact) {
                let queueIds = yield ContactQueues_1.default.findAll({
                    where: { contactId: contact.id }
                });
                queueIds = queueIds.map((q) => q.queueId);
                yield AssociateContatctQueue_1.default(contact, [...queueIds, queueId]);
            }
        }
    });
}
function vcard(msg) {
    var _a;
    return __awaiter(this, void 0, void 0, function* () {
        let array = [];
        let contact;
        let obj = [];
        try {
            const multi_vcard = ((_a = msg === null || msg === void 0 ? void 0 : msg.vCards) === null || _a === void 0 ? void 0 : _a.length) === 0 ? false : true;
            if (multi_vcard) {
                array = msg === null || msg === void 0 ? void 0 : msg.vCards;
                contact = [];
            }
            else {
                array = msg.body.split("\n");
                contact = "";
            }
            for (let index = 0; index < array.length; index++) {
                const v = array[index];
                const values = v.split(":");
                for (let ind = 0; ind < values.length; ind++) {
                    if (values[ind].indexOf("+") !== -1) {
                        obj.push({ number: values[ind] });
                    }
                    if (values[ind].indexOf("FN") !== -1) {
                        if (multi_vcard)
                            contact.push({ name: values[ind + 1].split("\n")[0] });
                        else
                            contact = values[ind + 1];
                    }
                }
            }
            for (const i in obj) {
                let data = {};
                if (multi_vcard) {
                    data = {
                        name: contact[i].name,
                        number: obj[i].number.replace(/\D/g, "")
                    };
                }
                else {
                    data = {
                        name: contact,
                        number: obj[i].number.replace(/\D/g, "")
                    };
                }
                const cont = yield CreateContactService_1.default(data);
            }
        }
        catch (error) {
            console.log(error);
        }
    });
}
function backUra(whatsappId, contactId, data) {
    return __awaiter(this, void 0, void 0, function* () {
        let uraOptionSelected = yield RedisClient_1.findObject(whatsappId, contactId, "ura");
        uraOptionSelected = uraOptionSelected[4].split("|").filter(Boolean);
        let id = uraOptionSelected[0];
        let history = `|${uraOptionSelected[0]}`;
        if (uraOptionSelected.length > 1) {
            const idRemove = uraOptionSelected[uraOptionSelected.length - 1];
            history = yield historyUra(whatsappId, contactId, idRemove, true);
            const lstIds = history.split("|").filter(Boolean);
            id = lstIds[lstIds.length - 1];
        }
        yield RedisClient_1.createObject({
            whatsappId,
            contactId,
            identifier: "ura",
            value: id,
            history
        });
        let response = data.find((o) => o.id == id);
        return response;
    });
}
function historyUra(whatsappId, contactId, id, remove) {
    var _a, _b;
    return __awaiter(this, void 0, void 0, function* () {
        let uraOptionSelected = yield RedisClient_1.findObject(whatsappId, contactId, "ura");
        let history = "";
        console.log("SELECED OPTION uraOptionSelected: ", uraOptionSelected);
        if (remove) {
            return (_a = uraOptionSelected[4]) === null || _a === void 0 ? void 0 : _a.replace(`|${id}`, "");
        }
        if (uraOptionSelected && uraOptionSelected.length == 5) {
            if (!((_b = uraOptionSelected[4]) === null || _b === void 0 ? void 0 : _b.includes(`${id}`)))
                history += `${uraOptionSelected[4]}|${id}`;
            else
                history = `${uraOptionSelected[4]}`;
        }
        else {
            history = `|${id}`;
        }
        return history;
    });
}
function whatsappInfo(whatsappId) {
    return __awaiter(this, void 0, void 0, function* () {
        return yield Whatsapp_1.default.findByPk(whatsappId);
    });
}
