module.exports = function(Self) {
    Self.remoteMethodCtx('setPosition', {
        description: 'sets the position of a given module',
        accessType: 'WRITE',
        returns: {
            type: 'object',
            root: true
        },
        accepts: [
            {
                arg: 'moduleName',
                type: 'string',
                required: true,
                description: 'The module name'
            },
            {
                arg: 'direction',
                type: 'string',
                required: true,
                description: 'Whether to move left or right the module position'
            }
        ],
        http: {
            path: `/setPosition`,
            verb: 'post'
        }
    });

    Self.setPosition = async(ctx, moduleName, direction, options) => {
        const models = Self.app.models;
        const userId = ctx.req.accessToken.userId;

        let tx;
        const myOptions = {};

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

        if (!myOptions.transaction) {
            tx = await Self.beginTransaction({});
            myOptions.transaction = tx;
        }

        try {
            const filter = {
                where: {
                    workerFk: userId,
                    moduleFk: moduleName
                },
                order: 'position DESC'
            };

            const [movingModule] = await models.StarredModule.find(filter, myOptions);

            let operator;
            let order;

            switch (direction) {
            case 'left':
                operator = {lt: movingModule.position};
                order = 'position DESC';
                break;
            case 'right':
                operator = {gt: movingModule.position};
                order = 'position ASC';
                break;
            default:
                return;
            }

            const pushedModule = await models.StarredModule.findOne({
                where: {
                    position: operator,
                    workerFk: userId
                },
                order: order
            }, myOptions);

            if (!pushedModule) return;

            const movingPosition = pushedModule.position;
            const pushingPosition = movingModule.position;

            await movingModule.updateAttribute('position', movingPosition, myOptions);
            await pushedModule.updateAttribute('position', pushingPosition, myOptions);

            if (tx) await tx.commit();

            return {
                movingModule: movingModule,
                pushedModule: pushedModule
            };
        } catch (e) {
            if (tx) await tx.rollback();
            throw e;
        }
    };
};