"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getConfig = getConfig;
exports.sendNotification = sendNotification;
exports.register = register;
exports.unregister = unregister;
exports.notify = notify;
const tslib_1 = require("tslib");
const node_fetch_1 = tslib_1.__importDefault(require("node-fetch"));
const env_1 = require("@things-factory/env");
const app_1 = require("firebase-admin/app");
const messaging_1 = require("firebase-admin/messaging");
const notificationConfig = env_1.config.get('notification') || {};
const { fcm, vapidKey } = notificationConfig;
const { serviceAccount, appConfig, serverKey } = fcm || {};
const { publicKey } = vapidKey || {};
var messaging;
if (serviceAccount) {
    try {
        const app = (0, app_1.initializeApp)({
            credential: (0, app_1.cert)(serviceAccount)
        });
        messaging = (0, messaging_1.getMessaging)(app);
    }
    catch (err) {
        env_1.logger.error('incorrect notification configuration');
        env_1.logger.error(err);
    }
}
function getConfig() {
    return messaging
        ? {
            appConfig,
            vapidPublicKey: publicKey
        }
        : {};
}
/**
 * sendNotification
 *
 * @param receiver user.id who will receive notification
 * @param message message object to be sent
 */
async function sendNotification({ receivers, message }) {
    if (!messaging) {
        return;
    }
    notify({
        receivers,
        ...message
    });
}
async function register(user, { subscription }) {
    if (!messaging || !subscription || !user) {
        return false;
    }
    try {
        var notification_key = await getDeviceGroup(user.id);
        if (!notification_key) {
            await postDeviceGroup({
                operation: 'create',
                notification_key_name: user.id,
                registration_ids: [subscription]
            });
        }
        else {
            await postDeviceGroup({
                operation: 'add',
                notification_key_name: user.id,
                notification_key,
                registration_ids: [subscription]
            });
        }
        return true;
    }
    catch (err) {
        return;
    }
}
async function unregister(user, { subscription }) {
    if (!messaging || !subscription || !user) {
        return false;
    }
    try {
        var notification_key = await getDeviceGroup(user.id);
        if (notification_key) {
            await postDeviceGroup({
                operation: 'remove',
                notification_key_name: user.id,
                notification_key,
                registration_ids: [subscription]
            });
        }
        return true;
    }
    catch (err) {
        return;
    }
}
async function notify({ receivers, privileges, tokens, topic, title, body, data, image, actions }) {
    if (!messaging) {
        return;
    }
    // Caution: non-string attributes are not allowed in FCM payload validation
    var notification = {
        title: title || '',
        body: body || '',
        image: image || ''
    };
    if (tokens && tokens instanceof Array && tokens.length > 0) {
        if (tokens.length > 1) {
            const response = await messaging.sendMulticast({
                notification,
                data,
                tokens
            });
            if (response.failureCount > 0) {
                const failedTokens = [];
                response.responses.forEach((resp, idx) => {
                    if (!resp.success) {
                        failedTokens.push(tokens[idx]);
                    }
                });
                env_1.logger.error('List of tokens that caused failures: ' + failedTokens);
            }
        }
        else {
            const token = tokens[0];
            try {
                const response = await messaging.send({
                    notification,
                    data,
                    token
                });
                env_1.logger.log('Successfully sent message:', response);
            }
            catch (err) {
                env_1.logger.error('Error sending message:', err);
            }
        }
    }
    if (topic) {
        try {
            const response = await messaging.send({
                notification,
                data,
                topic
            });
            env_1.logger.log('Successfully sent message:', response);
        }
        catch (err) {
            env_1.logger.error('Error sending message:', err);
        }
    }
    if (receivers && receivers instanceof Array) {
        for (let receiver of receivers) {
            const notification_key = await getDeviceGroup(receiver);
            if (notification_key) {
                await messaging.sendToDeviceGroup(notification_key, {
                    notification,
                    data
                });
            }
        }
    }
}
async function postDeviceGroup(body) {
    var response = await (0, node_fetch_1.default)('https://fcm.googleapis.com/fcm/notification', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            Authorization: `key=${serverKey}`,
            project_id: appConfig.messagingSenderId
        },
        body: JSON.stringify(body)
    });
    if (response.ok) {
        const { notification_key } = await response.json();
        return notification_key;
    }
    else {
        console.error('postDeviceGroup-notok', response.status, await response.text());
    }
}
async function getDeviceGroup(notificationKeyName) {
    const response = await (0, node_fetch_1.default)(`https://fcm.googleapis.com/fcm/notification?notification_key_name=${notificationKeyName}`, {
        method: 'GET',
        headers: {
            'Content-Type': 'application/json',
            Authorization: `key=${serverKey}`,
            project_id: appConfig.messagingSenderId
        }
    });
    if (response.ok) {
        const { notification_key } = await response.json();
        return notification_key;
    }
}
//# sourceMappingURL=fcm.js.map