import * as React from "react";
import {
  Platform,
  RefreshControl as RNRefreshControl,
  StyleSheet,
} from "react-native";
import * as R from "ramda";
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
import { useLocalizedStrings } from "@applicaster/zapp-react-native-utils/localizationUtils";
import { useAnalytics } from "@applicaster/zapp-react-native-utils/analyticsUtils";
import { useSendAnalyticsEventWithFunction } from "@applicaster/zapp-react-native-utils/analyticsUtils/helpers/hooks";
import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
import { useDispatch } from "react-redux";
import { useShallow } from "zustand/react/shallow";
import { useScreenContextV2 } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
import { useSafeAreaInsets } from "react-native-safe-area-context";

const BRIGHTNESS_THRESHOLD = 160;
const ABOVE_DEFAULT_COLOR = "gray";
const BELOW_DEFAULT_COLOR = "white";
const BASE_INDICATOR_HEIGHT = 40;
const BASE_INDICATOR_OFFSET = 16;

/** Return spacing required to position indicator below the navbar bottom line (Android only) */
const getRefreshControlOffset = () => {
  return Platform.OS === "ios"
    ? 0
    : BASE_INDICATOR_HEIGHT + BASE_INDICATOR_OFFSET;
};

const styles = StyleSheet.create({
  // eslint-disable-next-line react-native/no-color-literals
  control: {
    zIndex: 1,
    backgroundColor: "transparent",
  },
});

const getBrightness = (RGBcolor) => {
  const RGBvalues = RGBcolor.substring(
    RGBcolor.indexOf("(") + 1,
    RGBcolor.length - 1
  )
    .replace(/\s/g, "")
    .split(",");

  return Math.floor(
    Math.sqrt(
      Number(RGBvalues[0]) ** 2 * 0.241 +
        Number(RGBvalues[1]) ** 2 * 0.691 +
        Number(RGBvalues[2]) ** 2 * 0.068
    )
  );
};

export const usePullToRefresh = (
  riverComponents,
  pullToRefreshPipesV1RefreshingStateUpdater,
  refreshingPipesV1
) => {
  const isPipesV1 = !!pullToRefreshPipesV1RefreshingStateUpdater;

  const dispatch = useDispatch();

  const [refreshing, setRefreshing] = React.useState(false);

  const feeds: string[] =
    riverComponents?.map(R.path(["data", "source"])).filter((feed) => !!feed) ??
    [];

  const screenData = useCurrentScreenData();

  const feedsLength = feeds.length;

  const [requestsCompletedCounter, setRequestsCompletedCounter] =
    React.useState(0);

  React.useEffect(() => {
    // will not work for pipes v1 on 1st level screens
    if (refreshing && !isPipesV1) {
      feeds.forEach((feed) => {
        dispatch(
          loadPipesData(feed, {
            silentRefresh: true,
            clearCache: true,
            callback: () => {
              setRequestsCompletedCounter(R.inc);
            },
            riverId: screenData.id,
          })
        );
      });
    }
  }, [refreshing, isPipesV1]);

  React.useEffect(() => {
    if (requestsCompletedCounter === feedsLength) {
      setRefreshing(false);
    }
  }, [requestsCompletedCounter, feedsLength]);

  const onRefresh = React.useCallback(() => {
    if (isPipesV1) {
      pullToRefreshPipesV1RefreshingStateUpdater(true);
    } else {
      setRefreshing(true);
      setRequestsCompletedCounter(0);
    }
  }, [isPipesV1]);

  return {
    refreshing: isPipesV1 ? refreshingPipesV1 : refreshing,
    onRefresh,
  };
};

/** Returns the offset for the progress view of the RefreshControl component
 *  based on navbar content position */
export const useGetProgressViewOffset = () => {
  const { _navBarStore } = useScreenContextV2();
  const { top } = useSafeAreaInsets();

  const offset = getRefreshControlOffset();

  const { height, contentPosition } = _navBarStore(
    useShallow(({ contentPosition, height }) => ({ contentPosition, height }))
  );

  if (height === 0) {
    return offset;
  }

  switch (contentPosition) {
    case "on_bottom_status_bar":
      // navbar height
      return offset + height;
    case "on_top_screen":
      // navbar height + status bar height
      return offset + height + top;
    default:
      return offset;
  }
};

export function RefreshControl(props: {
  pullToRefreshPipesV1RefreshingStateUpdater?: (refreshing: boolean) => void;
  refreshingPipesV1?: boolean;
}) {
  const screenData = useCurrentScreenData();

  const { refreshing, onRefresh } = usePullToRefresh(
    screenData.ui_components,
    props.pullToRefreshPipesV1RefreshingStateUpdater,
    props.refreshingPipesV1
  );

  const { app_background_color: themeBackgroundColor } = useTheme();

  const localizedStrings = useLocalizedStrings({
    localizations: screenData?.localizations || {},
  });

  const {
    indicatorColor,
    titleUnderIndicatorColor,
    indicatorBackgroundColor,
    indicatorSize,
    generalContentBackgroungColor,
    displayTitleIOS,
  } = React.useMemo(
    () => ({
      indicatorColor: R.prop(
        "pull_to_refresh_indicator_color",
        screenData.styles
      ),
      titleUnderIndicatorColor: R.prop(
        "pull_to_refresh_title_color_under_indicator",
        screenData.styles
      ),
      indicatorBackgroundColor: R.prop(
        "pull_to_refresh_indicator_bg_color",
        screenData.styles
      ),
      indicatorSize:
        R.prop("pull_to_refresh_indicator_size", screenData.styles) === "large"
          ? "large"
          : "default",
      generalContentBackgroungColor: R.prop(
        "screen_background_color",
        screenData.styles
      ),
      displayTitleIOS: R.prop(
        "pull_to_refresh_display_title_ios",
        screenData.styles
      ),
    }),
    [screenData]
  );

  const {
    preparedIndicatorColor,
    preparedTitleUnderIndicatorColor,
    preparedIndicatorBackgroundColor,
  } = React.useMemo(() => {
    if (
      indicatorColor &&
      titleUnderIndicatorColor &&
      indicatorBackgroundColor
    ) {
      return {
        preparedIndicatorColor: indicatorColor,
        preparedTitleUnderIndicatorColor: titleUnderIndicatorColor,
        preparedIndicatorBackgroundColor: indicatorBackgroundColor,
      };
    }

    const brightness = getBrightness(
      generalContentBackgroungColor || themeBackgroundColor
    );

    const defaultColor =
      brightness > BRIGHTNESS_THRESHOLD
        ? ABOVE_DEFAULT_COLOR
        : BELOW_DEFAULT_COLOR;

    const defaultIndicatorBackgroundColor =
      brightness > BRIGHTNESS_THRESHOLD
        ? BELOW_DEFAULT_COLOR
        : ABOVE_DEFAULT_COLOR;

    return {
      preparedIndicatorColor: indicatorColor || defaultColor,
      preparedTitleUnderIndicatorColor:
        titleUnderIndicatorColor || defaultColor,
      preparedIndicatorBackgroundColor:
        indicatorBackgroundColor || defaultIndicatorBackgroundColor,
    };
  }, [
    indicatorColor,
    titleUnderIndicatorColor,
    indicatorBackgroundColor,
    generalContentBackgroungColor,
    themeBackgroundColor,
  ]);

  const { sendScreenEvent } = useAnalytics();

  const callbackSendAnalyticsEvent = useSendAnalyticsEventWithFunction();

  const onRefreshHandler = React.useCallback(() => {
    callbackSendAnalyticsEvent({
      sendAnalyticsFunction: sendScreenEvent,
      extraProps: { forceReload: true },
    });

    onRefresh();
  }, [onRefresh, screenData]);

  return (
    <RNRefreshControl
      {...props}
      refreshing={refreshing}
      onRefresh={onRefreshHandler}
      colors={[preparedIndicatorColor]}
      progressViewOffset={useGetProgressViewOffset()}
      progressBackgroundColor={preparedIndicatorBackgroundColor}
      // @ts-ignore in RN68 this `size` became string
      size={indicatorSize}
      tintColor={preparedIndicatorColor}
      title={
        displayTitleIOS
          ? localizedStrings?.pull_to_refresh_title_under_indicator ||
            "reloading..."
          : null
      }
      titleColor={preparedTitleUnderIndicatorColor}
      style={styles.control}
    />
  );
}
