const Vue = require('vue');
const VueI18n = require('vue-i18n');
const renderer = require('vue-server-renderer').createRenderer();
const fs = require('fs-extra');
const juice = require('juice');
const smtp = require('./smtp');
const fallbackLocale = 'es';

if (!process.env.OPENSSL_CONF)
    process.env.OPENSSL_CONF = '/etc/ssl/';

Vue.use(VueI18n);

module.exports = {

    path: `${appPath}/report`,

    /**
     * Renders a report component
     *
     * @param {String} name - Report name
     * @param {Object} ctx - Request context
     */
    async render(name, ctx) {
        const component = require(`${this.path}/${name}`);
        const result = await this.preFetch(component, ctx);
        const i18n = new VueI18n({
            locale: 'es',
            fallbackLocale
        });
        const app = new Vue({i18n,
            render: h => h(result.component)});

        return renderer.renderToString(app).then(renderedHtml => {
            return {
                html: renderedHtml,
                data: result.mergedData,
            };
        });
    },

    /**
     * Prefetch all component data from asyncData method
     *
     * @param {Object} orgComponent - Component object
     * @param {Object} ctx - Request context
     */
    async preFetch(orgComponent, ctx) {
        let component = Object.create(orgComponent);
        let mergedData = {attachments: []};
        let asyncData = {};
        let data = {};
        let params = {};

        if (Object.keys(ctx.body).length > 0)
            params = ctx.body;

        if (Object.keys(ctx.query).length > 0)
            params = ctx.query;

        await this.attachAssets(component);

        if (orgComponent.hasOwnProperty('data'))
            data = orgComponent.data();

        if (orgComponent.hasOwnProperty('asyncData')) {
            asyncData = await orgComponent.asyncData(ctx, params);

            if (asyncData.locale) {
                let locale = component.i18n.messages[asyncData.locale];

                if (!locale)
                    locale = component.i18n.messages[fallbackLocale];

                mergedData.subject = locale.subject;
            }
        }

        mergedData = Object.assign(mergedData, data, asyncData);

        component.data = function data() {
            return mergedData;
        };

        if (data.hasOwnProperty('files')) {
            const files = data.files;
            files.forEach(file => {
                const componentPath = `${this.path}/${orgComponent.name}`;
                let fileSrc = componentPath + file;

                if (file.slice(0, 4) === 'http' || file.slice(0, 5) === 'https')
                    fileSrc = file;

                const fileName = file.split('/').pop();
                mergedData.attachments.push({
                    filename: fileName,
                    path: fileSrc,
                    cid: file,
                });
            });
        }

        const components = orgComponent.components;

        if (components) {
            const promises = [];
            const childNames = [];
            component.components = {};

            Object.keys(components).forEach(childName => {
                childNames.push(childName);
                promises.push(this.preFetch(components[childName], ctx));
            });

            await Promise.all(promises).then(results => {
                results.forEach((result, i) => {
                    result.mergedData.attachments.forEach(atth => {
                        mergedData.attachments.push(atth);
                    });

                    component.components[childNames[i]] = result.component;
                });
            });
        }

        return {component, mergedData};
    },

    async attachAssets(component) {
        const localePath = `${this.path}/${component.name}/locale.js`;
        const templatePath = `${this.path}/${component.name}/index.html`;
        const stylePath = `${this.path}/${component.name}/assets/css/index.js`;

        const template = await fs.readFile(templatePath, 'utf8');
        const css = require(stylePath);

        component.i18n = require(localePath);
        component.template = juice.inlineContent(template, css);
    },

    async toEmail(name, ctx) {
        const rendered = await this.render(name, ctx);
        const data = rendered.data;
        const options = {
            to: data.recipient,
            subject: data.subject,
            html: rendered.html,
            attachments: data.attachments,
        };
        return smtp.send(options);
    },
};