import { usePaymetricFrame } from "@insite/client-framework/Common/Hooks/usePaymetricFrame";
import { BillingAddress, usePaystandFrame } from "@insite/client-framework/Common/Hooks/usePaystandFrame";
import {
    BillingAddressData,
    SpreedlyIframeStyles,
    useSpreedlyFrame,
} from "@insite/client-framework/Common/Hooks/useSpreedlyFrame";
import { useStripeSession } from "@insite/client-framework/Common/Hooks/useStripeSession";
import { useSquareFrame } from "@insite/client-framework/Common/Hooks/useSquareFrame";
import {
    IFrame,
    TokenEx as TokenExType,
    TokenExIframeStyles,
    useTokenExFrame,
} from "@insite/client-framework/Common/Hooks/useTokenExFrame";
import StyledWrapper, { getStyledWrapper } from "@insite/client-framework/Common/StyledWrapper";
import parseQueryString from "@insite/client-framework/Common/Utilities/parseQueryString";
import { makeHandlerChainAwaitable } from "@insite/client-framework/HandlerCreator";
import { getAdyenSessionData, postAdyenRefund } from "@insite/client-framework/Services/PaymentService";
import siteMessage from "@insite/client-framework/SiteMessage";
import ApplicationState from "@insite/client-framework/Store/ApplicationState";
import { getSettingsCollection } from "@insite/client-framework/Store/Context/ContextSelectors";
import loadAdyenSettings from "@insite/client-framework/Store/Context/Handlers/LoadAdyenSettings";
import loadPaymetricConfig from "@insite/client-framework/Store/Context/Handlers/LoadPaymetricConfig";
import loadSpreedlyConfig from "@insite/client-framework/Store/Context/Handlers/LoadSpreedlyConfig";
import loadTokenExConfig from "@insite/client-framework/Store/Context/Handlers/LoadTokenExConfig";
import signOut from "@insite/client-framework/Store/Context/Handlers/SignOut";
import { getBillToState } from "@insite/client-framework/Store/Data/BillTos/BillTosSelectors";
import loadBillTo from "@insite/client-framework/Store/Data/BillTos/Handlers/LoadBillTo";
import { getCartState, getCurrentCartState } from "@insite/client-framework/Store/Data/Carts/CartsSelector";
import resetCurrentCartId from "@insite/client-framework/Store/Data/Carts/Handlers/ResetCurrentCartId";
import { getLocation } from "@insite/client-framework/Store/Data/Pages/PageSelectors";
import { getPageLinkByPageType } from "@insite/client-framework/Store/Links/LinksSelectors";
import checkoutWithPayPal from "@insite/client-framework/Store/Pages/CheckoutReviewAndSubmit/Handlers/CheckoutWithPayPal";
import getPaymetricResponsePacket from "@insite/client-framework/Store/Pages/CheckoutReviewAndSubmit/Handlers/GetPaymetricResponsePacket";
import loadAdyenDropInConfig from "@insite/client-framework/Store/Pages/CheckoutReviewAndSubmit/Handlers/LoadAdyenDropInConfiguration";
import placeOrder from "@insite/client-framework/Store/Pages/CheckoutReviewAndSubmit/Handlers/PlaceOrder";
import setCheckoutPaymentMethod from "@insite/client-framework/Store/Pages/CheckoutReviewAndSubmit/Handlers/SetCheckoutPaymentMethod";
import setPaymetricIFrameIsSet from "@insite/client-framework/Store/Pages/CheckoutReviewAndSubmit/Handlers/SetPaymetricIFrameIsSet";
import setPlaceOrderErrorMessage from "@insite/client-framework/Store/Pages/CheckoutReviewAndSubmit/Handlers/SetPlaceOrderErrorMessage";
import setPONumber from "@insite/client-framework/Store/Pages/CheckoutReviewAndSubmit/Handlers/SetPONumber";
import setValidateForm from "@insite/client-framework/Store/Pages/CheckoutReviewAndSubmit/Handlers/SetValidateForm";
import validateAdyenPayment, {
    ValidatAdyenPaymenteResult,
    ValidateAdyenPaymentParameter,
} from "@insite/client-framework/Store/Pages/CheckoutReviewAndSubmit/Handlers/ValidateAdyenPayment";
import preloadOrderConfirmationData from "@insite/client-framework/Store/Pages/OrderConfirmation/Handlers/PreloadOrderConfirmationData";
import translate from "@insite/client-framework/Translate";
import { PaymentMethodDto } from "@insite/client-framework/Types/ApiModels";
import WidgetModule from "@insite/client-framework/Types/WidgetModule";
import usePaymentDetailsCartState from "@insite/content-library/Hooks/Payments/usePaymentDetailsCartState";
import usePaymentDetailsFormHandlers from "@insite/content-library/Hooks/Payments/usePaymentDetailsFormHandlers";
import usePaymentDetailsFormState from "@insite/content-library/Hooks/Payments/usePaymentDetailsFormState";
import usePaymentDetailsFormValidation from "@insite/content-library/Hooks/Payments/usePaymentDetailsFormValidation";
import AdyenDropIn from "@insite/content-library/Widgets/CheckoutReviewAndSubmit/AdyenDropIn";
import CreditCardBillingAddressEntry, {
    CreditCardBillingAddressEntryStyles,
} from "@insite/content-library/Widgets/CheckoutReviewAndSubmit/CreditCardBillingAddressEntry";
import CreditCardDetailsEntry, {
    CreditCardDetailsEntryStyles,
    CreditCardDetailsValidation,
} from "@insite/content-library/Widgets/CheckoutReviewAndSubmit/CreditCardDetailsEntry";
import ECheckDetailsEntry, {
    ECheckDetailsEntryStyles,
    Validatable,
} from "@insite/content-library/Widgets/CheckoutReviewAndSubmit/ECheckDetailsEntry";
import GooglePayButtonWrapper from "@insite/content-library/Widgets/CheckoutReviewAndSubmit/GooglePayButtonWrapper";
import PaymentProfileBillingAddress from "@insite/content-library/Widgets/CheckoutReviewAndSubmit/PaymentProfileBillingAddress";
import PayPalButton, { PayPalButtonStyles } from "@insite/content-library/Widgets/CheckoutReviewAndSubmit/PayPalButton";
import SavedPaymentProfileEntry, {
    SavedPaymentProfileEntryStyles,
    SavedPaymentProfileValidation,
} from "@insite/content-library/Widgets/CheckoutReviewAndSubmit/SavedPaymentProfileEntry";
import { convertPaymetricCardType } from "@insite/content-library/Widgets/SavedPayments/PaymentUtilities";
import { BaseTheme } from "@insite/mobius/globals/baseTheme";
import GridContainer, { GridContainerProps } from "@insite/mobius/GridContainer";
import GridItem, { GridItemProps } from "@insite/mobius/GridItem";
import Link, { LinkPresentationProps } from "@insite/mobius/Link";
import LoadingSpinner, { LoadingSpinnerProps } from "@insite/mobius/LoadingSpinner";
import Select, { SelectPresentationProps } from "@insite/mobius/Select";
import { generateSpreedlyFrameStyleConfig } from "@insite/mobius/SpreedlyFrame";
import TextField, { TextFieldPresentationProps } from "@insite/mobius/TextField";
import ToasterContext, { HasToasterContext, withToaster } from "@insite/mobius/Toast/ToasterContext";
import { generateTokenExFrameStyleConfig } from "@insite/mobius/TokenExFrame";
import Typography, { TypographyPresentationProps } from "@insite/mobius/Typography";
import { HasHistory, withHistory } from "@insite/mobius/utilities/HistoryContext";
import InjectableCss from "@insite/mobius/utilities/InjectableCss";
import VisuallyHidden from "@insite/mobius/VisuallyHidden";
import qs from "qs";
import React, { useCallback, useEffect, useRef, useState } from "react";
import { connect, ResolveThunks } from "react-redux";
import { css, ThemeProps, withTheme } from "styled-components";

const mapStateToProps = (state: ApplicationState) => {
    const {
        cartId,
        payPalRedirectUri,
        payPalCheckoutErrorMessage,
        placeOrderErrorMessage,
        requestedPickUpDateDisabled,
        requestedDeliveryDateDisabled,
        paymetricIFrameIsSet,
    } = state.pages.checkoutReviewAndSubmit;
    const cartState = cartId ? getCartState(state, cartId) : getCurrentCartState(state);
    const settingsCollection = getSettingsCollection(state);
    return {
        cartState,
        billToState: getBillToState(state, cartState.value ? cartState.value.billToId : undefined),
        cartSettings: settingsCollection.cartSettings,
        tokenExConfigs: state.context.tokenExConfigs,
        orderConfirmationPageLink: getPageLinkByPageType(state, "OrderConfirmationPage"),
        savedPaymentsPageLink: getPageLinkByPageType(state, "SavedPaymentsPage"),
        session: state.context.session,
        signInPageLink: getPageLinkByPageType(state, "SignInPage"),
        checkoutReviewAndSubmitPageLink: getPageLinkByPageType(state, "CheckoutReviewAndSubmitPage"),
        payPalRedirectUri,
        payPalCheckoutErrorMessage,
        location: getLocation(state),
        adyenSettings: state.context.adyenSettings,
        paymetricConfig: state.context.paymetricConfig,
        spreedlyConfig: state.context.spreedlyConfig,
        currency: state.context.session.currency,
        enableVat: settingsCollection.productSettings.enableVat,
        bypassCvvForSavedCards: settingsCollection.cartSettings.bypassCvvForSavedCards,
        placeOrderErrorMessage,
        requestedDeliveryDateDisabled,
        requestedPickUpDateDisabled,
        paymetricIFrameIsSet,
    };
};

const mapDispatchToProps = {
    loadTokenExConfig,
    placeOrder,
    checkoutWithPayPal,
    preloadOrderConfirmationData,
    loadBillTo,
    loadPaymetricConfig,
    loadAdyenSettings,
    loadAdyenDropInConfig,
    loadSpreedlyConfig,
    getPaymetricResponsePacket,
    resetCurrentCartId,
    setCheckoutPaymentMethod,
    signOut,
    validateAdyenPayment: makeHandlerChainAwaitable<ValidateAdyenPaymentParameter, ValidatAdyenPaymenteResult>(
        validateAdyenPayment,
    ),
    setPlaceOrderErrorMessage,
    setPaymetricIFrameIsSet,
    setPONumber,
    setValidateForm,
};

type Props = ReturnType<typeof mapStateToProps> &
    ResolveThunks<typeof mapDispatchToProps> &
    ThemeProps<BaseTheme> &
    HasHistory &
    HasToasterContext;

export interface CheckoutReviewAndSubmitPaymentDetailsStyles {
    form?: InjectableCss;
    fieldset?: InjectableCss;
    paymentDetailsHeading?: TypographyPresentationProps;
    paymentMethodPayPalText?: TypographyPresentationProps;
    paymentMethodAndPONumberContainer?: GridContainerProps;
    paymentMethodGridItem?: GridItemProps;
    paymentMethodSelect?: SelectPresentationProps;
    paymentProfileBillingAddress?: any;
    paymentProfileExpiredErrorWrapper?: InjectableCss;
    paymentProfileExpiredErrorText?: TypographyPresentationProps;
    paymentProfileEditCardLink?: LinkPresentationProps;
    vatNumberGridItem?: GridItemProps;
    vatNumberText?: TextFieldPresentationProps;
    poNumberGridItem?: GridItemProps;
    poNumberText?: TextFieldPresentationProps;
    emptyGridItem?: GridItemProps;
    adyenDropInGridItem?: GridItemProps;
    mainContainer?: GridContainerProps;
    savedPaymentProfile?: SavedPaymentProfileEntryStyles;
    creditCardDetailsGridItem?: GridItemProps;
    paystandDetailsGridItem?: GridItemProps;
    eCheckDetailsGridItem?: GridItemProps;
    creditCardDetails?: CreditCardDetailsEntryStyles;
    creditCardAddressGridItem?: GridItemProps;
    creditCardAddress?: CreditCardBillingAddressEntryStyles;
    payPalButton?: PayPalButtonStyles;
    eCheckDetailsEntryStyles?: ECheckDetailsEntryStyles;
    paypalCheckoutErrorWrapper?: InjectableCss;
    paypalCheckoutErrorText?: TypographyPresentationProps;
    loadingSpinner?: LoadingSpinnerProps;
}

export const checkoutReviewAndSubmitPaymentDetailsStyles: CheckoutReviewAndSubmitPaymentDetailsStyles = {
    fieldset: {
        css: css`
            margin: 0;
            padding: 0;
            border: 0;
        `,
    },
    paymentDetailsHeading: { variant: "h5" },
    paymentMethodAndPONumberContainer: {
        gap: 10,
        css: css`
            margin-bottom: 1rem;
        `,
    },
    paymentMethodGridItem: {
        width: 6,
        css: css`
            flex-direction: column;
        `,
    },
    paymentProfileExpiredErrorWrapper: {
        css: css`
            display: flex;
            width: 100%;
        `,
    },
    paymentProfileExpiredErrorText: { color: "danger" },
    paymentProfileEditCardLink: {
        css: css`
            margin-left: 1rem;
        `,
    },
    vatNumberGridItem: { width: 6 },
    poNumberGridItem: { width: 6 },
    emptyGridItem: { width: 6 },
    creditCardDetailsGridItem: { width: [12, 12, 12, 6, 6] },
    paystandDetailsGridItem: { width: 12 },
    eCheckDetailsGridItem: { width: [12, 12, 12, 6, 6] },
    creditCardAddressGridItem: {
        width: [12, 12, 12, 6, 6],
        css: css`
            flex-direction: column;
        `,
    },
    paypalCheckoutErrorWrapper: {
        css: css`
            display: flex;
            width: 100%;
            padding-top: 1em;
        `,
    },
    paypalCheckoutErrorText: { color: "danger" },
    loadingSpinner: {
        css: css`
            margin: auto;
        `,
    },
    adyenDropInGridItem: { width: 12 },
};

declare const TokenEx: TokenExType;
let tokenExIframe: IFrame | undefined;
let tokenExAccountNumberIframe: IFrame | undefined;
let tokenExFrameStyleConfig: TokenExIframeStyles;
let spreedlyFrameStyleConfig: SpreedlyIframeStyles;

const styles = checkoutReviewAndSubmitPaymentDetailsStyles;
const StyledForm = getStyledWrapper("form");
const StyledFieldSet = getStyledWrapper("fieldset");

const CheckoutReviewAndSubmitPaymentDetails = ({
    loadBillTo,
    cartState,
    billToState,
    tokenExConfigs,
    placeOrder,
    orderConfirmationPageLink,
    savedPaymentsPageLink,
    history,
    checkoutWithPayPal,
    payPalRedirectUri,
    preloadOrderConfirmationData,
    loadTokenExConfig,
    theme,
    session,
    checkoutReviewAndSubmitPageLink,
    location,
    toaster,
    paymetricConfig,
    loadPaymetricConfig,
    adyenSettings,
    loadAdyenSettings,
    loadAdyenDropInConfig,
    loadSpreedlyConfig,
    spreedlyConfig,
    getPaymetricResponsePacket,
    resetCurrentCartId,
    enableVat,
    bypassCvvForSavedCards,
    setCheckoutPaymentMethod,
    signInPageLink,
    placeOrderErrorMessage,
    signOut,
    requestedDeliveryDateDisabled,
    requestedPickUpDateDisabled,
    validateAdyenPayment,
    setPlaceOrderErrorMessage,
    setPaymetricIFrameIsSet,
    setPONumber,
    setValidateForm,
    currency,
}: Props) => {
    const paymentDetailsFormState = usePaymentDetailsFormState();
    const {
        paymentMethod,
        setPaymentMethod,
        poNumber,
        vatNumber,
        saveCard,
        cardHolderName,
        setCardHolderName,
        cardNumber,
        setCardNumber,
        cardType,
        setCardType,
        expirationMonth,
        setExpirationMonth,
        expirationYear,
        setExpirationYear,
        securityCode,
        setSecurityCode,
        useBillingAddress,
        setUseBillingAddress,
        address1,
        setAddress1,
        countryId,
        setCountryId,
        stateId,
        setStateId,
        city,
        setCity,
        postalCode,
        setPostalCode,
        paymentMethodError,
        poNumberError,
        address1Error,
        countryError,
        stateError,
        cityError,
        postalCodeError,
        payPalError,
        paystandError,
        setPaystandError,
        googlePayError,
        setGooglePayError,
        showFormErrors,
        setShowFormErrors,
        isCardNumberTokenized,
        setIsCardNumberTokenized,
        isECheckTokenized,
        setIsECheckTokenized,
        accountHolderName,
        setAccountHolderName,
        accountNumber,
        setAccountNumber,
        routingNumber,
        setRoutingNumber,
        payerId,
        setPayerId,
        creditCardLastFourDigits,
        setCreditCardLastFourDigits,
        bankAccountLastFourDigits,
        setBankAccountLastFourDigits,
        isIframeLoaded,
        setIsIframeLoaded,
        isPayPal,
        setIsPayPal,
        runSubmitPayPal,
        setRunSubmitPayPal,
        paymentMethodRef,
        poNumberRef,
        address1Ref,
        countryRef,
        stateRef,
        cityRef,
        postalCodeRef,
        maskedCardNumber,
        setMaskedCardNumber,
        antiFraudSessionId,
        setAntiFraudSessionId,
        externalTokenProvider,
        setExternalTokenProvider,
    } = paymentDetailsFormState;
    const paymentDetailsCartState = usePaymentDetailsCartState(cartState, paymentMethod, countryId);
    const {
        cart,
        useTokenExGateway,
        useECheckTokenExGateway,
        usePaymetricGateway,
        useSquareGateway,
        useAdyenDropIn,
        usePaystandDropIn,
        countries,
        showPayPal,
        paymentOptions,
        paymentMethods,
        paymentMethodDto,
        isCreditCard,
        isECheck,
        isPaymentProfile,
        selectedCountry,
        websiteSettings,
        useSpreedlyDropIn,
        enableGooglePay,
    } = paymentDetailsCartState;
    const paymentDetailsFormValidation = usePaymentDetailsFormValidation(
        paymentDetailsFormState,
        paymentDetailsCartState,
    );
    const {
        validatePaymentMethod,
        validatePONumber,
        validateAddress1,
        validateCountry,
        validateState,
        validateCity,
        validatePostalCode,
    } = paymentDetailsFormValidation;
    const {
        handlePaymentMethodChange,
        handlePONumberChange,
        handleVatNumberChange,
        handleSaveCardChange,
        handleCardHolderNameChange,
        handleCardNumberChange,
        handleCardTypeChange,
        handleExpirationMonthChange,
        handleExpirationYearChange,
        handleSecurityCodeChange,
        handleUseBillingAddressChange,
        handleAddressChange,
        handleCountryChange,
        handleStateChange,
        handleCityChange,
        handlePostalCodeChange,
        handleEditCardClick,
    } = usePaymentDetailsFormHandlers({
        paymentDetailsFormState,
        paymentDetailsFormValidation,
        paymentDetailsCartState,
        history,
        savedPaymentsPageLink,
        setPaymentMethodCallback: (
            event: React.ChangeEvent<HTMLSelectElement>,
            paymentMethods: PaymentMethodDto[] | null | undefined,
        ) => {
            setCheckoutPaymentMethod({
                paymentMethod: paymentMethods?.find(method => method.name === event.target.value),
            });
        },
    });

    const antiFraudSessionIdHandler = useCallback(
        (stripeRadarSessionId: string) => {
            setAntiFraudSessionId(stripeRadarSessionId ?? "");
        },
        [setAntiFraudSessionId],
    );
    const tokenExLibraryIsLoaded = useTokenExFrame();
    const spreedlyLibraryIsLoaded = useSpreedlyFrame();
    // will exist after we are redirected back here from paypal
    const { isStripeRadarScriptLoaded } = useStripeSession(antiFraudSessionIdHandler);

    const {
        PayerID: payPalPayerId,
        token: payPalToken,
        redirectResult: adyenRedirectResult,
        cartId,
    } = parseQueryString<{
        PayerID?: string;
        token?: string;
        redirectResult?: string;
        cartId?: string;
    }>(location.search);

    useEffect(() => {
        if (!billToState.value && !billToState.isLoading && cartState.value && cartState.value.billToId) {
            loadBillTo({ billToId: cartState.value.billToId });
        }
    }, [billToState]);

    useEffect(() => {
        if (isCardNumberTokenized || isECheckTokenized) {
            placeOrder({
                paymentMethod,
                poNumber,
                vatNumber,
                saveCard,
                cardHolderName,
                cardNumber,
                cardType,
                expirationMonth,
                expirationYear,
                securityCode,
                useBillingAddress,
                address1,
                countryId,
                stateId,
                city,
                postalCode,
                payPalToken,
                payPalPayerId,
                accountHolderName,
                accountNumber,
                routingNumber,
                payerId,
                maskedCardNumber,
                antiFraudSessionId,
                onSuccess: (cartId: string) => {
                    if (!orderConfirmationPageLink) {
                        return;
                    }

                    if (cart?.isAwaitingApproval) {
                        resetCurrentCartId({});
                        toaster.addToast({
                            body: siteMessage("OrderApproval_OrderPlaced"),
                            messageType: "success",
                        });
                    }

                    history.push(`${orderConfirmationPageLink.url}?cartId=${cartId}`);
                },
                onError: () => {
                    setIsCardNumberTokenized(false);
                    tokenExIframe?.reset();
                    if (usePaymetricGateway) {
                        // this will end up resetting the paymetric iframe
                        loadPaymetricConfig();
                    }

                    if (useSpreedlyDropIn) {
                        // this will end up resetting the Spreedly iframe
                        loadSpreedlyConfig();
                    }
                },
                onComplete(resultProps) {
                    if (resultProps.apiResult?.cart) {
                        // "this" is targeting the object being created, not the parent SFC

                        this.onSuccess?.(resultProps.apiResult.cart.id);
                    } else {
                        // "this" is targeting the object being created, not the parent SFC

                        this.onError?.();
                    }
                },
            });
        }
    }, [isCardNumberTokenized, isECheckTokenized]);

    useEffect(() => {
        if (!cartState.isLoading && cartState.value && cartState.value.paymentMethod && paymentMethod === "") {
            if (useAdyenDropIn && adyenRedirectResult) {
                // force set credit card payment method if we returned from Adyen
                setPaymentMethod(cartState.value.paymentOptions?.paymentMethods?.find(o => o.isCreditCard)?.name || "");
            } else {
                setPaymentMethod(cartState.value.paymentMethod.name);
            }
        }
    }, [cartState]);

    // IsPayPal
    // Setup isPayPal from cart.paymentOptions and validates form when cartState changes and is loaded.
    useEffect(() => {
        if (cartState.value) {
            const tempIsPayPal = cartState.value.paymentOptions?.isPayPal || (!!payPalToken && !!payPalPayerId);
            setIsPayPal(tempIsPayPal);
            if (tempIsPayPal) {
                validateForm();
            }
        }
    }, [cartState]);

    // Submit PayPal
    // When isPayPal and runSubmitPayPal are true will validate form, and submitPayPal with the current page redirectUri and current cart.
    useEffect(() => {
        if (isPayPal && runSubmitPayPal) {
            if (!validateForm()) {
                setShowFormErrors(true);
                return;
            }
            if (!checkoutReviewAndSubmitPageLink) {
                return;
            }
            let redirectUri = `${window.location.host}${checkoutReviewAndSubmitPageLink.url}`;
            if (cartId) {
                redirectUri += `?cartId=${cartId}`;
            }
            checkoutWithPayPal({ redirectUri });
        }
    }, [runSubmitPayPal, isPayPal]);

    // Submit PayPal State Check
    // Handles the PayPal button click response, getting the payPal redirectUri from the server on cart update call.
    useEffect(() => {
        if (payPalRedirectUri) {
            window.location.href = payPalRedirectUri;
        }
    }, [payPalRedirectUri]);

    const [adyenSessionId, setAdyenSessionId] = useState("");
    const [adyenSessionData, setAdyenSessionData] = useState("");
    const [adyenWebOrderNumber, setAdyenWebOrderNumber] = useState("");
    const [adyenRegion, setAdyenRegion] = useState("");
    const [adyenErrorMessage, setAdyenErrorMessage] = useState("");
    const [adyenConfiguration, setAdyenConfiguration] = useState<any>(null);
    const [adyenDropIn, setAdyenDropIn] = useState<any>(null);

    let tokenName: string | undefined;
    const eCheckDetails = useRef<Validatable>(null);
    const creditCardDetails = useRef<CreditCardDetailsValidation>(null);
    const savedPaymentProfile = useRef<SavedPaymentProfileValidation>(null);

    if (useTokenExGateway) {
        if (isPaymentProfile) {
            tokenName = paymentMethodDto!.name;
        } else if (isCreditCard) {
            tokenName = "";
        }
    }

    if (useECheckTokenExGateway) {
        if (isECheck) {
            tokenName = "";
        }
    }

    const placeAdyenOrder = async (paymentResult: string) => {
        const { success, adyenPspReference, errorMessage, paymentAmount, currency } = await validateAdyenPayment({
            paymentResult,
        });
        if (!success) {
            if (adyenPspReference && paymentAmount && currency) {
                postAdyenRefund(adyenPspReference, adyenWebOrderNumber, paymentAmount, currency);
            }

            if (errorMessage) {
                setAdyenErrorMessage(errorMessage);
            }

            resetAdyenSession();
            return;
        }

        placeOrder({
            paymentMethod: "",
            poNumber: window.localStorage.getItem("order-po-number") ?? poNumber,
            vatNumber,
            saveCard,
            cardHolderName,
            cardNumber,
            cardType,
            expirationMonth,
            expirationYear,
            securityCode,
            useBillingAddress,
            address1,
            countryId,
            stateId,
            city,
            postalCode,
            payPalToken,
            payPalPayerId,
            isPending: true,
            isAdyenDropIn: true,
            adyenPspReference,
            accountHolderName,
            accountNumber,
            routingNumber,
            payerId,
            maskedCardNumber,
            antiFraudSessionId,
            onSuccess: (cartId: string) => {
                preloadOrderConfirmationData({
                    cartId,
                    onSuccess: () => {
                        if (cart?.isAwaitingApproval) {
                            resetCurrentCartId({});
                            toaster.addToast({
                                body: siteMessage("OrderApproval_OrderPlaced"),
                                messageType: "success",
                            });
                        }
                        history.push(`${orderConfirmationPageLink!.url}?cartId=${cartId}`);
                    },
                });
            },
            onComplete(resultProps) {
                if (!resultProps.apiResult?.cart) {
                    return;
                }
                // "this" is targeting the object being created, not the parent SFC

                this.onSuccess?.(resultProps.apiResult.cart.id);
            },
        });
    };

    const resetAdyenSession = () => {
        setAdyenSessionId("");
        setAdyenSessionData("");
        setAdyenRegion("");
        setAdyenConfiguration(null);

        const parsedQuery = parseQueryString<any>(window.location.search);
        delete parsedQuery.customerId;
        delete parsedQuery.amount;
        delete parsedQuery.sessionId;
        delete parsedQuery.redirectResult;
        delete parsedQuery.type;
        delete parsedQuery.resultCode;
        const queryString = qs.stringify(parsedQuery);
        history.replace(`${window.location.pathname}${queryString !== "" ? `?${queryString}` : ""}`);
    };

    useEffect(() => {
        let mounted = true;
        if (
            useAdyenDropIn &&
            paymentMethodDto?.isCreditCard &&
            checkoutReviewAndSubmitPageLink &&
            cartState.value?.orderGrandTotal &&
            !adyenSessionData
        ) {
            if (!adyenSettings?.clientKey) {
                loadAdyenSettings();
            }
            const returnUrl = !cartId
                ? checkoutReviewAndSubmitPageLink.url
                : checkoutReviewAndSubmitPageLink.url.includes("?")
                ? `${checkoutReviewAndSubmitPageLink.url}&cartId=${cartId}`
                : `${checkoutReviewAndSubmitPageLink.url}?cartId=${cartId}`;
            getAdyenSessionData(cartState.value.orderGrandTotal, returnUrl, cartId).then(result => {
                if (!mounted) {
                    return;
                }
                setAdyenSessionId(result.transactionId);
                setAdyenSessionData(result.sessionData);
                setAdyenWebOrderNumber(result.webOrderNumber);
                setAdyenRegion(result.region);
            });
        }
        return () => {
            mounted = false;
        };
    }, [useAdyenDropIn, checkoutReviewAndSubmitPageLink, cartState, paymentMethodDto, adyenSessionData]);

    useEffect(() => {
        if (adyenSessionId && adyenSessionData && adyenRegion && adyenSettings?.clientKey && !adyenConfiguration) {
            loadAdyenDropInConfig({
                sessionId: adyenSessionId,
                sessionData: adyenSessionData,
                region: adyenRegion,
                clientKey: adyenSettings.clientKey,
                cartId,
                webOrderNumber: adyenWebOrderNumber,
                returnUrl: !cartId
                    ? checkoutReviewAndSubmitPageLink!.url
                    : checkoutReviewAndSubmitPageLink!.url.includes("?")
                    ? `${checkoutReviewAndSubmitPageLink!.url}&cartId=${cartId}`
                    : `${checkoutReviewAndSubmitPageLink!.url}?cartId=${cartId}`,
                setAdyenErrorMessage,
                resetAdyenSession,
                placeAdyenOrder,
                setShowFormErrors,
                onSuccess: (adyenConfiguration: any) => {
                    setAdyenConfiguration(adyenConfiguration);
                },
            });
        }
    }, [adyenSessionId, adyenSessionData, adyenRegion, adyenSettings]);

    useEffect(() => {
        setAdyenSessionId("");
        setAdyenSessionData("");
        setAdyenRegion("");
        setAdyenConfiguration(null);
    }, [cartState.value?.billToId]);

    useEffect(() => {
        if (typeof tokenName !== "undefined") {
            loadTokenExConfig({ token: tokenName, isECheck });
        }
    }, [paymentMethod]);

    useEffect(() => {
        if (useSpreedlyDropIn && !spreedlyConfig?.environmentKey) {
            loadSpreedlyConfig();
        }
    }, [paymentMethod]);

    const handleTokenExSessionExpired = (token: string) => {
        loadTokenExConfig({ token, isECheck });
    };

    const tokenExConfig = typeof tokenName !== "undefined" ? tokenExConfigs[tokenName] : undefined;

    const [paymetricFrameRef, paymetricIframe] = usePaymetricFrame(
        usePaymetricGateway,
        paymentMethod,
        isCreditCard,
        paymetricConfig,
        loadPaymetricConfig,
        setPaymetricIFrameIsSet,
    );

    const [paystandCard] = usePaystandFrame(websiteSettings, paymentMethod, isCreditCard);
    useEffect(() => {
        if (paystandCard.getIsPaystandScriptLoaded() && billToState.value) {
            paystandCard.setup(
                billToState.value,
                () => {
                    setIsIframeLoaded(true);
                },
                data => {
                    const isBillToUpdated = updateBillToCallback(
                        data.card?.billingAddress ?? data.bank?.billingAddress,
                    );
                    if (isBillToUpdated) {
                        toaster.addToast({
                            body: translate("Payment method submitted successfully"),
                            messageType: "success",
                        });
                        setCardNumber(data.id);
                        setPayerId(data.payerId);
                        setBankAccountLastFourDigits(data.bank?.last4);
                        setPaystandError("");
                        setCardHolderName(data.card?.nameOnCard ?? data?.bank.nameOnAccount);
                        setCardType(data.card?.brand.toUpperCase() ?? data.bank?.bankName);
                        if (data.card) {
                            setExpirationMonth(parseInt(data.card.expirationMonth, 10));
                            setExpirationYear(parseInt(data.card.expirationYear, 10));
                            setCreditCardLastFourDigits(data.card.last4);
                            setMaskedCardNumber(data.card.last4);
                        }
                    } else {
                        setShowFormErrors(true);
                        setPaystandError(
                            translate("Selected country isn't supported. Please re-enter payment details."),
                        );
                    }
                },
            );
        }
    }, [paystandCard.getIsPaystandScriptLoaded(), paymentMethod]);

    const updateBillToCallback = (address: BillingAddress): boolean => {
        const country = countries?.find(
            o =>
                o.name === address.country ||
                o.abbreviation === address.country ||
                o.states?.find(o => o.name === address.state || o.abbreviation === address.state),
        );

        if (country) {
            setCountryId(country.id);
            const state = country.states?.find(o => o.name === address.state || o.abbreviation === address.state);
            if (state) {
                setStateId(state.id);
            }
        } else {
            return false;
        }

        setUseBillingAddress(false);
        setAddress1(address.street1);
        setCity(address.city);
        setPostalCode(address.postalCode);

        return true;
    };

    const [squareCard] = useSquareFrame(websiteSettings, paymentMethod, isCreditCard);

    const tokenizeSquareCard = () => {
        squareCard?.tokenize().then((tokenResult: any) => {
            if (tokenResult.status === "OK") {
                setCardType(tokenResult.details.card.brand);
                setExpirationMonth(tokenResult.details.card.expMonth);
                setExpirationYear(tokenResult.details.card.expYear);
                setCardNumber(tokenResult.token);
                setIsCardNumberTokenized(true);
            }
        });
    };

    const toasterContext = React.useContext(ToasterContext);
    useEffect(() => {
        if (placeOrderErrorMessage === siteMessage("CreditCardInfo_MaximumCreditCardAttempts")) {
            toasterContext.addToast({
                body: placeOrderErrorMessage,
                messageType: "danger",
            });

            setTimeout(() => {
                signOut();
                signInPageLink && history.push(signInPageLink.url);
            }, 3000);
        }
    }, [placeOrderErrorMessage]);

    const handleAccountNumberIFrame = (accountNumberIFrame: IFrame) => {
        tokenExAccountNumberIframe = accountNumberIFrame;
    };

    const handlePaymetricValidateSuccess = (success: boolean) => {
        if (success) {
            paymetricIframe.submit({
                onSuccess: (msg: string) => {
                    // The HasPassed is case sensitive, and not standard json.
                    const message: { data: { HasPassed: boolean } } = JSON.parse(msg);
                    if (message.data.HasPassed) {
                        handleSuccessSubmitPaymetricIframe();
                    }
                },
                onError: (msg: string) => {
                    const message: { data: { Code: number; HasPasssed: boolean; Message: string } } = JSON.parse(msg);
                    // Code = 150 -> Already submitted
                    if (message.data.Code === 150) {
                        handleSuccessSubmitPaymetricIframe();
                    }

                    if (!message.data.HasPasssed) {
                        if (message.data.Message === "Error" && message.data.Code === 100) {
                            setPlaceOrderErrorMessage({
                                errorMessage: siteMessage("Checkout_Paymetric_Code_100_Error") as string,
                            });
                        } else if (message.data.Message && message.data.Message !== "Error") {
                            setPlaceOrderErrorMessage({
                                // eslint-disable-next-line spire/avoid-dynamic-translate
                                errorMessage: translate(message.data.Message),
                            });
                        }
                    }
                },
            });
        }
    };

    const handleSuccessSubmitPaymetricIframe = () => {
        if (!paymetricConfig?.accessToken) {
            return;
        }

        getPaymetricResponsePacket({
            accessToken: paymetricConfig.accessToken,
            onComplete: result => {
                if (result.apiResult?.success) {
                    setCardType(convertPaymetricCardType(result.apiResult.creditCard.cardType));
                    setExpirationMonth(result.apiResult.creditCard.expirationMonth!);
                    setExpirationYear(result.apiResult.creditCard.expirationYear!);
                    setCardNumber(result.apiResult.creditCard.cardNumber!);
                    setSecurityCode(result.apiResult.creditCard.securityCode!);
                    setCardHolderName(result.apiResult.creditCard.cardHolderName!);
                    setIsCardNumberTokenized(true);
                }
            },
        });
    };

    const validateFormForProvider = (externalProvider: string) => {
        return (
            validatePONumber(poNumber) &&
            validateAddress1(address1) &&
            validateCountry(countryId) &&
            validateState(stateId) &&
            validateCity(city) &&
            validatePostalCode(postalCode) &&
            !requestedDeliveryDateDisabled &&
            !requestedPickUpDateDisabled
        );
    };

    const validateForm = () => {
        const paymentMethodValid = validatePaymentMethod(paymentMethod);
        const poNumberValid = validatePONumber(poNumber);
        if (isPayPal) {
            return paymentMethodValid;
        }

        if (useAdyenDropIn && paymentMethodDto?.isCreditCard) {
            return poNumberValid;
        }

        if (useECheckTokenExGateway && isECheck) {
            tokenExAccountNumberIframe?.validate();
        }

        if (useSpreedlyDropIn && isStripeRadarScriptLoaded && !antiFraudSessionId) {
            setPlaceOrderErrorMessage({
                errorMessage: translate(
                    "The Stripe Radar session has not been loaded. Please try again in a minute.",
                ) as string,
            });
            return false;
        }

        if (usePaymetricGateway && cart && cart.showCreditCard && !cart.requiresApproval) {
            const isFormValidForPaymetricPayment = paymentMethodValid && poNumberValid;
            if (!isFormValidForPaymetricPayment) {
                return false;
            }
            if (isCreditCard && paymetricIframe) {
                paymetricIframe.validate({
                    onValidate: (success: boolean) => {
                        handlePaymetricValidateSuccess(success);
                    },
                });
            } else if (isPaymentProfile) {
                if (savedPaymentProfile?.current) {
                    return savedPaymentProfile?.current.validate();
                }

                return true;
            }
        }

        if (useSquareGateway && cart && cart.showCreditCard && !cart.requiresApproval) {
            const isFormValidForSquarePayment = paymentMethodValid && poNumberValid;
            if (!isFormValidForSquarePayment) {
                return false;
            }
            if (isCreditCard && squareCard) {
                tokenizeSquareCard();
            } else if (isPaymentProfile) {
                return true;
            }
        }

        if (usePaystandDropIn && isCreditCard && cart && cart.showCreditCard && !cart.requiresApproval) {
            const isTokenExist = !!payerId && !!cardNumber;
            setPaystandError(!isTokenExist ? translate("Payment details are required.") : "");
            return isTokenExist;
        }

        const address1Valid = validateAddress1(address1);
        const countryValid = validateCountry(countryId);
        const stateValid = validateState(stateId);
        const cityValid = validateCity(city);
        const postalCodeValid = validatePostalCode(postalCode);
        let accountHolderNameValid = true;
        let accountNumberValid = true;
        let routingNumberValid = true;
        if (eCheckDetails?.current) {
            accountHolderNameValid = eCheckDetails.current.validateAccountHolderNameChange(accountHolderName);
            accountNumberValid = eCheckDetails.current.validateAccountNumberChange(accountNumber);
            routingNumberValid = eCheckDetails.current.validateRoutingNumberChange(routingNumber);
        }
        let creditCardValid = true;
        if (creditCardDetails?.current && externalTokenProvider !== "GooglePay") {
            creditCardValid = creditCardDetails.current.validate();
        }

        if (savedPaymentProfile?.current) {
            creditCardValid = savedPaymentProfile?.current.validate();
        }

        if (!paymentMethodValid) {
            paymentMethodRef.current?.focus();
        } else if (!poNumberValid) {
            poNumberRef.current?.focus();
        } else if (!address1Valid) {
            address1Ref.current?.focus();
        } else if (!countryValid) {
            countryRef.current?.focus();
        } else if (!stateValid) {
            stateRef.current?.focus();
        } else if (!cityValid) {
            cityRef.current?.focus();
        } else if (!postalCodeValid) {
            postalCodeRef.current?.focus();
        }

        return (
            paymentMethodValid &&
            poNumberValid &&
            creditCardValid &&
            address1Valid &&
            countryValid &&
            stateValid &&
            cityValid &&
            postalCodeValid &&
            accountHolderNameValid &&
            accountNumberValid &&
            routingNumberValid &&
            !requestedDeliveryDateDisabled &&
            !requestedPickUpDateDisabled
        );
    };

    useEffect(() => {
        setPONumber({ poNumber });
    }, [poNumber]);

    useEffect(() => {
        setValidateForm({ validateForm });
    }, [validateForm]);

    const handleFormSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
        event.preventDefault();
        setExternalTokenProvider(null);
        if (document.activeElement?.className === "adyen-checkout__payment-method__header__title") {
            // The adyen form buttons are incorrectly submitting our form, we should just ignore these occurances.
            return false;
        }

        if (!validateForm()) {
            setShowFormErrors(true);
            return false;
        }

        if (useAdyenDropIn && isCreditCard && !isPayPal) {
            if (adyenDropIn) {
                const { success, errorMessage } = await validateAdyenPayment({
                    customerId: cartState.value?.billToId,
                    paymentAmount: cartState.value?.orderGrandTotal,
                });
                if (success) {
                    window.localStorage.setItem("order-po-number", poNumber);
                    adyenDropIn.submit();
                } else if (errorMessage) {
                    setAdyenErrorMessage(errorMessage);
                }
            }
        } else if (
            (useTokenExGateway || useSpreedlyDropIn) &&
            ((isPaymentProfile && !bypassCvvForSavedCards) || isCreditCard)
        ) {
            creditCardDetails.current?.tokenize();
            savedPaymentProfile.current?.tokenize();
        } else if (useSpreedlyDropIn && isCreditCard) {
            creditCardDetails.current?.tokenize();
        } else if (useECheckTokenExGateway && !isPayPal && isECheck) {
            tokenExAccountNumberIframe?.tokenize();
        } else {
            placeOrder({
                paymentMethod,
                poNumber,
                vatNumber,
                saveCard,
                cardHolderName,
                cardNumber,
                cardType,
                expirationMonth,
                expirationYear,
                securityCode,
                useBillingAddress,
                address1,
                countryId,
                stateId,
                city,
                postalCode,
                payPalToken,
                payPalPayerId,
                accountHolderName,
                accountNumber,
                routingNumber,
                payerId,
                maskedCardNumber,
                antiFraudSessionId,
                onSuccess: (cartId: string) => {
                    preloadOrderConfirmationData({
                        cartId,
                        onSuccess: () => {
                            if (cart?.isAwaitingApproval) {
                                resetCurrentCartId({});
                                toaster.addToast({
                                    body: siteMessage("OrderApproval_OrderPlaced"),
                                    messageType: "success",
                                });
                            }
                            history.push(`${orderConfirmationPageLink!.url}?cartId=${cartId}`);
                        },
                    });
                },
                onComplete(resultProps) {
                    if (!resultProps.apiResult?.cart) {
                        return;
                    }
                    // "this" is targeting the object being created, not the parent SFC
                    this.onSuccess?.(resultProps.apiResult.cart.id);
                },
            });
        }

        return false;
    };

    const submitPayPalRequest = (event: React.MouseEvent<HTMLAnchorElement>) => {
        event.preventDefault();
        if (!checkoutReviewAndSubmitPageLink) {
            return;
        }
        if (!session?.isAuthenticated) {
            return;
        }
        setPaymentMethod("");
        setRunSubmitPayPal(true);
        setIsPayPal(true);
    };

    const handleExternalProviderValidate = (externalProvider: "GooglePay" | "ApplePay"): boolean => {
        if (!checkoutReviewAndSubmitPageLink) {
            return false;
        }
        if (!session?.isAuthenticated) {
            return false;
        }

        setExternalTokenProvider(externalProvider);
        const isValid = validateFormForProvider(externalProvider);
        if (!isValid) {
            setShowFormErrors(true);
            return false;
        }

        return true;
    };

    const handleGooglePayAuthorize = (paymentData: google.payments.api.PaymentData) => {
        setCardNumber(paymentData.paymentMethodData?.tokenizationData?.token || "");
        setCreditCardLastFourDigits(paymentData.paymentMethodData?.info?.cardDetails || "");
        setMaskedCardNumber(paymentData.paymentMethodData?.info?.cardDetails || "");
        setCardType(paymentData.paymentMethodData?.info?.cardNetwork || "");
        setPaymentMethod("GooglePay");
        setSecurityCode("GooglePay");
        setIsCardNumberTokenized(true);
    };

    const handleResetPaymentMethodClick = () => {
        if (usePaystandDropIn) {
            paystandCard.resetCheckout(billToState.value!);
        }
    };

    if (!tokenExFrameStyleConfig) {
        tokenExFrameStyleConfig = generateTokenExFrameStyleConfig({ theme });
    }

    if (!spreedlyFrameStyleConfig && useSpreedlyDropIn) {
        spreedlyFrameStyleConfig = generateSpreedlyFrameStyleConfig({ theme });
    }

    if (
        !cart ||
        cart.requiresApproval ||
        !paymentOptions ||
        !orderConfirmationPageLink ||
        (useTokenExGateway && !tokenExLibraryIsLoaded) ||
        (useSpreedlyDropIn && !spreedlyLibraryIsLoaded)
    ) {
        return null;
    }

    const iframeName = useTokenExGateway
        ? "TokenEx"
        : usePaymetricGateway
        ? "Paymetric"
        : useSquareGateway
        ? "Square"
        : usePaystandDropIn
        ? "Paystand"
        : useSpreedlyDropIn
        ? "Spreedly"
        : undefined;

    const paymentDetailsStyles = usePaystandDropIn ? styles.paystandDetailsGridItem : styles.creditCardDetailsGridItem;
    const billingData: BillingAddressData = useBillingAddress
        ? {
              email: billToState.value?.email,
              firstName: billToState.value?.firstName,
              lastName: billToState.value?.lastName,
              address1: billToState.value?.address1,
              address2: billToState.value?.address2,
              country: billToState.value?.country?.abbreviation,
              state: billToState.value?.state?.abbreviation,
              city: billToState.value?.city,
              zip: billToState.value?.postalCode,
              phoneNumber: billToState.value?.phone,
              company: billToState.value?.companyName,
          }
        : {
              email: billToState.value?.email,
              firstName: billToState.value?.firstName,
              lastName: billToState.value?.lastName,
              address1,
              country: selectedCountry?.abbreviation,
              state: selectedCountry?.states?.find(o => o.id === stateId)?.abbreviation,
              city,
              zip: postalCode,
              phoneNumber: billToState.value?.phone,
              company: billToState.value?.companyName,
          };

    return (
        <StyledForm
            {...styles.form}
            id="reviewAndSubmitPaymentForm"
            onSubmit={handleFormSubmit}
            noValidate={true}
            data-test-selector="reviewAndSubmitPaymentForm"
        >
            {/* This button should only be used to trigger the submit of the form. Should be on the top of the form. */}
            <button id="reviewAndSubmitPaymentForm-submit" type="submit" style={{ display: "none" }}>
                {translate("Place Order")}
            </button>
            <StyledFieldSet {...styles.fieldset}>
                <Typography {...styles.paymentDetailsHeading} as="h2">
                    {translate("Payment Details")}
                </Typography>
                {isPayPal && (
                    <Typography {...styles.paymentMethodPayPalText} as="span">
                        {translate("Selected Payment Method: PayPal")}
                    </Typography>
                )}
                {!isPayPal && (
                    <GridContainer {...styles.paymentMethodAndPONumberContainer}>
                        <GridItem {...styles.paymentMethodGridItem}>
                            {paymentMethods && paymentMethods.length > 0 && (
                                <>
                                    <Select
                                        {...styles.paymentMethodSelect}
                                        label={translate("Payment Method")}
                                        value={paymentMethod ?? paymentMethodDto?.name}
                                        onChange={handlePaymentMethodChange}
                                        required
                                        error={showFormErrors && paymentMethodError}
                                        data-test-selector="checkoutReviewAndSubmit_paymentMethod"
                                        ref={paymentMethodRef}
                                    >
                                        <option value="">{translate("Select Payment Method")}</option>
                                        {paymentMethods.map(method => (
                                            <option key={method.name} value={method.name}>
                                                {method.description || method.name}
                                            </option>
                                        ))}
                                    </Select>
                                    {paymentMethodDto?.isPaymentProfile &&
                                        !paymentMethodDto.isPaymentProfileExpired && (
                                            <PaymentProfileBillingAddress
                                                address={paymentMethodDto.billingAddress}
                                                extendedStyles={styles.paymentProfileBillingAddress}
                                            />
                                        )}
                                    {paymentMethodDto?.isPaymentProfile && paymentMethodDto.isPaymentProfileExpired && (
                                        <StyledWrapper {...styles.paymentProfileExpiredErrorWrapper}>
                                            <Typography {...styles.paymentProfileExpiredErrorText}>
                                                {siteMessage("Checkout_PaymentProfileExpired")}
                                            </Typography>
                                            {savedPaymentsPageLink && (
                                                <Link
                                                    {...styles.paymentProfileEditCardLink}
                                                    onClick={handleEditCardClick}
                                                >
                                                    {translate("Edit Card")}
                                                </Link>
                                            )}
                                        </StyledWrapper>
                                    )}
                                </>
                            )}
                            {showPayPal && (
                                <PayPalButton
                                    {...styles.payPalButton}
                                    submitPayPalRequest={submitPayPalRequest}
                                    error={showFormErrors ? payPalError : undefined}
                                ></PayPalButton>
                            )}
                            {enableGooglePay && spreedlyConfig && (
                                <GooglePayButtonWrapper
                                    amount={cart.orderGrandTotal!}
                                    currencyCode={currency?.currencyCode ?? ""}
                                    gatewayMerchantId={spreedlyConfig?.environmentKey || ""}
                                    onValidate={() => handleExternalProviderValidate("GooglePay")}
                                    onSuccess={paymentData => handleGooglePayAuthorize(paymentData)}
                                    onError={(error: string) => setGooglePayError(error)}
                                    error={showFormErrors ? googlePayError : undefined}
                                />
                            )}
                        </GridItem>
                        {enableVat && (
                            <GridItem {...styles.vatNumberGridItem}>
                                <TextField
                                    {...styles.vatNumberText}
                                    label={translate("VAT Number")}
                                    value={vatNumber}
                                    onChange={handleVatNumberChange}
                                    maxLength={50}
                                    data-test-selector="checkoutReviewAndSubmit_vatNumber"
                                />
                            </GridItem>
                        )}
                        {cart.showPoNumber && (
                            <GridItem {...styles.poNumberGridItem}>
                                <TextField
                                    {...styles.poNumberText}
                                    label={
                                        <>
                                            <span aria-hidden>{translate("PO Number")}</span>
                                            <VisuallyHidden>{translate("Purchase Order Number")}</VisuallyHidden>
                                        </>
                                    }
                                    value={poNumber}
                                    onChange={handlePONumberChange}
                                    required={cart.requiresPoNumber}
                                    maxLength={50}
                                    error={showFormErrors && poNumberError}
                                    data-test-selector="checkoutReviewAndSubmit_poNumber"
                                    ref={poNumberRef}
                                />
                            </GridItem>
                        )}
                        {cart.showPoNumber && enableVat && <GridItem {...styles.emptyGridItem}></GridItem>}
                        {paymentMethodDto?.isPaymentProfile &&
                            !paymentMethodDto.isPaymentProfileExpired &&
                            !bypassCvvForSavedCards && (
                                <GridItem width={6}>
                                    <SavedPaymentProfileEntry
                                        iframe={iframeName}
                                        onSecurityCodeUpdate={handleSecurityCodeChange}
                                        extendedStyles={styles.savedPaymentProfile}
                                        tokenExConfig={tokenExConfig}
                                        tokenExFrameStyleConfig={tokenExFrameStyleConfig}
                                        spreedlyConfig={spreedlyConfig}
                                        spreedlyFrameStyleConfig={spreedlyFrameStyleConfig}
                                        paymentMethodDto={paymentMethodDto}
                                        updateCardIsTokenized={setIsCardNumberTokenized}
                                        ref={savedPaymentProfile}
                                    />
                                </GridItem>
                            )}
                        {paymentMethodDto?.isCreditCard && useAdyenDropIn && !adyenDropIn && !showPayPal && (
                            <LoadingSpinner {...styles.loadingSpinner} />
                        )}
                        {paymentMethodDto?.isCreditCard && useAdyenDropIn && (
                            <GridItem {...styles.adyenDropInGridItem}>
                                <AdyenDropIn
                                    redirectResult={adyenRedirectResult}
                                    adyenConfiguration={adyenConfiguration}
                                    setAdyenDropIn={setAdyenDropIn}
                                    adyenErrorMessage={adyenErrorMessage}
                                />
                            </GridItem>
                        )}
                        {cart.showCreditCard && paymentMethodDto?.isCreditCard && !useAdyenDropIn && (
                            <GridItem {...paymentDetailsStyles}>
                                <CreditCardDetailsEntry
                                    canSaveCard={paymentOptions.canStorePaymentProfile}
                                    iframe={iframeName}
                                    paymetricFrameRef={paymetricFrameRef}
                                    onSaveCardUpdate={handleSaveCardChange}
                                    onCardHolderNameUpdate={handleCardHolderNameChange}
                                    onCardNumberUpdate={handleCardNumberChange}
                                    onCardTypeUpdate={handleCardTypeChange}
                                    onExpirationMonthUpdate={handleExpirationMonthChange}
                                    onExpirationYearUpdate={handleExpirationYearChange}
                                    onSecurityCodeUpdate={handleSecurityCodeChange}
                                    availableCardTypes={paymentOptions.cardTypes ?? []}
                                    availableMonths={paymentOptions.expirationMonths ?? []}
                                    availableYears={paymentOptions.expirationYears ?? []}
                                    extendedStyles={styles.creditCardDetails}
                                    onResetPaymentMethodClick={handleResetPaymentMethodClick}
                                    isIframeLoaded={isIframeLoaded}
                                    error={showFormErrors ? paystandError : undefined}
                                    bankAccountLastFourDigits={bankAccountLastFourDigits}
                                    creditCardLastFourDigits={creditCardLastFourDigits}
                                    tokenExConfig={tokenExConfig}
                                    onTokenExSessionExpired={handleTokenExSessionExpired}
                                    spreedlyConfig={spreedlyConfig}
                                    tokenExFrameStyleConfig={tokenExFrameStyleConfig}
                                    spreedlyFrameStyleConfig={spreedlyFrameStyleConfig}
                                    updateCardIsTokenized={setIsCardNumberTokenized}
                                    updateMaskedCardNumber={setMaskedCardNumber}
                                    ref={creditCardDetails}
                                    billingData={billingData}
                                />
                            </GridItem>
                        )}
                        {cart.showECheck && paymentMethodDto?.isECheck && (
                            <GridItem {...styles.eCheckDetailsGridItem}>
                                <ECheckDetailsEntry
                                    iframe={useECheckTokenExGateway ? "TokenEx" : undefined}
                                    paymentMethod={paymentMethod}
                                    onAccountHolderNameChange={setAccountHolderName}
                                    onAccountNumberChange={setAccountNumber}
                                    onRoutingNumberChange={setRoutingNumber}
                                    tokenExConfig={tokenExConfig}
                                    tokenExFrameStyleConfig={tokenExFrameStyleConfig}
                                    extendedStyles={styles.eCheckDetailsEntryStyles}
                                    showFormErrors={showFormErrors}
                                    updateIsECheckTokenized={setIsECheckTokenized}
                                    updateShowFormErrors={setShowFormErrors}
                                    setAccountNumberIFrame={handleAccountNumberIFrame}
                                    ref={eCheckDetails}
                                />
                            </GridItem>
                        )}
                        {((cart.showECheck && paymentMethodDto?.isECheck) ||
                            (cart.showCreditCard &&
                                paymentMethodDto?.isCreditCard &&
                                !useAdyenDropIn &&
                                !usePaystandDropIn)) && (
                            <GridItem {...styles.creditCardAddressGridItem}>
                                <CreditCardBillingAddressEntry
                                    useBillTo={useBillingAddress}
                                    onUseBillToChange={handleUseBillingAddressChange}
                                    billTo={billToState.value}
                                    address1={address1}
                                    address1Ref={address1Ref}
                                    onAddress1Change={handleAddressChange}
                                    address1Error={showFormErrors ? address1Error : undefined}
                                    country={countryId}
                                    countryRef={countryRef}
                                    onCountryChange={handleCountryChange}
                                    countryError={showFormErrors ? countryError : undefined}
                                    state={stateId}
                                    stateRef={stateRef}
                                    onStateChange={handleStateChange}
                                    stateError={showFormErrors ? stateError : undefined}
                                    city={city}
                                    cityRef={cityRef}
                                    onCityChange={handleCityChange}
                                    cityError={showFormErrors ? cityError : undefined}
                                    postalCode={postalCode}
                                    postalCodeRef={postalCodeRef}
                                    onPostalCodeChange={handlePostalCodeChange}
                                    postalCodeError={showFormErrors ? postalCodeError : undefined}
                                    availableCountries={countries ?? []}
                                    availableStates={selectedCountry?.states}
                                    extendedStyles={styles.creditCardAddress}
                                />
                            </GridItem>
                        )}
                    </GridContainer>
                )}
            </StyledFieldSet>
        </StyledForm>
    );
};

const widgetModule: WidgetModule = {
    component: connect(
        mapStateToProps,
        mapDispatchToProps,
    )(withToaster(withHistory(withTheme(CheckoutReviewAndSubmitPaymentDetails)))),
    definition: {
        group: "Checkout - Review & Submit",
        displayName: "Payment Details",
        allowedContexts: ["CheckoutReviewAndSubmitPage"],
    },
};

export default widgetModule;
