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

import { isEqual } from "@applicaster/zapp-react-native-utils/equalUtils";
import { ThemeContext } from "@applicaster/zapp-react-native-utils/theme";
import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
import {
  mapKeys,
  partitionByKeys,
} from "@applicaster/zapp-react-native-utils/objectUtils";

type Props = {
  children: React.ReactNode;
  plugins: QuickBrickPlugin[];
};

const DEFAULT_THEME_ID = "base-theme";

function populateTheme(plugin) {
  const { id, getProps } = plugin?.module || {};

  if (!id || !getProps) {
    return null;
  }

  return [id, getProps(plugin?.configuration || {})];
}

const TABLET_PREFIX = "tablet_";

const prepareForTablet = (isTablet) => (themeProps) => {
  const [tabletThemeProps, mobileTheme] = partitionByKeys(
    R.compose(R.startsWith(TABLET_PREFIX), R.head),
    themeProps
  );

  if (!tabletThemeProps?.tablet_theme) {
    return mobileTheme;
  }

  const mobileThemeWithoutScreenStyles = R.compose(
    R.reduce((_theme, key) => {
      if (key.includes("padding_")) return _theme;
      _theme[key] = mobileTheme[key];

      return _theme;
    }, {}),
    R.keys
  )(mobileTheme);

  const tabletTheme = R.compose(
    R.merge(mobileThemeWithoutScreenStyles),
    mapKeys(R.replace(TABLET_PREFIX, "")),
    R.reject(R.isNil),
    R.omit(["tablet_theme"])
  )(tabletThemeProps);

  return isTablet ? tabletTheme : mobileTheme;
};

const selectThemes = (isTablet, plugins) =>
  R.compose(
    R.map(prepareForTablet(isTablet)),
    R.fromPairs,
    R.reject(R.isNil),
    R.map(populateTheme),
    R.filter(R.pathEq(["module", "isTheme"], true))
  )(plugins);

const ThemeContextProvider = ({
  themes,
  selectedThemeId,
  setSelectedThemeId,
  children,
}: any) => {
  const value = { themes, selectedThemeId, setSelectedThemeId };

  return (
    <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
  );
};

const MemoizedThemeContextProvider = React.memo(
  ThemeContextProvider,
  isEqual({
    byValue: ["selectedThemeId", "setSelectedThemeId"],
    byReference: ["children", "themes"],
  })
);

function ThemeManagerComponent({ children, plugins }: Props) {
  const isTablet = useIsTablet();

  const themes = selectThemes(isTablet, plugins);

  const [selectedThemeId, setSelectedThemeId] =
    React.useState(DEFAULT_THEME_ID);

  return (
    <MemoizedThemeContextProvider
      themes={themes}
      selectedThemeId={selectedThemeId}
      setSelectedThemeId={setSelectedThemeId}
    >
      {children}
    </MemoizedThemeContextProvider>
  );
}

export const ThemeManager = ThemeManagerComponent;
