"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const BlueBaseModuleRegistry_1 = require("./BlueBaseModuleRegistry");
const utils_1 = require("../utils");
function inputToPlugin(plugin) {
    const { value } = plugin, rest = tslib_1.__rest(plugin, ["value"]);
    return Object.assign({ components: {}, defaultConfigs: {}, enabled: true, filters: {}, name: 'Untitled Plugin', themes: {} }, rest, value);
}
exports.inputToPlugin = inputToPlugin;
/**
 * Creates a BlueBase plugin from input params
 * @param plugin
 */
function createPlugin(plugin) {
    const { components, filters, themes, routes, value } = plugin, rest = tslib_1.__rest(plugin, ["components", "filters", "themes", "routes", "value"]);
    return Object.assign({ categories: [], defaultConfigs: {}, enabled: true, name: 'Untitled Plugin' }, rest, { value: Object.assign({ components: components || {}, filters: filters || {}, routes, themes: themes || {} }, value) });
}
exports.createPlugin = createPlugin;
/**
 * 🔌 PluginRegistry
 */
class PluginRegistry extends BlueBaseModuleRegistry_1.BlueBaseModuleRegistry {
    /**
     * Returns a Promise that resolves a Plugin
     * @param keys
     */
    async resolve(...keys) {
        const item = this.findOne(...keys);
        if (!item) {
            throw Error(`Could not resolve any of the following plugins: [${keys.join(', ')}].`);
        }
        const input = Object.assign({}, item, { value: await item.value });
        return inputToPlugin(input);
    }
    /**
     * Checks if a plugin is enabled
     * @param key
     */
    isEnabled(key) {
        const item = this.get(key);
        if (!item) {
            throw Error(`Could not check if plugin is enabled. Reason: No plugin registered by key "${key}".`);
        }
        return item.enabled;
    }
    /**
     * Enable a plugin
     * @param key
     */
    async enable(key) {
        const item = this.get(key);
        if (!item) {
            throw Error(`Could not enable plugin. Reason: No plugin registered by key "${key}".`);
        }
        item.enabled = true;
        this.set(key, item);
    }
    /**
     * Disable a plugin
     * @param key
     */
    async disable(key) {
        const item = this.get(key);
        if (!item) {
            throw Error(`Could not disable plugin. Reason: No plugin registered by key "${key}".`);
        }
        item.enabled = false;
        this.set(key, item);
    }
    /**
     * Checks if a config belongs to a plugin. Does so by checking 2 things:
     *
     * 1. Does the config start with 'plugin.{key}.'?
     * 2. Does the config exist in defaultConfigs property of the plugin?
     *
     * Returns true if any of the above are true, otherwise returns false
     *
     * @param key
     */
    hasConfig(key, config) {
        const plugin = this.get(key);
        if (!plugin) {
            throw Error(`Could not check config for a plugin. Reason: No plugin registered by key "${key}".`);
        }
        return (config.startsWith(`plugin.${key}.`) ||
            Object.keys(plugin.defaultConfigs).findIndex(k => k === config) >= 0);
    }
    /**
     * Creates a map of routes for each plugin
     *
     * Ignores plugins if:
     *
     * - Plugin is not enabled
     * - Plugin is not resolved
     */
    getRouteMap(prefixPluginKey = true) {
        const pluginRoutes = {};
        const pluginRoutePathPrefix = this.BB.Configs.getValue('pluginRoutePathPrefix') || '';
        for (const [key, item] of this.entries()) {
            // Skip if pluign is not loaded, or plugin is not enabled
            if ((item.value.isAsync && !item.value.loaded) || !item.enabled) {
                continue;
            }
            // Resolve plugin
            const plugin = inputToPlugin(item.value.module);
            // Skip if plugin doesn't have any routes
            if (!plugin.routes) {
                continue;
            }
            // Resolve routes, if it's a thunk
            // Put the resovled value in an array, if it's a single item
            let routes = utils_1.getDefiniteArray(utils_1.resolveThunk(plugin.routes, this.BB));
            // Add plugin slug as prefix to top level routes
            routes = routes.map(route => (Object.assign({}, route, { path: utils_1.joinPaths(pluginRoutePathPrefix, prefixPluginKey ? key : '', route.path) })));
            // Put the result in the collective result
            pluginRoutes[key] = routes;
        }
        return pluginRoutes;
    }
    /**
     * Convert any input value to an item. This is where you transform inputs and add defualts
     * @param key
     * @param partial
     */
    createItem(key, partial) {
        return super.createItem(key, createPlugin(partial));
    }
    /**
     * Typeguard to check a given object is an input value
     * @param value
     */
    isInputValue(value) {
        return utils_1.isBlueBaseModule(value) || typeof value === 'object';
    }
}
exports.PluginRegistry = PluginRegistry;
