/* eslint-disable @typescript-eslint/no-explicit-any */
import React, { useEffect, useState } from 'react';
import { LayoutChangeEvent, 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 { useEventListener } from '../../hooks/useEventListener';
import { useDispatch, useSelector } from 'react-redux';
import { BOTTOM_SHEET_OVER_FULLSCREEN_PERCENTAGE_SIZE } 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';
import { eventBus } from '../../utils/eventBus';
import { UnsavedChangesMessage } from '../../messages/webMessages/unsavedChangesMessage';

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(0);
  const [containerHeight, setContainerHeight] = useState(0);
  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();

  const handleContainerLayout = (e: LayoutChangeEvent) => {
    setContainerHeight(e.nativeEvent.layout.height);
  };

  useEffect(() => {
    if (containerHeight === 0) return;

    const computedOverFullScreenHeight = containerHeight * BOTTOM_SHEET_OVER_FULLSCREEN_PERCENTAGE_SIZE;

    // Always set sliderMaxHeight when containerHeight is available,
    // so the BottomSheet can mount and render children (which may need to load before reporting height).
    if (nativePlace === BottomSheetNativePlaceType.modal) {
      setSliderMaxHeight(containerHeight);
    } else {
      setSliderMaxHeight(computedOverFullScreenHeight);
    }

    if (!shouldShowBottomSheet) {
      setHeight(0);
    } else {
      // For overFullScreen/modal, set the known height immediately so the WebView
      // has space to load (older Android WebViews won't fire events with 0 height).
      // For menu/contentHeight, wait until content reports its height.
      switch (nativePlace) {
        case BottomSheetNativePlaceType.overFullScreen:
          setHeight(computedOverFullScreenHeight);
          break;
        case BottomSheetNativePlaceType.modal:
          setHeight(containerHeight);
          break;
        default:
          if (!isComponentLoading && componentHeight) {
            setHeight(componentHeight < computedOverFullScreenHeight ? componentHeight : computedOverFullScreenHeight);
          } else {
            setHeight(0);
          }
          break;
      }
    }
  }, [componentHeight, nativePlace, isComponentLoading, shouldShowBottomSheet, containerHeight]);

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

    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));
  };

  useEventListener({ busEventKey: BottomSheetNativeMessage.REQUEST_RENDERING, action: requestRendering });
  useEventListener({ 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}
            containerHeight={containerHeight}
          />
        ) : null;

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

      default:
        return null;
    }
  };

  if (!isBottomSheetActive) return null;

  return (
    <View style={styles.container} onLayout={handleContainerLayout}>
      {containerHeight > 0 && sliderMaxHeight > 0 && (
        <BottomSheet
          isOpen={isBottomSheetActive}
          onOpen={() => dispatch(setIsBottomSheetActive(true))}
          onClose={() => {
            // When a bottom sheet is dismissed (backdrop/swipe), release the bill form's
            // navigation blocker in case it was the unsaved-changes draft sheet. The web side's
            // cancel() is idempotent, so this is a no-op for any other flow. We drive it from here
            // because an RN-initiated dismiss tears down the slot WebView before its own React
            // cleanup can publish the event.
            eventBus.emit(UnsavedChangesMessage.UNIT_BILL_PAY_UNSAVED_CHANGES_ACTION, { action: 'cancel' });
            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);
