/* Riot WIP, @license MIT */
import { IS_PURE_SYMBOL, callOrAssign, memoize } from '@riotjs/util';
import { MOCKED_TEMPLATE_INTERFACE } from './mocked-template-interface.js';
import { componentTemplateFactory } from './component-template-factory.js';
import { createPureComponent } from './create-pure-component.js';
import { instantiateComponent } from './instantiate-component.js';

/**
 * Create the component interface needed for the @riotjs/dom-bindings tag bindings
 * @param   {RiotComponentWrapper} componentWrapper - riot compiler generated object
 * @param   {string} componentWrapper.css - component css
 * @param   {Function} componentWrapper.template - function that will return the dom-bindings template function
 * @param   {Object} componentWrapper.exports - component interface
 * @param   {string} componentWrapper.name - component name
 * @returns {Object} component like interface
 */

function createComponentFromWrapper(componentWrapper) {
  const {
    css,
    template,
    exports,
    name
  } = componentWrapper;
  const templateFn = template ? componentTemplateFactory(template, componentWrapper) : MOCKED_TEMPLATE_INTERFACE;
  return _ref => {
    let {
      slots,
      attributes,
      props
    } = _ref;
    // pure components rendering will be managed by the end user
    if (exports && exports[IS_PURE_SYMBOL]) return createPureComponent(exports, {
      slots,
      attributes,
      props,
      css,
      template
    });
    const componentAPI = callOrAssign(exports) || {};
    const component = instantiateComponent({
      css,
      template: templateFn,
      componentAPI,
      name
    })({
      slots,
      attributes,
      props
    }); // notice that for the components created via tag binding
    // we need to invert the mount (state/parentScope) arguments
    // the template bindings will only forward the parentScope updates
    // and never deal with the component state

    return {
      mount(element, parentScope, state) {
        return component.mount(element, state, parentScope);
      },

      update(parentScope, state) {
        return component.update(state, parentScope);
      },

      unmount(preserveRoot) {
        return component.unmount(preserveRoot);
      }

    };
  };
}
/**
 * Performance optimization for the recursive components
 * @param  {RiotComponentWrapper} componentWrapper - riot compiler generated object
 * @returns {Object} component like interface
 */

const memoizedCreateComponentFromWrapper = memoize(createComponentFromWrapper);

export { createComponentFromWrapper, memoizedCreateComponentFromWrapper };
