const Vue = require('vue');
const VueI18n = require('vue-i18n');
const renderer = require('vue-server-renderer').createRenderer();
Vue.use(VueI18n);

const fs = require('fs');
const yaml = require('js-yaml');
const juice = require('juice');
const path = require('path');
const config = require('./config');

class Component {
    constructor(name) {
        this.name = name;
    }

    get path() {
        return `./components/${this.name}`;
    }

    get template() {
        const templatePath = `${this.path}/${this.name}.html`;
        const fullPath = path.resolve(__dirname, templatePath);

        return fs.readFileSync(fullPath, 'utf8');
    }

    get locale() {
        if (!this._locale)
            this._locale = this.getLocales();

        return this._locale;
    }

    getLocales() {
        const mergedLocales = {messages: {}};
        const localePath = path.resolve(__dirname, `${this.path}/locale`);

        if (!fs.existsSync(localePath))
            return mergedLocales;

        const localeDir = fs.readdirSync(localePath);
        for (const locale of localeDir) {
            const fullPath = path.join(localePath, '/', locale);
            const yamlLocale = fs.readFileSync(fullPath, 'utf8');
            const jsonLocale = yaml.safeLoad(yamlLocale);
            const localeName = locale.replace('.yml', '');

            mergedLocales.messages[localeName] = jsonLocale;
        }

        return mergedLocales;
    }

    async getUserLocale() {
        let lang = this.args.lang;

        // Fetches user locale from mixing method getLocale()
        if (this.args.recipientId) {
            const component = await this.component();
            lang = await component.getLocale(this.args.recipientId);
        }

        const messages = this.locale.messages;
        const userTranslations = messages[lang];

        if (!userTranslations) {
            const fallbackLang = config.i18n.fallbackLocale;

            return messages[fallbackLang];
        }

        return userTranslations;
    }

    get stylesheet() {
        let mergedStyles = '';
        const stylePath = path.resolve(__dirname, `${this.path}/assets/css`);

        if (!fs.existsSync(stylePath))
            return mergedStyles;

        return require(`${stylePath}/import`);
    }

    get attachments() {
        const attachmentsPath = `${this.path}/attachments.json`;
        const fullPath = path.resolve(__dirname, attachmentsPath);

        if (!fs.existsSync(fullPath))
            return [];

        return require(fullPath);
    }

    build() {
        const fullPath = path.resolve(__dirname, this.path);
        if (!fs.existsSync(fullPath))
            throw new Error(`Template "${this.name}" not found`);

        const component = require(`${this.path}/${this.name}`);
        component.i18n = this.locale;
        component.attachments = this.attachments;
        component.template = juice.inlineContent(this.template, this.stylesheet, {
            inlinePseudoElements: true
        });
        const tplPath = this.path;
        if (!component.computed) component.computed = {};
        component.computed.path = function() {
            return tplPath;
        };

        return component;
    }

    component() {
        if (this._component)
            return this._component;

        const component = this.build();
        const i18n = new VueI18n(config.i18n);
        const props = {...this.args};
        this._component = new Vue({
            i18n: i18n,
            render: h => h(component, {
                props: props
            })
        });

        return this._component;
    }

    /**
     * @return {Promise} Rendered component
     */
    async render() {
        return renderer.renderToString(
            this.component()
        );
    }
}

module.exports = Component;