import React, { useImperativeHandle, useRef, useState, useEffect } from 'react';
import type WebView from 'react-native-webview';
import { HeightEvent, PageMessage } from '../../messages/webMessages/pageMessage';
import { RequestRefreshEvent, RequestRenderingEvent, UnitComponentsMessage } from '../../messages/webMessages/unitComponentsMessages';
import { WebComponent } from '../../webComponent/WebComponent';
import type { WebViewMessage } from '../../messages/webMessages';
import {
  getCardParams,
  getCardScript,
  injectRefreshEventIfNeeded,
  injectOpenActionsMenuScript,
  injectRequestCardActionScript,
  injectRequestShowSensitiveDataScript, injectRequestHideSensitiveDataScript,
} from './UNCardComponent.utils';
import { UNComponentsOnLoadResponse, UNCard, UNComponentsError, UNCardMenuAction, UNCardMenuItem } from '../../types/shared';
import { CardMessage } from '../../messages/webMessages/cardMessage';
import { NativeModules } from 'react-native';
import { RESPONSE_KEYS, UnitOnLoadResponseEvent } from '../../messages/webMessages/onLoadMessage';
import {
  BottomSheetRenderingType,
  SlotRendering,
} from '../../types/internal/bottomSheet.types';
import type { BottomSheetSlotData } from '../../types/internal/bottomSheet.types';
import { PresentationMode, WebComponentType } from '../../types/internal/webComponent.types';
import { UnitComponentsSDK } from '../../unitComponentsSdkManager/UnitComponentsSdkManager';
import { BottomSheetNativeMessage } from '../../messages/nativeMessages/bottomSheetMessage';
import { useLaunchInitialize } from '../../helpers/pushProvisioningService/hooks/useLaunchInitialize';
import { selectWallet } from '../../slices/pushProvisioningSlice';
import { useSelector } from 'react-redux';
import { withReduxStoreAndRefForwarding } from '../../helpers/store/helpers';
import { useEventListener } from '../../hooks/useEventListener';
import { eventBus } from '../../utils/eventBus';
import { UNBaseView } from '../../nativeComponents/UNBaseView';

export interface UNCardComponentProps {
  // inputs
  cardId: string;
  learnMoreUrl?: string;
  fee?: number;
  menuItems?: UNCardMenuItem[];

  // ui
  theme?: string;
  language?: string;
  hideActionsMenuButton?: boolean;
  hideCardTitle?: boolean;
  hideSensitiveDataButton?: boolean;
  showCardTypeSubtitle?: boolean;
  showCardHolderSubtitle?: boolean;

  // events
  onLoad?: (response: UNComponentsOnLoadResponse<UNCard>) => void;
  onStatusChanged?: (card: UNCard) => void;
  onCardActivated?: (card: UNCard) => void;
  onAction?: (action: UNCardMenuAction) => void;
  onActionsMenuClicked?: () => void;
  pushProvisioningModule?: typeof NativeModules;
}

export interface CardRef {
  openActionsMenu: () => void;
  openAction: (action: UNCardMenuAction) => void;
  showSensitiveData: () => void;
  hideSensitiveData: () => void;
}

const UNCardComponent = React.forwardRef<CardRef, UNCardComponentProps>(function UNCardComponent(props, cardRef) {

  const [height, setHeight] = useState(0);

  const webRef = useRef<WebView>(null);
  const { initializePushProvisioning } = useLaunchInitialize();
  const { signedNonce } = useSelector(selectWallet);

  useImperativeHandle(cardRef, () => ({
    openActionsMenu() {
      injectOpenActionsMenuScript(webRef.current);
    },
    openAction(action: UNCardMenuAction) {
      injectRequestCardActionScript(webRef.current, action);
    },
    showSensitiveData() {
      injectRequestShowSensitiveDataScript(webRef.current);
    },
    hideSensitiveData() {
      injectRequestHideSensitiveDataScript(webRef.current);
    },
  }));

  const cardStatusChanged = (card: UNCard) => {
    if (props.onStatusChanged) {
      props.onStatusChanged(card);
    }
  };

  const cardActivated = (card: UNCard) => {
    if (props.onCardActivated) {
      props.onCardActivated(card);
    }
  };

  const requestRefresh = (data: RequestRefreshEvent) => {
    injectRefreshEventIfNeeded(webRef.current, data, props.cardId);
  };

  const handleUnitOnLoad = (response: UnitOnLoadResponseEvent) => {
    if (!props.onLoad) {
      return;
    }

    if (RESPONSE_KEYS.errors in response) {
      props.onLoad(response as UNComponentsError);
      return;
    }

    if (RESPONSE_KEYS.card in response) {
      // CardOnLoadResponse
      props.onLoad(response[RESPONSE_KEYS.card] as UNComponentsOnLoadResponse<UNCard>);
      return;
    }

    console.error('On Load Error: unexpected response type');
    return;
  };

  useEventListener({ busEventKey: UnitComponentsMessage.UNIT_REQUEST_REFRESH, action: requestRefresh });
  useEventListener({ busEventKey: CardMessage.CARD_STATUS_CHANGED, action: cardStatusChanged });
  useEventListener({ busEventKey: CardMessage.CARD_ACTIVATED, action: cardActivated });

  const handleMessage = (message: WebViewMessage) => {
    if (!message || !message.details) return;

    switch (message.type) {
      case UnitComponentsMessage.UNIT_REQUEST_RENDERING: {
        const slotData: BottomSheetSlotData = {
          componentName: WebComponentType.card,
          componentResourceId: props.cardId,
          requestRenderingEvent: message.details as RequestRenderingEvent,
        };

        const data = {
          type: BottomSheetRenderingType.Slot,
          data: slotData,
        } as SlotRendering;

        eventBus.emit(BottomSheetNativeMessage.REQUEST_RENDERING, data);

        sendActionCallbackIfNeeded(slotData.requestRenderingEvent);
        break;
      }
      case PageMessage.PAGE_HEIGHT:
        setHeight((message.details as HeightEvent).height);
        break;
      case UnitComponentsMessage.UNIT_ON_LOAD:
        handleUnitOnLoad(message.details as UnitOnLoadResponseEvent);
        break;
    }
  };

  const sendActionCallbackIfNeeded = (requestRenderingEvent: RequestRenderingEvent) => {
    switch (requestRenderingEvent.data.nativeComponentName) {
      case WebComponentType.cardMenu:
        props.onActionsMenuClicked && props.onActionsMenuClicked();
        break;
      case WebComponentType.cardAction: {
        // Find the relevant action from the native component
        const actionMatch = requestRenderingEvent.data.nativeComponent.match(/action=([^\s]+)/);
        if (actionMatch && props.onAction) {
          const actionString = actionMatch[1] as string;

          // Check if the actionString matches any value in the UNCardMenuAction enum
          if (Object.values(UNCardMenuAction).includes(actionString as UNCardMenuAction)) {
            props.onAction(actionString as UNCardMenuAction);
          }
        }
      }
    }
  };

  useEffect(() => {
    if (props.pushProvisioningModule) {
      UnitComponentsSDK.setPushProvisioningModule(props.pushProvisioningModule);
    }
  }, [props.pushProvisioningModule]);

  useEffect(() => {
    if (signedNonce || !UnitComponentsSDK.getPushProvisionModule()) return;
    initializePushProvisioning();
  }, []);

  return (
    <UNBaseView style={{ height, width: '100%', minWidth: 235 }} onLoadError={ handleUnitOnLoad } fallback={<></>}>
      <WebComponent
        ref={webRef}
        type={WebComponentType.card}
        presentationMode={PresentationMode.Default}
        params={getCardParams(props)}
        theme={props.theme}
        language={props.language}
        script={getCardScript()}
        onMessage={message => handleMessage(message)}
        isScrollable={false}
      />
    </UNBaseView>
  );

});

export default withReduxStoreAndRefForwarding<UNCardComponentProps, CardRef>(UNCardComponent);
