const errors = require('@tryghost/errors');
const {i18n, events} = require('../../../server/lib/common');
const logging = require('../../../shared/logging');
const settingsCache = require('../../../server/services/settings/cache');
const config = require('../../../shared/config');

const jp = require('jsonpath');

const isNil = require('lodash/isNil');

class ThemeI18n extends i18n.I18n {
    constructor(locale) {
        super(locale);
    }

    /**
     * Setup i18n support for themes:
     *  - Load correct language file into memory
     */
    init() {
        // This function is called during theme initialization, and when switching language or theme.
        const currentLocale = this._loadLocale();
        const activeTheme = settingsCache.get('active_theme');

        // Reading file for current locale and active theme and keeping its content in memory
        if (activeTheme) {
            // Reading translation file for theme .hbs templates.
            // Compatibility with both old themes and i18n-capable themes.
            // Preventing missing files.
            this._strings = this._tryGetLocale(activeTheme, currentLocale);

            if (!this._strings && currentLocale !== this.defaultLocale()) {
                logging.warn(`Falling back to locales/${this.defaultLocale()}.json.`);
                this._strings = this._tryGetLocale(activeTheme, this.defaultLocale());
            }
        }

        if (isNil(this._strings)) {
            // even if empty, themeStrings must be an object for jp.value
            this._strings = {};
        }

        this._initializeIntl();
    }

    /**
     *  Attempt to load a local file and parse the contents
     *
     * @param {String} activeTheme
     * @param {String} locale
     */
    _tryGetLocale(activeTheme, locale) {
        try {
            return this._readStringsFile(config.getContentPath('themes'), activeTheme, 'locales', `${locale}.json`);
        } catch (err) {
            if (err.code === 'ENOENT') {
                if (locale !== this.defaultLocale()) {
                    logging.warn(`Theme's file locales/${locale}.json not found.`);
                }
            } else if (err instanceof SyntaxError) {
                logging.error(new errors.IncorrectUsageError({
                    err,
                    message: `Unable to parse locales/${locale}.json. Please check that it is valid JSON.`
                }));
            } else {
                throw err;
            }
        }
    }

    /**
     * Load the current locale out of the settings cache
     */
    _loadLocale() {
        this._locale = settingsCache.get('lang');
        return this._locale;
    }

    /**
     * Do the lookup with JSON path
     *
     * @param {String} msgPath
     */
    _getCandidateString(msgPath) {
        // Both jsonpath's dot-notation and bracket-notation start with '$'
        // E.g.: $.store.book.title or $['store']['book']['title']
        // The {{t}} translation helper passes the default English text
        // The full Unicode jsonpath with '$' is built here
        // jp.stringify and jp.value are jsonpath methods
        // Info: https://www.npmjs.com/package/jsonpath
        let path = jp.stringify(['$', msgPath]);
        return jp.value(this._strings, path) || msgPath;
    }
}

let themeI18n = new ThemeI18n();

// /**
//  * When active theme changes, we reload theme translations
//  * We listen on the service event, because of the following known case:
//  *  1. you override a theme, which is already active
//  *  2. The data has not changed, no event is triggered.
//  */
events.on('services.themes.activated', function () {
    themeI18n.init();
});

/**
 * When locale changes, we reload theme translations
 */
events.on('settings.lang.edited', function () {
    themeI18n.init();
});

module.exports = themeI18n;
