const _ = require('lodash');
const moment = require('moment');
const config = require('../../config');
const models = require('../../models');
const urlUtils = require('../../lib/url-utils');
const common = require('../../lib/common');
const api = require('./index');

module.exports = {
    docName: 'schedules',
    publish: {
        headers: {},
        options: [
            'id',
            'resource'
        ],
        data: [
            'force'
        ],
        validation: {
            options: {
                id: {
                    required: true
                },
                resource: {
                    required: true,
                    values: ['posts', 'pages']
                }
            }
        },
        permissions: {
            docName: 'posts'
        },
        query(frame) {
            let resource;
            const resourceType = frame.options.resource;
            const publishAPostBySchedulerToleranceInMinutes = config.get('times').publishAPostBySchedulerToleranceInMinutes;

            return models.Base.transaction((transacting) => {
                const options = {
                    transacting: transacting,
                    status: 'scheduled',
                    forUpdate: true,
                    id: frame.options.id,
                    context: {
                        internal: true
                    }
                };

                return api[resourceType].read({id: frame.options.id}, options)
                    .then((result) => {
                        resource = result[resourceType][0];
                        const publishedAtMoment = moment(resource.published_at);

                        if (publishedAtMoment.diff(moment(), 'minutes') > publishAPostBySchedulerToleranceInMinutes) {
                            return Promise.reject(new common.errors.NotFoundError({message: common.i18n.t('errors.api.job.notFound')}));
                        }

                        if (publishedAtMoment.diff(moment(), 'minutes') < publishAPostBySchedulerToleranceInMinutes * -1 && frame.data.force !== true) {
                            return Promise.reject(new common.errors.NotFoundError({message: common.i18n.t('errors.api.job.publishInThePast')}));
                        }

                        const editedResource = {};
                        editedResource[resourceType] = [{
                            status: 'published',
                            updated_at: moment(resource.updated_at).toISOString(true)
                        }];

                        return api[resourceType].edit(
                            editedResource,
                            _.pick(options, ['context', 'id', 'transacting', 'forUpdate'])
                        );
                    })
                    .then((result) => {
                        const scheduledResource = result[resourceType][0];

                        if (
                            (scheduledResource.status === 'published' && resource.status !== 'published') ||
                            (scheduledResource.status === 'draft' && resource.status === 'published')
                        ) {
                            this.headers.cacheInvalidate = true;
                        } else if (
                            (scheduledResource.status === 'draft' && resource.status !== 'published') ||
                            (scheduledResource.status === 'scheduled' && resource.status !== 'scheduled')
                        ) {
                            this.headers.cacheInvalidate = {
                                value: urlUtils.urlFor({
                                    relativeUrl: urlUtils.urlJoin('/p', scheduledResource.uuid, '/')
                                })
                            };
                        } else {
                            this.headers.cacheInvalidate = false;
                        }

                        return result;
                    });
            });
        }
    },

    getScheduled: {
        // NOTE: this method is for internal use only by DefaultScheduler
        //       it is not exposed anywhere!
        permissions: false,
        validation: {
            options: {
                resource: {
                    required: true,
                    values: ['posts', 'pages']
                }
            }
        },
        query(frame) {
            const resourceModel = 'Post';
            const resourceType = (frame.options.resource === 'post') ? 'post' : 'page';
            const cleanOptions = {};
            cleanOptions.filter = `status:scheduled+type:${resourceType}`;
            cleanOptions.columns = ['id', 'published_at', 'created_at', 'type'];

            return models[resourceModel].findAll(cleanOptions)
                .then((result) => {
                    let response = {};
                    response[resourceType] = result;
                    return response;
                });
        }
    }
};