import * as React from "react";
import { AppState, AppStateStatus } from "react-native";
import * as R from "ramda";

import { connectToStore } from "@applicaster/zapp-react-native-redux/utils/connectToStore";
import { setAppState } from "@applicaster/zapp-react-native-redux/appState";
import { Dispatch } from "@reduxjs/toolkit";

type Props = {
  Component: () => React.ComponentType<any>;
  plugins: [{}];
  dispatch: Dispatch;
};

function withAppManagerDecorator(
  Component: React.ComponentType<any>
): React.ComponentType<any> {
  return class AppStateManagerComponent extends React.Component<Props> {
    currentState: AppStateStatus;
    isAvailable: boolean;
    plugins: QuickBrickPlugin[];
    appStateListener: ReturnType<typeof AppState.addEventListener>;

    constructor(props: Props) {
      super(props);

      this.currentState = AppState.currentState;
      this.isAvailable = true;
      this.plugins = [];
    }

    componentDidMount() {
      this.plugins = this.getAppStatePlugins();

      this.appStateListener = AppState.addEventListener(
        "change",
        this.onChange
      );
    }

    componentWillUnmount() {
      this.appStateListener.remove();
    }

    dispatchAction(nextState: AppStateStatus, eventType) {
      const { isAvailable, currentState } = this;
      const { dispatch } = this.props;

      this.currentState = nextState;
      this.sendAppStateToPlugins(this.plugins, nextState, currentState);

      dispatch(
        setAppState({
          isAvailable,
          currentState,
          nextState,
          eventType,
        })
      );
    }

    getAppStatePlugins() {
      return R.compose(
        R.sortBy(R.path(["module", "weight"])),
        R.filter(R.pathEq(["module", "isAppStateListener"], true)),
        R.prop("plugins")
      )(this.props);
    }

    onChange = (nextState: AppStateStatus) => {
      this.dispatchAction(nextState, "change");
    };

    sendAppStateToPlugins(
      plugins: QuickBrickPlugin[],
      appState: AppStateStatus,
      previousAppState?: AppStateStatus
    ) {
      const [currentPlugin, ...remainingPlugins] = plugins;

      if (currentPlugin && currentPlugin.module) {
        return currentPlugin.module
          .run(appState, currentPlugin.configuration, {
            previousAppState,
          })
          .then((next) => {
            if (next) {
              if (remainingPlugins && remainingPlugins.length) {
                return this.sendAppStateToPlugins(
                  remainingPlugins,
                  appState,
                  previousAppState
                );
              }
            }
          });
      }
    }

    render() {
      return <Component {...this.props} />;
    }
  };
}

export const withAppManager = R.compose(
  connectToStore(R.pick(["plugins"])),
  withAppManagerDecorator
);
