import * as React from "react";
import * as R from "ramda";

import { ActionsContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ActionsContext";
import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";

type Props = {
  children: React.ReactNode;
  rivers: Record<string, any>;
  plugins: {}[];
  useLocation: () => {};
  useHistory: () => {};
};

type Plugin = Record<string, any> & {
  identifier: string;
};

type PluginsIdMap = Record<string, Plugin>;

const getActionPlugins = (plugins) =>
  R.filter(R.path(["module", "actionName"]))(plugins);

/**
 * this functions translates array of objects,
 * to object of keys create from original object.identifier
 */

const abstractIdentifier = (actionPlugins: Plugin[]): PluginsIdMap =>
  R.compose(
    R.mergeAll,
    R.map((plugin) => ({ [plugin.identifier]: plugin }))
  )(actionPlugins);

/**
 * Component returning children.
 * Can be used to create Component from children
 */
const ChildrenWrapper = ({
  children,
}: {
  children: React.ReactElement<any>;
}) => {
  return children;
};

/**
 * It wraps children in multiple context providers
 * @param contexts - Array of React Context Providers
 */
const contextComposer = (contexts: Plugin[]): React.ExoticComponent =>
  R.compose(...contexts)(ChildrenWrapper);

/**
 * ActionsProvider is a React Context Provider for a ActionPlugins
 * @param props.plugins - list of app plugins
 * @return  Returns Children wrapped in the Action providers
 */
export function ActionsProvider(props: Props) {
  const { children, plugins } = props;

  const actionPlugins = React.useMemo(
    () =>
      R.ifElse(
        isNilOrEmpty,
        R.always([]),
        R.compose(abstractIdentifier, getActionPlugins)
      )(plugins),
    [plugins]
  );

  const contextProviders = React.useMemo((): [Plugin] | [] => {
    try {
      const providers = R.compose(
        R.map(R.path(["module", "contextProvider"])),
        getActionPlugins
      )(plugins);

      return providers;
    } catch (err) {
      return [];
    }
  }, []);

  const Context = React.useMemo(
    () =>
      contextProviders?.length
        ? contextComposer(contextProviders)
        : React.Fragment,
    []
  );

  return (
    <ActionsContext.Provider value={{ actions: actionPlugins }}>
      <Context>{children}</Context>
    </ActionsContext.Provider>
  );
}
