import React, { useState, useEffect, useRef } from 'react';
import { WebComponent } from '../../webComponent/WebComponent';
import type { WebViewMessage } from '../../messages/webMessages';
import type { UNOnLoadResponse, UNACHData, UNACHOnLoadData, UNError, UNOnLoadResponseData } from '../../types/shared';
import { HeightEvent, PageMessage } from '../../messages/webMessages/pageMessage';
import { Platform } from 'react-native';
import { getACHCreditParams, getACHCreditScript, injectUnitPlaidResponse } from './UNACHCreditComponent.utils';
import { PaymentMessage } from '../../messages/webMessages/paymentsMessage';
import type { ACHEvent } from '../../messages/webMessages/achCreditMessage';
import { RESPONSE_KEYS, UnitOnLoadResponseEvent } from '../../messages/webMessages/onLoadMessage';
import {
  PlaidLinkTokenData,
  PlaidTokenCreatedEvent,
  RequestExternalSdkEvent,
  UnitMessage,
} from '../../messages/webMessages/unitMessages';
import { LinkSuccess, openLink } from 'react-native-plaid-link-sdk';
import type WebView from 'react-native-webview';
import * as AppInfo from '../../utils/AppInfo';
import { PresentationMode, WebComponentType } from '../../types/internal/webComponent.types';
import { withReduxStore } from '../../helpers/store/helpers';
import { UNPlaidAccountFilter } from '../../types/shared';
import { PlaidMessage } from '../../messages/webMessages/plaidMessages';
import { UNBaseView } from '../../nativeComponents/UNBaseView';
import { ensureArray } from '../../utils/onLoadMessages.utils';

export interface UNACHCreditComponentProps {
  accountId?: string;
  customerToken: string;
  theme?: string;
  language?: string;
  isAutoFocus?: boolean;
  fee?: number;
  withPlaid?: boolean;
  onPaymentCreated?: (data: UNACHData) => void;
  onInitialStageBackButtonClicked?: () => void;
  onFinalStageDoneButtonClicked?: () => void;
  onLoad?: (response: UNOnLoadResponse<UNACHOnLoadData>) => void;
  sameDay?: boolean;
  plaidAccountFilters?: UNPlaidAccountFilter[];
  plaidLinkCustomizationName?: string;
  initialStageBackButton?: boolean;
  finalStageDoneButton?: boolean;
}

const UNACHCreditComponent = (props: UNACHCreditComponentProps) => {
  const [height, setHeight] = useState<number>(0);
  const [presentationMode, setPresentationMode] = useState<PresentationMode>(PresentationMode.Inherit);
  const [linkToken, setLinkToken] = useState<string>();
  const [appPackageName, setAppPackageName] = useState<string>();
  const webRef = useRef<WebView>(null);

  useEffect(() => {
    const setPackageNameForAndroid = async () => {
      if (Platform.OS === 'android') {
        const packageName = await AppInfo.getAppIdentifier();
        setAppPackageName(packageName);
      }
    };
    setPackageNameForAndroid();
  }, []);

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

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

    if (RESPONSE_KEYS.account in response && RESPONSE_KEYS.counterpartyAccount in response) {
      const account = response[RESPONSE_KEYS.account].data;
      // ACHOnLoadResponse;
      const achOnload: UNOnLoadResponseData<UNACHOnLoadData> = {
        data: {
          [RESPONSE_KEYS.account]: ensureArray(account),
          [RESPONSE_KEYS.counterpartyAccount]: response[RESPONSE_KEYS.counterpartyAccount].data,
        },
      };
      props.onLoad(achOnload);
      return;
    }

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

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

    switch (message.type) {
      case PaymentMessage.INITIAL_STAGE_BACK_BUTTON_CLICKED: {
        props.onInitialStageBackButtonClicked && props.onInitialStageBackButtonClicked();
        break;
      }
      case PaymentMessage.FINAL_STAGE_DONE_BUTTON_CLICKED: {
        props.onFinalStageDoneButtonClicked && props.onFinalStageDoneButtonClicked();
        break;
      }
      case PaymentMessage.PAYMENT_CREATED: {
        const achCreditEvent = message.details as ACHEvent;
        props.onPaymentCreated && props.onPaymentCreated(achCreditEvent.data as UNACHData);
        break;
      }
      case UnitMessage.UNIT_ON_LOAD:
        handleUnitOnLoad(message.details as UnitOnLoadResponseEvent);
        break;
      case PageMessage.PAGE_HEIGHT: {
        const currentHeight = (message.details as HeightEvent).height;
        setHeight(currentHeight);
        if (presentationMode === PresentationMode.Inherit && currentHeight === 0) {
          setPresentationMode(PresentationMode.Default);
        }
        break;
      }
      case PlaidMessage.UNIT_PLAID_TOKEN_CREATED: {
        const linkTokenEvent = message.details as PlaidTokenCreatedEvent;
        const linkTokenData = linkTokenEvent.linkToken as PlaidLinkTokenData;
        setLinkToken(linkTokenData.attributes.linkToken);
        break;
      }

      case UnitMessage.UNIT_REQUEST_EXTERNAL_SDK: {
        const externalSdkType = (message.details as RequestExternalSdkEvent).type;
        if (externalSdkType !== 'plaid') return;
        linkToken && openLink({
          tokenConfig: { noLoadingState: false, token: linkToken },
          onSuccess: (success: LinkSuccess) => {
            injectUnitPlaidResponse(webRef.current, success);
          },
          onExit: exit => {
            console.log(exit);
          },
        }).catch(e => {
          console.error(e);
        });
        break;
      }
    }
  };

  const style = presentationMode === PresentationMode.Inherit ? { flex: 1 } : { height: height };

  return (
    <UNBaseView style={style} onLoadError={ handleUnitOnLoad }>
      <WebComponent
        ref={webRef}
        type={WebComponentType.achCreditPayment}
        presentationMode={presentationMode}
        params={getACHCreditParams(props)}
        script={getACHCreditScript(appPackageName)}
        onMessage={(message: WebViewMessage) => handleWebViewMessage(message)}
        isScrollable={true}
        theme={props.theme}
        language={props.language}
      />
    </UNBaseView>
  );
};

export default withReduxStore<UNACHCreditComponentProps>(UNACHCreditComponent);
