import * as R from "ramda";
import isEmpty from "lodash/isEmpty";
import { Dimensions, NativeModules } from "react-native";
import {
  loadAppContextData,
  AppData,
} from "@applicaster/zapp-react-native-redux";
import { isTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
import { mapPromises } from "@applicaster/zapp-react-native-utils/arrayUtils";
import { fetchPluginConfiguration, getPromiseForType } from "../helpers";
import { cacheAssets } from "../../AssetCache";
import { logger } from "@applicaster/zapp-react-native-utils/logger";
import { ACTIVE_LAYOUT_ID_STORAGE_KEY } from "../consts";
const { AppLoaderBridge } = NativeModules;
import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
import { useErrorStore } from "../../ErrorBoundary/store";

export async function getNativeRemoteContextData(
  dispatch,
  runtimeConfigurationUrls,
  plugins
) {
  const { width, height } = Dimensions.get("window");

  const isTabletDevice = isTablet(
    { width, height },
    width > height ? "landscape" : "portrait"
  );

  const generalConfiguration = await mapPromises(getPromiseForType, [
    "remoteConfigurations",
    "pluginConfigurations",
    "pipesEndpoints",
  ]);

  loadAppContextData(dispatch, R.mergeAll([...generalConfiguration]));

  try {
    const layoutManagerPlugin = R.find(
      R.pathSatisfies(R.is(Function), ["module", "selectLayout"])
    )(plugins);

    if (layoutManagerPlugin) {
      await layoutManagerPlugin.module?.selectLayout({
        runtimeConfigurationUrls,
        plugin: layoutManagerPlugin,
        isTablet: isTabletDevice,
      });
    } else {
      const layoutId = await localStorage.getItem(ACTIVE_LAYOUT_ID_STORAGE_KEY);

      if (layoutId) {
        await AppLoaderBridge?.switchLayout(layoutId, null);
      }
    }
  } catch (error) {
    logger.error({
      message: "Error selecting layout using layout manager plugin",
      data: error,
    });
  }

  const layout = await getPromiseForType("layout");

  const layoutLoadingErrorMessage = "Failed to load layout data";

  if (isEmpty(layout)) {
    useErrorStore
      .getState()
      .setError(
        new Error(layoutLoadingErrorMessage),
        layoutLoadingErrorMessage,
        false
      );
  }

  const apiVersion = layout?.layout?.["api_version"]; // Taken from remote configuration

  dispatch(AppData.actions.merge({ layoutVersion: apiVersion || "v1" }));

  const resolvedPromises = await mapPromises(getPromiseForType, ["cellStyles"]);

  let optionalResolvedPromise;

  try {
    optionalResolvedPromise = await getPromiseForType("presetsMapping");
  } catch (e) {
    // don't break loading sequence if presetsMapping does not exist
    // only general error could be intercepted here so no way divide flow
  }

  const remoteData = R.mergeAll([
    ...resolvedPromises,
    ...generalConfiguration,
    optionalResolvedPromise,
    layout,
  ]);

  const cachedRemoteData = await cacheAssets({
    layout: remoteData.layout,
    pluginConfigurations: remoteData.pluginConfigurations,
    cellStyles: remoteData.cellStyles,
  });

  const { pluginConfigurations } = cachedRemoteData;

  const updatedPlugins = R.map(
    fetchPluginConfiguration(pluginConfigurations),
    plugins
  );

  const appProperties = R.compose(
    R.mergeLeft({
      contentTypes: remoteData.layout?.content_types,
      rivers: cachedRemoteData.layout,
      cellStyles: cachedRemoteData.cellStyles,
    }),
    R.omit(["layout"])
  )(remoteData);

  if (remoteData.presetsMapping) {
    appProperties.presetsMapping = remoteData.presetsMapping;
  }

  loadAppContextData(dispatch, {
    ...appProperties,
    plugins: updatedPlugins,
  });
}
