import isEqual from "lodash/isEqual";
import React, { useEffect, useMemo, useState } from "react";
import { View } from "react-native";
import { useDispatch, useSelector } from "react-redux";
import { commonStyles } from "../../Container/Navi-Insurance/Styles";
import { ActionMetaData, GenericActionPayload } from "../actions/GenericAction";
import { sendAsAnalyticsEvent } from "../hooks/useAnalyticsEvent";
import { useBottomSheet } from "../hooks/useBottomSheet";
import { logToSentry } from "../hooks/useSentryLogging";
import { CtaData } from "../interface";
import { ModalView } from "../interface/modals/ModalView";
import { ScreenData } from "../interface/widgets/screenData/ScreenData";
import { Router } from "../navigator/NavigationRouter";
import { updateCtaData } from "../redux/screens/screenActionCreators";
import { setCurrentScreenName } from "../utilities/AlfredUtils";
import {
  getCacheKey,
  getScreenDataFromCache,
  isScreenWhiteListedForCaching,
  saveScreenDataInCache,
} from "../utilities/CacheUtils";
import {
  getScreenMapperNameFromCtaData,
  getScreenNameFromCtaData,
} from "../utilities/MiscUtils";
import { WidgetActionTypes } from "../widgets/widget-actions/WidgetActionTypes";
import { ScreenMapper } from "./screen-mappers/ScreenMapper";
import useScreenLoadTime from "../hooks/useScreenLoadTime";

const BaseScreen: React.FC<{ navigation: any; route: any }> = ({
  navigation,
  route,
}) => {
  const [screenData, setScreenData] = useState<ScreenData | null>(null);
  const [screenName, setScreenName] = useState<string | null>(null);
  const [screenKey, setScreenKey] = useState<string | null>(null);
  const [screenState, setScreenState] = useState<ScreenState | null>(
    ScreenState.LOADING,
  );
  const [errorMetaData, setErrorMetaData] = useState<ActionMetaData[] | null>(
    null,
  );

  useEffect(() => {
    const cacheKey = getCacheKey(screenName, screenKey);
    if (!screenData) {
      const screenInitialData: ScreenData = {
        screenState: ScreenState.LOADING,
      };
      setScreenData(screenInitialData);
    }
    if (!!cacheKey && isScreenWhiteListedForCaching(screenName)) {
      if (
        !(
          !!screenData?.errorMetaData ||
          screenData?.screenState === ScreenState.ERROR
        )
      ) {
        saveScreenDataInCache(screenName, screenData);
      }
    }
  }, [screenData]);

  useEffect(() => {
    if (!!getScreenNameFromCtaData(route.params?.ctaData)) {
      setScreenName(getScreenNameFromCtaData(route.params?.ctaData)!!);
      if (!!route.params?.ctaData?.screenKey) {
        setScreenKey(route.params?.ctaData?.screenKey);
      }
      if (isScreenWhiteListedForCaching(screenName)) {
        retrieveScreenDataFromCache(
          getScreenNameFromCtaData(route.params?.ctaData)!!,
          route.params?.ctaData?.screenKey,
        );
      }
    }
  }, []);

  const dispatch = useDispatch();

  const retrieveScreenDataFromCache = (
    screenName: string | null | undefined,
    screenKey: string | null | undefined,
  ) => {
    let cacheKey = getCacheKey(screenName, screenKey);
    if (!!cacheKey) {
      getScreenDataFromCache(cacheKey).then(screenData => {
        if (!!screenData) {
          setScreenData(screenData);
        }
      });
    }
  };

  const { cta } = useSelector((state: any) => {
    const savedCta = state.screenReducer.ctaData;
    if (isEqual(savedCta, route.params.ctaData)) {
      return { cta: state.screenReducer.ctaData };
    }
    return { cta: route.params.ctaData };
  });

  useEffect(() => {
    const ctaData: CtaData = route.params.ctaData;
    if (!isEqual(cta, ctaData)) {
      dispatch(updateCtaData({ cta: ctaData, setScreenState: screenState }));
    }
  }, [route.params.ctaData, screenState]);
  useScreenLoadTime(screenName, screenData?.screenState);

  const handleActions = (actionPayload?: GenericActionPayload) => {
    actionPayload?.metaData?.forEach(ActionMetaData => {
      if (!!ActionMetaData.analyticsEventProperties) {
        sendAsAnalyticsEvent(ActionMetaData.analyticsEventProperties);
      }
      if (ActionMetaData.actionType === WidgetActionTypes.OPEN_BOTTOM_SHEET) {
        addBottomSheet(ActionMetaData.data as ModalView);
      }
      if (
        ActionMetaData.actionType === WidgetActionTypes.REPLACE_BOTTOM_SHEET
      ) {
        replaceBottomSheet(ActionMetaData.data as ModalView);
      }
    });
    const updatedActionPayload: GenericActionPayload = {
      ...(actionPayload as GenericActionPayload),
      setScreenData,
      setScreenState,
      setErrorMetaData,
      ctaData: cta,
      screenData: { ...screenData },
    };
    if (!!actionPayload) {
      Router.handleAction(updatedActionPayload, navigation);
    } else {
      // handle error
      logToSentry(
        `Action payload is missing or invalid: ${actionPayload} | MethodName: handleActions`,
      );
    }
  };

  const { bottomsheet, addBottomSheet, replaceBottomSheet } =
    useBottomSheet(handleActions);

  const MemoizedScreenMapper = useMemo(() => {
    const secondIdentifier = getScreenMapperNameFromCtaData(cta);
    setCurrentScreenName(
      "RN_" + secondIdentifier?.toUpperCase() + "_" + screenName,
    );

    return (
      <View style={commonStyles.flex_1}>
        {ScreenMapper.getScreenMapper(cta, screenData, handleActions)}
      </View>
    );
  }, [cta, screenData]);

  return (
    <View style={commonStyles.flex_1}>
      {MemoizedScreenMapper}
      {bottomsheet.map((sheet, index) => (
        <React.Fragment key={`bottomSheet-${index}`}>{sheet}</React.Fragment>
      ))}
    </View>
  );
};

export enum ScreenState {
  LOADING,
  LOADED,
  ERROR,
  OVERLAY,
}

export default BaseScreen;
