"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const BlueBaseModuleRegistry_1 = require("./BlueBaseModuleRegistry");
const themes_1 = require("../themes");
const utils_1 = require("../utils");
const react_loadable_1 = tslib_1.__importDefault(require("react-loadable"));
const components_1 = require("../components/");
const lodash_flowright_1 = tslib_1.__importDefault(require("lodash.flowright"));
const hoist_non_react_statics_1 = tslib_1.__importDefault(require("hoist-non-react-statics"));
/**
 * 🎁 ComponentRegistry
 */
class ComponentRegistry extends BlueBaseModuleRegistry_1.BlueBaseModuleRegistry {
    /**
     * Resolves a Component. Wraps it in `hocs` and `styles`. Takes care of loading and error
     * states if required.
     * @param keys
     */
    resolve(...keys) {
        const item = this.findOne(...keys);
        if (!item) {
            throw Error(`Could not resolve any of the following components: [${keys.join(', ')}].`);
        }
        // If component bundle has to be downloaded, wrap into lazy
        const rawComponent = item.value.isAsync
            ? react_loadable_1.default({ loader: () => item.value, loading: components_1.ReactLoadableLoading })
            : item.value.module;
        let themedComponent = rawComponent;
        // Do we apply styles and theming to this component?
        if (item.applyStyles === true) {
            // If yes, then append applyStyles hoc
            themedComponent = themes_1.applyStyles({ name: item.key, styles: item.styles })(rawComponent);
        }
        // HOCs
        let hocs = item.hocs;
        // Process delayed HOCs
        hocs = item.hocs.map(hoc => (Array.isArray(hoc) ? hoc[0](hoc[1]) : hoc));
        // Wrap
        const wrappedComponent = lodash_flowright_1.default([...hocs])(themedComponent);
        return hoist_non_react_statics_1.default(wrappedComponent, rawComponent);
    }
    /**
     * Adds higher order component to the registered component
     * @param {string} key The name of the registered component to whom hocs are to added
     * @param {Array<ComponentRegistryHocItem>} hocs The HOCs to compose with the raw component.
     */
    addHocs(key, ...hocs) {
        const item = super.get(key);
        if (!item) {
            throw Error(`Could not add hocs for "${key}" component. Reason: Component not found.`);
        }
        this.set(key, Object.assign({}, item, { hocs }));
    }
    /**
     * Set styles of a component.
     * @param key
     * @param styles
     */
    setStyles(key, styles) {
        const item = this.get(key);
        if (!item) {
            throw Error(`Cannot set styles "${key}" component. Reason: Component not found.`);
        }
        item.styles = styles;
        this.data = this.data.set(key, item);
    }
    /**
     * Get styles of a component
     * @param key
     */
    getStyles(key) {
        const item = this.get(key);
        if (!item) {
            return;
        }
        return item.styles;
    }
    /**
     * Convert any input value to an item. This is where you transform inputs and add defualts
     * @param key
     * @param partial
     */
    createItem(key, partial) {
        const value = utils_1.getDefiniteBlueBaseModule(partial.value);
        return super.createItem(key, Object.assign({ applyStyles: true, hocs: [], isAsync: value.isAsync, preload: false }, partial, { value }));
    }
    /**
     * Typeguard to check a given object is an input value
     * @param value
     */
    isInputValue(value) {
        return (utils_1.isBlueBaseModule(value) ||
            typeof value === 'function' ||
            (typeof value === 'object' && typeof value.render === 'function'));
    }
}
exports.ComponentRegistry = ComponentRegistry;
