/* eslint-disable @typescript-eslint/no-explicit-any */
import React, { useEffect, useState } from 'react';
import { View } from 'react-native';
import BottomSheet from '../../helpers/BottomSheet/BottomSheet';
import { RequestRenderingEvent, UnitComponentsMessage } from '../../messages/webMessages/unitComponentsMessages';

import { getStylesObject } from './UNBottomSheetComponent.styles';
import {
  BottomSheetNativePlaceType,
  BottomSheetRenderingType,
  BottomSheetSlotData,
  NativeComponentData,
  ScrollState,
} from '../../types/internal/bottomSheet.types';
import {
  BottomSheetNativeMessage,
  BottomSheetRenderingMessage,
} from '../../messages/nativeMessages/bottomSheetMessage';
import { withReduxStore } from '../../helpers/store/helpers';
import { useListenerToEvent } from '../../hooks/useListenerToEvent';
import { useDispatch, useSelector } from 'react-redux';
import { fullScreenHeight, overFullScreenHeight } from './UNBottomSheetComponent.constants';
import { RootState } from '../../store';

import {
  resetBottomSheetSlice,
  setIsBottomSheetActive,
  setIsComponentLoading,
  setNativePlace,
  setScrollState,
  setShouldEnableBottomSheetScroll,
  setShouldShowBottomSheet,
} from '../../slices/BottomSheetSlice';
import UNBottomSheetSlotComponent from './components/UNBottomSheetSlotComponent/UNBottomSheetSlotComponent';
import UNBottomSheetNativeComponent from './components/UNBottomSheetNativeComponent/UNBottomSheetNativeComponent';
import { WebComponentType } from '../../types/internal/webComponent.types';
import { getNativeComponentDataFromEvent } from './UNBottomSheetComponent.utils';

const UNBottomSheetComponent = () => {
  const dispatch = useDispatch();

  const isBottomSheetActive = useSelector((state: RootState) => state.bottomSheet.isBottomSheetActive);
  const isComponentLoading = useSelector((state: RootState) => state.bottomSheet.isComponentLoading);
  const shouldShowBottomSheet = useSelector((state: RootState) => state.bottomSheet.shouldShowBottomSheet);
  const nativePlace = useSelector((state: RootState) => state.bottomSheet.nativePlace);
  const componentHeight = useSelector((state: RootState) => state.bottomSheet.componentHeight);
  const scrollState = useSelector((state: RootState) => state.bottomSheet.scrollState);
  const shouldEnableBottomSheetScroll = useSelector((state: RootState) => state.bottomSheet.shouldEnableBottomSheetScroll);
  const [renderingType, setRenderingType] = useState<BottomSheetRenderingType>();
  const [height, setHeight] = useState(0);
  const [sliderMaxHeight, setSliderMaxHeight] = useState(overFullScreenHeight);
  const [nativeComponentData, setNativeComponentData] = useState<NativeComponentData>();
  const [requestRenderingEventData, setRequestRenderingEventData] = useState<RequestRenderingEvent>();
  const [componentParams, setComponentParams] = useState<{
    componentName?: WebComponentType,
    componentResourceId?: string
  }>();
  
  const [currentBottomSheetRenderingMessage, setCurrentBottomSheetRenderingMessage] = useState<BottomSheetRenderingMessage>();
  const styles = getStylesObject();

  useEffect(() => {
    const setHeightFromNativePlace = () => {
      switch (nativePlace) {
        // In the case of overFullScreen, set the height to the overFullScreenHeight.
        case BottomSheetNativePlaceType.overFullScreen:
          setHeight(overFullScreenHeight);
          break;
        // For modal native place type, set the height to the fullScreenHeight.
        case BottomSheetNativePlaceType.modal:
          setHeight(fullScreenHeight);
          break;
        default:
          // In general, we want the bottom sheet to fully contain the component,
          // thus adjusting its height to the component height, up to the maximum of overFullScreenHeight.
          if (componentHeight) {
            setHeight(componentHeight < overFullScreenHeight ? componentHeight : overFullScreenHeight);
          }
          break;
      }
    };

    const setSliderMaxHeightFromNativePlace = () => {
      if (nativePlace === BottomSheetNativePlaceType.modal) {
        setSliderMaxHeight(fullScreenHeight);
      } else {
        setSliderMaxHeight(overFullScreenHeight);
      }
    };

    // Check if the inner contained component is still loading or the bottom sheet should not be shown.
    if (isComponentLoading || !shouldShowBottomSheet) {
      // If so, hide the bottom sheet by setting the height to 0.
      setHeight(0);
    } else {
      // If not, display the bottom sheet by calculating and setting the height based on the native place type.
      setHeightFromNativePlace();
      setSliderMaxHeightFromNativePlace();
    }
  }, [componentHeight, nativePlace, isComponentLoading, shouldShowBottomSheet]);

  useEffect(() => {
    const resetBottomSheetManagerState = () => {
      setComponentParams(undefined);
      setRequestRenderingEventData(undefined);
      setNativeComponentData(undefined);
      setRenderingType(undefined);
      setHeight(0);
      setSliderMaxHeight(overFullScreenHeight);
    };

    if (!isBottomSheetActive) {
      dispatch(resetBottomSheetSlice());
      resetBottomSheetManagerState();
    }
  }, [isBottomSheetActive, dispatch]);

  const requestRendering = (rendering: BottomSheetRenderingMessage) => {
    if (isBottomSheetActive) {
      dispatch(setShouldShowBottomSheet(false));
    }

    handleRequestRendering(rendering);

    if (isBottomSheetActive) {
      setTimeout(() => dispatch(setShouldShowBottomSheet(true)), 400);
    } else {
      dispatch(setIsBottomSheetActive(true));
      dispatch(setShouldShowBottomSheet(true));
    }
  };

  const handleCloseFlow = () => {
    dispatch(setIsBottomSheetActive(false));
  };

  useListenerToEvent({ busEventKey: BottomSheetNativeMessage.REQUEST_RENDERING, action: requestRendering });
  useListenerToEvent({ busEventKey: UnitComponentsMessage.UNIT_REQUEST_CLOSE_FLOW, action: handleCloseFlow });

  const handleRequestRendering = (rendering: BottomSheetRenderingMessage) => {
    if (rendering === currentBottomSheetRenderingMessage) {
      return;
    } else {
      setCurrentBottomSheetRenderingMessage(rendering);
    }
    dispatch(setIsComponentLoading(true));
    switch (rendering.type) {
      //if slot check if we know this component and want to show it, otherwise get directly the component
      case BottomSheetRenderingType.Slot:
        determineRenderingTypeFromEvent(rendering.data as BottomSheetSlotData);
        break;
      case BottomSheetRenderingType.NativeComponent:
        setupDataForNativeComponent(rendering.data as NativeComponentData);
        break;
      default:
        break;
    }
  };

  const determineRenderingTypeFromEvent = (event: BottomSheetSlotData) => {
    const nativeComponentDataFromEvent = getNativeComponentDataFromEvent(event);
    if (nativeComponentDataFromEvent) {
      setupDataForNativeComponent(nativeComponentDataFromEvent as NativeComponentData);
      return;
    }
    setupDataForSlotComponent(event);
  };

  const setupDataForNativeComponent = (eventData: NativeComponentData) => {
    const nativePlace = eventData.nativePlace ? eventData.nativePlace : BottomSheetNativePlaceType.modal;
    setRenderingType(BottomSheetRenderingType.NativeComponent);
    dispatch(setNativePlace(nativePlace));
    setNativeComponentData(eventData as NativeComponentData);
    dispatch(setIsComponentLoading(false)); //todo: work with events?
  };
  const setupDataForSlotComponent = (eventData: BottomSheetSlotData) => {
    setRenderingType(BottomSheetRenderingType.Slot);
    const componentParamsFromEvent = {
      componentName: eventData.componentName ? eventData.componentName : componentParams?.componentName,
      componentResourceId: eventData.componentResourceId ? eventData.componentResourceId : componentParams?.componentResourceId,
    };
    setComponentParams(componentParamsFromEvent);
    dispatch(setNativePlace(eventData.requestRenderingEvent.data.nativePlace));
    setRequestRenderingEventData(eventData.requestRenderingEvent);
  };

  const handleWebViewScroll = () => {
    if (scrollState === ScrollState.unScrollable) return;
    dispatch(setScrollState(ScrollState.onlyWebView));
    dispatch(setShouldEnableBottomSheetScroll(false));
  };

  const renderBottomSheetComponent = () => {
    switch (renderingType) {
      case BottomSheetRenderingType.Slot:
        return requestRenderingEventData ? (
          <UNBottomSheetSlotComponent
            requestRenderingEvent={requestRenderingEventData}
            componentName={componentParams?.componentName}
            componentResourceId={componentParams?.componentResourceId}
          />
        ) : null;

      case BottomSheetRenderingType.NativeComponent:
        return nativeComponentData ? (
          <UNBottomSheetNativeComponent
            nativeComponentData={nativeComponentData}
          />
        ) : null;

      default:
        return null;
    }
  };
  return (
    <View
      pointerEvents={isBottomSheetActive ? undefined : 'none'}
      style={styles.container}
    >
      <BottomSheet
        isOpen={isBottomSheetActive}
        onOpen={() => dispatch(setIsBottomSheetActive(true))}
        onClose={() => dispatch(setIsBottomSheetActive(false))}
        height={height}
        animationDuration={200}
        expandToMaxHeightEnabled={false}
        handleWebViewScroll={() => handleWebViewScroll()}
        shouldEnableBottomSheetScroll={shouldEnableBottomSheetScroll}
        nativePlace={nativePlace}
        isComponentLoading={isComponentLoading}
        sliderMaxHeight={sliderMaxHeight}
      >
        {renderBottomSheetComponent()}
      </BottomSheet>
    </View>
  );
};

export default withReduxStore(UNBottomSheetComponent);
