const UserError = require('vn-loopback/util/user-error');

module.exports = Self => {
    require('../methods/notification/getList')(Self);

    Self.observe('before save', async function(ctx) {
        await checkModifyPermission(ctx);
    });

    Self.observe('before delete', async function(ctx) {
        await checkModifyPermission(ctx);
    });

    async function checkModifyPermission(ctx) {
        const models = Self.app.models;
        const instance = ctx.instance;
        const userId = ctx.options.accessToken.userId;

        let notificationFk;
        let workerId;

        if (instance) {
            notificationFk = instance.notificationFk;
            workerId = instance.userFk;
        } else {
            const notificationSubscription = await models.NotificationSubscription.findById(ctx.where.id);
            notificationFk = notificationSubscription.notificationFk;
            workerId = notificationSubscription.userFk;
        }

        const worker = await models.Worker.findById(workerId, {fields: ['id', 'bossFk']});
        const available = await Self.getAvailable(workerId);
        const hasAcl = available.has(notificationFk);

        if (!hasAcl || (userId != worker.id && userId != worker.bossFk))
            throw new UserError('The notification subscription of this worker cant be modified');
    }

    Self.getAvailable = async function(userId, options) {
        const availableNotificationsMap = new Map();
        const models = Self.app.models;

        const myOptions = {};

        if (typeof options == 'object')
            Object.assign(myOptions, options);

        const roles = await models.RoleMapping.find({
            fields: ['roleId'],
            where: {principalId: userId}
        }, myOptions);

        const availableNotifications = await models.NotificationAcl.find({
            fields: ['notificationFk', 'roleFk'],
            include: {relation: 'notification'},
            where: {
                roleFk: {
                    inq: roles.map(role => role.roleId),
                },
            }
        }, myOptions);

        for (available of availableNotifications) {
            availableNotificationsMap.set(available.notificationFk, {
                id: null,
                notificationFk: available.notificationFk,
                name: available.notification().name,
                description: available.notification().description,
                active: false
            });
        }
        return availableNotificationsMap;
    };
};