import React, { useCallback } from 'react';
import { Adaptor } from './adaptor';
import { ComponentActionHandler } from './actionHandler';
import { PositionHandler } from './PositionHandler';
import { emitCustomEvent } from './customEventTrigger';
import { on, emitPage, PageEventListenerTypes } from './eventListener';
import { componentNodeMap, getComponentNode } from './componentNodeMap';
import { onComponentEventAction } from './componentEventActionEmitter';

function ComponentItem({ meta, global, instance, ...injectProps }) {
  const {
    key,
    children,
    component: { component: Component },
    data,
    style,
    commonStyle,
    position,
  } = instance;

  const emit = useCallback(trigger => emitCustomEvent(instance, trigger, global, meta), [
    instance,
    global,
    meta,
  ]);

  const on = useCallback(
    (eventName, callback) => onComponentEventAction(instance, eventName, callback),
    [instance]
  );

  if (children) {
    return (
      <Component
        key={key}
        componentKey={key}
        data={data}
        meta={meta}
        global={global}
        style={style}
        commonStyle={commonStyle}
        emit={emit}
        on={on}
      >
        {children.map(childInstance => (
          <ComponentItem
            key={childInstance.key}
            instance={childInstance}
            meta={meta}
            global={global}
          />
        ))}
      </Component>
    );
  }

  const content = (
    <ComponentActionHandler instance={instance} meta={meta} global={global}>
      <Adaptor instance={instance} injectProps={injectProps} meta={meta} global={global} />
    </ComponentActionHandler>
  );

  if (position) {
    return <PositionHandler positionStyle={position}>{content}</PositionHandler>;
  }

  return content;
}

export class AppRender extends React.Component {
  componentWillMount() {
    const { pluginInstances, global, meta } = this.props;

    pluginInstances.forEach(({ plugin: { plugin }, data, key }) => {
      plugin({
        data,
        key,
        global,
        meta,
        on,
        componentsMap: componentNodeMap,
        getComponentByKey: getComponentNode,
      });
    });

    emitPage(PageEventListenerTypes.INIT, { global, meta });
  }

  render() {
    const { componentInstances, global, meta } = this.props;
    return (
      <>
        {componentInstances.map(instance => (
          <ComponentItem key={instance.key} instance={instance} meta={meta} global={global} />
        ))}
      </>
    );
  }
}
