/* eslint-disable react-hooks/rules-of-hooks */
import * as R from "ramda";
import { allSettled } from "promise";
import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";

import * as React from "react";
import { coreAppLogger } from "../logger";
const logger = coreAppLogger.addSubsystem("AppLifeCycleManager");

const debugActions = (actions) =>
  logger.debug({
    message: `useSubscribeToActionProviders - available actions count: ${
      Object.keys(actions).length
    }`,
    data: { actions },
  });

const warnUndefinedContext = (context) =>
  logger.warning({
    message: "One of your action plugins has an undefined context value",
    data: { context },
  });

type Subscription = {
  [x: string]: () => any;
};

const getModuleContext = R.path(["module", "context"]);

const getContexts = R.compose(
  R.map((action) => {
    const item = getModuleContext(action);
    item["pluginId"] = action.name;

    return item;
  }),
  R.values
);

const useSubscribeToActionProviders = () => {
  // @ts-ignore
  const actionContext = useActions();

  React.useEffect(() => {
    if (!actionContext || !actionContext.actions) return;
    debugActions(actionContext.actions);
  }, [actionContext]);

  const subscriptions = getContexts(actionContext.actions).map((context) => {
    const subscription = React.useContext<{}>(context);

    if (subscription) {
      subscription["pluginId"] = context.pluginId;

      return subscription;
    } else {
      warnUndefinedContext(context);
    }
  });

  return subscriptions || [];
};

export const useRiverInitialState = () => {
  const key = "getRiverInitialState";
  const actionProvidersSubscriptions = useSubscribeToActionProviders();

  const subscriptions = React.useMemo(() => {
    if (!actionProvidersSubscriptions.length) return undefined;

    return actionProvidersSubscriptions.reduce((acc, item) => {
      const riverInitialStatePromise = item[key]?.();

      if (riverInitialStatePromise) {
        acc.push(riverInitialStatePromise);
      }

      return acc;
    }, [] as Subscription[]);
  }, [actionProvidersSubscriptions]);

  if (!actionProvidersSubscriptions.length) return undefined;

  return subscriptions;
};

const getActionInitialStateSetters = (key) => {
  return R.compose(
    R.map((subscription: { [x: string]: any; pluginId: any }) => {
      return async () => {
        const now = performance.now();

        logger.info({
          message: `Invocation Started - action plugin ${key}, pluginId: ${subscription.pluginId}`,
        });

        const promiseFunc = subscription[key];

        const result = await promiseFunc();

        logger.info({
          message: `Invocation Completed - action plugin ${key}, pluginId: ${
            subscription.pluginId
          }: ${performance.now() - now} ms`,
        });

        return result;
      };
    }),
    R.filter((subscription: { [x: string]: any }) => {
      return subscription[key];
    })
  );
};

export const useActionSetters = (key: string = "getInitialState") => {
  const actionProvidersSubscriptions = useSubscribeToActionProviders();
  if (!actionProvidersSubscriptions.length) return undefined;

  const subscriptions = React.useMemo(() => {
    if (!actionProvidersSubscriptions.length) return undefined;

    return getActionInitialStateSetters(key)(actionProvidersSubscriptions);
  }, [key, actionProvidersSubscriptions]);

  if (!actionProvidersSubscriptions.length) return undefined;

  return subscriptions;
};

export async function initializeActionSetters(actionSetters: any) {
  if (!actionSetters) return Promise.resolve();

  const loaders: Promise<{}>[] = actionSetters.map(
    (setter: () => Promise<{}>) => {
      return setter();
    }
  );

  return allSettled(loaders);
}
