import React, { useContext, memo } from 'react';
import Component from './Component';
import { ComponentDataContext, FilterDataContext, CallbackContext, InteractionContext, DataContainerContext } from './Context';
import { getState } from 'utils/interaction';
import { Utils } from '@easyv/react-gui';
import { DataFrom } from 'models/component.types';

const { getValueFromConfig } = Utils;

interface ComponentWrapProps {
  id: number;
  hideDefault: boolean;
  mountAnimation: any;
}

function ComponentWrap({ id, hideDefault, mountAnimation = {} }: ComponentWrapProps) {
  const { componentsById = {} } = useContext(ComponentDataContext);
  const { dataFilterResult } = useContext(DataContainerContext);
  const { filters = [] } = useContext(FilterDataContext);
  const { callbackKeys = {}, callbackValues = {} } = useContext(CallbackContext);
  const { interactions = [] } = useContext(InteractionContext);

  const component = componentsById[id];

  if (component) {
    const { useFilter, filters: componentFilters = [], children = [], dataContainers, dataFrom } = component;

    const usedFilters = useFilter
      ? componentFilters
          .filter((d) => d.enable)
          .map((d) => filters.find((o) => o.id === d.id))
          .filter((d) => d)
      : [];

    const dataCalbackKeys = (callbackKeys.data && callbackKeys.data[id]) || [];
    const dataCallbackValues =
      dataFrom === DataFrom.DATA_CONTAINER ? {} : dataCalbackKeys.reduce((all, item) => ({ ...all, [item]: callbackValues[item] }), {});
    const filterCallbackKeys = (callbackKeys.filter && callbackKeys.filter[id]) || [];
    const filterCallbackValues = filterCallbackKeys.reduce((all, item) => ({ ...all, [item]: callbackValues[item] }), {});
    const interactionCallbackKeys = (callbackKeys.interaction && callbackKeys.interaction[id]) || [];
    const interactionCallbackValues = interactionCallbackKeys.reduce((all, item) => ({ ...all, [item]: callbackValues[item] }), {});
    const { iState, iActiveState, bindedInteractionState } = getState({ id, interactions });

    let childrenComponent = children.map((d) => componentsById[d]).filter((d) => d);

    childrenComponent = childrenComponent.filter((d) => {
      const interaction = interactions.find((o) => o.id === d.id);
      return interaction
        ? !(interaction && interaction.state && interaction.state.show === false)
        : getValueFromConfig(d.config, [0], 'show') !== false;
    });

    const childrenUsedFilters = childrenComponent.map((child) => {
      const { useFilter, filters: componentFilters } = child;
      const childUsedFilters = useFilter
        ? componentFilters
            .filter((d) => d.enable)
            .map((d) => filters.find((o) => o.id === d.id))
            .filter((d) => d)
        : [];
      return childUsedFilters;
    });

    const childrenCallbackValues = childrenComponent.map((child) => {
      const { id: childId, dataFrom: childDataFrom } = child;
      const childDataCalbackKeys = (callbackKeys.data && callbackKeys.data[childId]) || [];
      const childDataCallbackValues =
        childDataFrom === DataFrom.DATA_CONTAINER
          ? {}
          : childDataCalbackKeys.reduce((all, item) => ({ ...all, [item]: callbackValues[item] }), {});
      const childFilterCallbackKeys = (callbackKeys.filter && callbackKeys.filter[childId]) || [];
      const childFilterCallbackValues = childFilterCallbackKeys.reduce((all, item) => ({ ...all, [item]: callbackValues[item] }), {});
      const childInteractionCallbackKeys = (callbackKeys.interaction && callbackKeys.interaction[childId]) || [];
      const childInteratcionCallbackValues = childInteractionCallbackKeys.reduce(
        (all, item) => ({ ...all, [item]: callbackValues[item] }),
        {}
      );

      return {
        data: childDataCallbackValues,
        filter: childFilterCallbackValues,
        interaction: childInteratcionCallbackValues
      };
    });
    const childrenDataCallbackValues = childrenCallbackValues.map((d) => d.data);
    const childrenFilterCallbackValues = childrenCallbackValues.map((d) => d.filter);
    const childrenInteractionCallbackValues = childrenCallbackValues.map((d) => d.interaction);

    const getContainerIds = () => {
      let ids = dataFrom === DataFrom.DATA_CONTAINER ? dataContainers.map((d) => d.id) : [];
      childrenComponent.map((child) => {
        const { dataFrom, dataContainers } = child;
        if (dataFrom === DataFrom.DATA_CONTAINER) {
          ids = ids.concat(dataContainers.map((c) => c.id));
        }
      });
      return ids;
    };
    const currentFilterRestlt = () => {
      const result = {};
      if (dataFilterResult) {
        getContainerIds()?.map((d) => {
          result[d] = dataFilterResult[d];
        });
      }
      return result;
    };

    return (
      <Component
        hideDefault={hideDefault}
        mountAnimation={mountAnimation}
        component={component}
        childrenComponent={childrenComponent}
        iState={iState}
        iActiveState={iActiveState}
        bindedInteractionState={bindedInteractionState}
        filters={usedFilters}
        dataFilterResult={currentFilterRestlt()}
        dataCallbackValues={dataCallbackValues}
        filterCallbackValues={filterCallbackValues}
        interactionCallbackValues={interactionCallbackValues}
        childrenFilters={childrenUsedFilters}
        childrenDataCallbackValues={childrenDataCallbackValues}
        childrenFilterCallbackValues={childrenFilterCallbackValues}
        childrenInteractionCallbackValues={childrenInteractionCallbackValues}
      />
    );
  } else {
    return null;
  }
}

export default memo(ComponentWrap);
