/*****************************************************************************\
|                                               ( )_  _                       |
|    _ _    _ __   _ _    __    ___ ___     _ _ | ,_)(_)  ___   ___     _     |
|   ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| |  | |/',__)/' v `\ /'_`\   |
|   | (_) )| |  ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) )  |
|   | ,__/'(_)  `\__,_)`\__  |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/'  |
|   | |                ( )_) |                                                |
|   (_)                 \___/'                                                |
|                                                                             |
| General Bots Copyright (c) Pragmatismo.io. All rights reserved.             |
| Licensed under the AGPL-3.0.                                                |
|                                                                             |
| According to our dual licensing model, this program can be used either      |
| under the terms of the GNU Affero General Public License, version 3,        |
| or under a proprietary license.                                             |
|                                                                             |
| The texts of the GNU Affero General Public License with an additional       |
| permission and of our proprietary license can be found at and               |
| in the LICENSE file you have received along with this program.              |
|                                                                             |
| This program is distributed in the hope that it will be useful,             |
| but WITHOUT ANY WARRANTY, without even the implied warranty of              |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                |
| GNU Affero General Public License for more details.                         |
|                                                                             |
| "General Bots" is a registered trademark of Pragmatismo.io.                 |
| The licensing of the program under the AGPLv3 does not imply a              |
| trademark license. Therefore any rights, title and interest in              |
| our trademarks remain entirely with us.                                     |
|                                                                             |
\*****************************************************************************/
import Swagger from 'swagger-client';
import { google } from 'googleapis';
import { PubSub } from '@google-cloud/pubsub';
import Fs from 'fs';
import { GBLog, GBService } from 'botlib';
import { GBServer } from '../../../src/app.js';
import { SecService } from '../../security.gbapp/services/SecService.js';
/**
 * Support for Google Chat.
 */
export class GoogleChatDirectLine extends GBService {
    static conversationIds = {};
    pollInterval = 5000;
    directLineClientName = 'DirectLineClient';
    directLineClient;
    GoogleChatSubscriptionName;
    botId;
    min;
    directLineSecret;
    pubSubClient;
    GoogleChatApiKey;
    GoogleClientEmail;
    GoogleClientPrivateKey;
    GoogleProjectId;
    constructor(min, botId, directLineSecret, GoogleChatSubscriptionName, GoogleChatApiKey, GoogleClientEmail, GoogleClientPrivateKey, GoogleProjectId) {
        super();
        this.min = min;
        this.botId = botId;
        this.directLineSecret = directLineSecret;
        this.GoogleChatSubscriptionName = GoogleChatSubscriptionName;
        this.GoogleChatApiKey = GoogleChatApiKey;
        this.GoogleClientEmail = GoogleClientEmail;
        this.GoogleClientPrivateKey = GoogleClientPrivateKey;
        this.GoogleProjectId = GoogleProjectId;
        this.pubSubClient = new PubSub({
            projectId: this.GoogleProjectId,
            credentials: { client_email: GoogleClientEmail, private_key: GoogleClientPrivateKey }
        });
    }
    static async asyncForEach(array, callback) {
        for (let index = 0; index < array.length; index++) {
            await callback(array[index], index, array);
        }
    }
    async setup(setUrl) {
        this.directLineClient = new Swagger({
            spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
            usePromise: true
        });
        const client = await this.directLineClient;
        client.clientAuthorizations.add('AuthorizationBotConnector', new Swagger.ApiKeyAuthorization('Authorization', `Bearer ${this.directLineSecret}`, 'header'));
        if (setUrl) {
            try {
                const subscription = this.pubSubClient.subscription(this.GoogleChatSubscriptionName);
                subscription.on('message', this.receiver.bind(this));
            }
            catch (error) {
                GBLog.error(`Error initializing 3rd party GoogleChat provider(1) ${error.message}`);
            }
        }
    }
    async resetConversationId(key) {
        GoogleChatDirectLine.conversationIds[key] = undefined;
    }
    async check() {
        GBLog.info(`GBGoogleChat: Checking server...`);
    }
    async receiver(message) {
        const event = JSON.parse(Buffer.from(message.data, 'binary').toString());
        let from = '';
        let fromName = '';
        let text;
        const threadName = event.message.thread.name;
        if (event['type'] === 'ADDED_TO_SPACE' && event['space']['singleUserBotDm']) {
        }
        else if (event['type'] === 'MESSAGE') {
            text = event.message.text;
            fromName = event.message.sender.displayName;
            from = event.message.sender.email;
            GBLog.info(`Received message from ${from} (${fromName}): ${text}.`);
        }
        message.ack();
        const sec = new SecService();
        const user = await sec.ensureUser(this.min.instance.instanceId, from, from, '', 'googlechat', fromName, from);
        await sec.updateConversationReferenceById(user.userId, threadName);
        GBLog.info(`GBGoogleChat: RCV ${from}: ${text})`);
        const client = await this.directLineClient;
        const conversationId = GoogleChatDirectLine.conversationIds[from];
        if (GoogleChatDirectLine.conversationIds[from] === undefined) {
            GBLog.info(`GBGoogleChat: Starting new conversation on Bot.`);
            const response = await client.Conversations.Conversations_StartConversation();
            const generatedConversationId = response.obj.conversationId;
            GoogleChatDirectLine.conversationIds[from] = generatedConversationId;
            this.pollMessages(client, generatedConversationId, threadName, from, fromName);
            this.inputMessage(client, generatedConversationId, threadName, text, from, fromName);
        }
        else {
            this.inputMessage(client, conversationId, threadName, text, from, fromName);
        }
    }
    inputMessage(client, conversationId, threadName, text, from, fromName) {
        return client.Conversations.Conversations_PostActivity({
            conversationId: conversationId,
            activity: {
                textFormat: 'plain',
                text: text,
                type: 'message',
                mobile: from,
                from: {
                    id: from,
                    name: fromName
                },
                replyToId: from
            }
        });
    }
    pollMessages(client, conversationId, threadName, from, fromName) {
        GBLog.info(`GBGoogleChat: Starting message polling(${from}, ${conversationId}).`);
        let watermark;
        const worker = async () => {
            try {
                const response = await client.Conversations.Conversations_GetActivities({
                    conversationId: conversationId,
                    watermark: watermark
                });
                watermark = response.obj.watermark;
                await this.printMessages(response.obj.activities, conversationId, threadName, from, fromName);
            }
            catch (err) {
                GBLog.error(`Error calling printMessages on GoogleChat channel ${err.data === undefined ? err : err.data}`);
            }
        };
        setInterval(worker, this.pollInterval);
    }
    async printMessages(activities, conversationId, threadName, from, fromName) {
        if (activities && activities.length) {
            // Ignore own messages.
            activities = activities.filter(m => m.from.id === this.botId && m.type === 'message');
            if (activities.length) {
                // Print other messages.
                await GoogleChatDirectLine.asyncForEach(activities, async (activity) => {
                    await this.printMessage(activity, conversationId, threadName, from, fromName);
                });
            }
        }
    }
    async printMessage(activity, conversationId, threadName, from, fromName) {
        let output = '';
        if (activity.text) {
            GBLog.info(`GBGoogleChat: SND ${from}(${fromName}): ${activity.text}`);
            output = activity.text;
        }
        if (activity.attachments) {
            activity.attachments.forEach(attachment => {
                switch (attachment.contentType) {
                    case 'image/png':
                        GBLog.info(`Opening the requested image ${attachment.contentUrl}`);
                        output += `\n${attachment.contentUrl}`;
                        break;
                    default:
                        GBLog.info(`Unknown content type: ${attachment.contentType}`);
                }
            });
        }
        await this.sendToDevice(from, conversationId, threadName, output);
    }
    async sendToDevice(from, conversationId, threadName, msg) {
        try {
            let threadParts = threadName.split('/');
            let spaces = threadParts[1];
            let threadKey = threadParts[3];
            const scopes = ['https://www.googleapis.com/auth/chat.bot'];
            const jwtClient = new google.auth.JWT(this.GoogleClientEmail, null, this.GoogleClientPrivateKey, scopes, null);
            await jwtClient.authorize();
            const chat = google.chat({ version: 'v1', auth: jwtClient });
            const res = await chat.spaces.messages.create({
                parent: `spaces/${spaces}`,
                threadKey: threadKey,
                requestBody: {
                    text: msg
                }
            });
            GBLog.info(res);
            GBLog.info(`Message [${msg}] sent to ${from}: `);
        }
        catch (error) {
            GBLog.error(`Error sending message to GoogleChat provider ${error.message}`);
        }
    }
    async sendToDeviceEx(to, conversationId, threadName, text, locale) {
        const minBoot = GBServer.globals.minBoot;
        text = await minBoot.conversationalService.translate(minBoot, text, locale);
        await this.sendToDevice(to, conversationId, threadName, text);
    }
}
//# sourceMappingURL=GoogleChatDirectLine.js.map