import React, { useRef } from 'react';
import { WebComponent } from '../../webComponent/WebComponent';
import { withReduxStore } from '../../helpers/store/helpers';
import { PresentationMode, WebComponentType } from '../../types/internal/webComponent.types';
import { RequestRefreshEvent, RequestRenderingEvent, UnitComponentsMessage, UnitWhiteLabelAppEvent } from '../../messages/webMessages/unitComponentsMessages';
import type { WebViewMessage } from '../../messages/webMessages';
import {
  BottomSheetRenderingType,
  SlotRendering,
} from '../../types/internal/bottomSheet.types';
import type { BottomSheetSlotData } from '../../types/internal/bottomSheet.types';
import { eventBus } from '../../utils/eventBus';
import { BottomSheetNativeMessage } from '../../messages/nativeMessages/bottomSheetMessage';
import { useEventListener } from '../../hooks/useEventListener';
import WebView from 'react-native-webview';
import {
  getWhiteLabelAppParams,
  getWhiteLabelAppScript,
  injectAccountCreationActionsOpenPlaidForLinkExternalAccount,
  injectCardCreated,
  injectRefreshEventIfNeeded,
} from './UNWhiteLabelAppComponent.utils';
import { UserDataKeys } from '../../types/internal/unitStore.types';
import { PageMessage } from '../../messages/webMessages/pageMessage';
import UNStoreManagerHelper from '../../nativeModulesHelpers/UNStoreModuleHelper/UNStoreModuleHelper';
import { ActivityMessage } from '../../messages/webMessages/activityMessage';
import { setItemInWindowUnitStore } from '../../utils/windowUnitStore';
import { UNBaseView } from '../../nativeComponents/UNBaseView';
import { UnitComponentsSDK } from '../../unitComponentsSdkManager/UnitComponentsSdkManager';
import { AccountMessage } from '../../messages/webMessages/accountMessage';
import { CardCreatedEvent, CardMessage } from '../../messages/webMessages/cardMessage';
import { OpenPlaidEvent, PlaidMessage } from '../../messages/webMessages/plaidMessages';
import { injectUnitPlaidExit, injectUnitPlaidResponse } from '../UNPayeeManagementComponent/UNPayeeManagementComponent.utils';
import { LinkExit, LinkSuccess, open as openPlaidLink, create as createPlaidLink } from 'react-native-plaid-link-sdk';

export interface UNWhiteLabelAppComponentProps {
  // inputs
  customerToken?: string;
  jwtToken?: string;

  // ui
  theme?: string;
  language?: string;
}

const UNWhiteLabelAppComponent = (props: UNWhiteLabelAppComponentProps) => {
  const webRef = useRef<WebView>(null);

  const handleWebViewMessage = (message: WebViewMessage) => {
    switch (message.type) {
      case UnitComponentsMessage.UNIT_REQUEST_RENDERING: {

        const slotData: BottomSheetSlotData = {
          componentName: WebComponentType.whiteLabelApp,
          requestRenderingEvent: message.details as RequestRenderingEvent,
        };

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

        eventBus.emit(BottomSheetNativeMessage.REQUEST_RENDERING, data);
        break;
      }
      case UnitComponentsMessage.UNIT_WHITE_LABEL_APP_ON_LOAD: {
        const data = message.details as UnitWhiteLabelAppEvent;
        if (data.attributes.customerToken) {
          UnitComponentsSDK.setCustomerToken(data.attributes.customerToken);
          UNStoreManagerHelper.saveValue(UserDataKeys.unitCustomerToken, data.attributes.customerToken);
          // Upon receiving a new token, the web interface updates the window. Therefore, we (only) store it for subsequent windows.
          // updateWindowUnitStore();
        }
        break;
      }
      case PageMessage.PAGE_LOADED:
        updateWindowUnitStore();
        break;
      case PlaidMessage.UNIT_OPEN_PLAID:
        openPlaid(message.details as OpenPlaidEvent);
        break;
    }
  };

  const updateWindowUnitStore = async () => {
    /**
     * The 2FA-token (verifiedToken) is managed for all the components in UNWebComponent.
     */
    try {
      const token = await UNStoreManagerHelper.getValue(UserDataKeys.unitCustomerToken);
      if (token) {
        setItemInWindowUnitStore(webRef.current, UserDataKeys.unitCustomerToken, token);
      }
    } catch (e) {
      console.log(e);
    }
  };

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

  const dispatchActivityFiltersChanged = (query: string) => {
    webRef.current?.injectJavaScript(`dispatchActivityFilterChangedEvent('${query}')`);
  };

  const openPlaid = (openPlaidData: OpenPlaidEvent) => {
    const linkToken = openPlaidData.plaidLinkToken.attributes.linkToken;
    createPlaidLink({ token: linkToken });

    openPlaidLink({
      onSuccess: (success: LinkSuccess) => {
        injectUnitPlaidResponse(webRef.current, success);
      },
      onExit: (exit: LinkExit) => {
        injectUnitPlaidExit(webRef.current, exit.error);
      }
    });
  };

  useEventListener({ busEventKey: UnitComponentsMessage.UNIT_REQUEST_REFRESH, action: requestRefresh });
  useEventListener({
    busEventKey: ActivityMessage.UNIT_ACTIVITY_FILTERS_CHANGED,
    action: dispatchActivityFiltersChanged,
  });
  useEventListener({
    busEventKey: PlaidMessage.UNIT_OPEN_PLAID,
    action: (details) => {
      openPlaid(details);
    },
  });
  useEventListener({
    busEventKey: AccountMessage.UNIT_ACCOUNT_CREATION_ACTIONS_OPEN_PLAID_FOR_LINK_EXTERNAL_ACCOUNT,
    action: () => injectAccountCreationActionsOpenPlaidForLinkExternalAccount(webRef.current),
  });
  useEventListener({ busEventKey: AccountMessage.UNIT_ACCOUNT_CREATED, action: () => {
    webRef.current?.injectJavaScript('dispatchAccountCreatedEvent()');
  } });
  useEventListener({ busEventKey: CardMessage.CARD_CREATED, action: (card: CardCreatedEvent) => {
    injectCardCreated(webRef.current, card);
  } });

  const renderWebView = () => {
    return (
      <UNBaseView style={{ flex: 1 }} >
        <WebComponent
          ref={webRef}
          type={WebComponentType.whiteLabelApp}
          presentationMode={PresentationMode.Inherit}
          params={getWhiteLabelAppParams(props)}
          onMessage={handleWebViewMessage}
          isScrollable={true}
          theme={props.theme}
          language={props.language}
          script={getWhiteLabelAppScript()}
        />
      </UNBaseView>
    );
  };

  return (
    renderWebView()
  );
};

export default withReduxStore<UNWhiteLabelAppComponentProps>(UNWhiteLabelAppComponent);
