import React, { useEffect } from "react";
import GooglePayButton from "@google-pay/button-react";
import mergeToNew from "@insite/client-framework/Common/mergeToNew";
import StyledWrapper from "@insite/client-framework/Common/StyledWrapper";
import ApplicationState from "@insite/client-framework/Store/ApplicationState";
import loadGooglePayConfig from "@insite/client-framework/Store/Context/Handlers/LoadGooglePayConfig";
import Typography, { TypographyPresentationProps } from "@insite/mobius/Typography";
import InjectableCss from "@insite/mobius/utilities/InjectableCss";
import { css } from "styled-components";
import translate from "@insite/client-framework/Translate";
import { connect, ResolveThunks } from "react-redux";
import { getBillToState } from "@insite/client-framework/Store/Data/BillTos/BillTosSelectors";
import parseQueryString from "@insite/client-framework/Common/Utilities/parseQueryString";
import {
    getCartState,
    getCurrentCartState,
    hasProductsWithInvalidPrice,
} from "@insite/client-framework/Store/Data/Carts/CartsSelector";
import { getLocation } from "@insite/client-framework/Store/Data/Pages/PageSelectors";
import { getShipToState } from "@insite/client-framework/Store/Data/ShipTos/ShipTosSelectors";

interface OwnProps {
    amount: number;
    currencyCode: string;
    gatewayMerchantId?: string;
    onSuccess?: (paymentData: google.payments.api.PaymentData) => void;
    onError?: (error: any) => void;
    onValidate?: () => boolean;
    extendedStyles?: GooglePayButtonWrapperStyles;
    error?: string;
}

const mapStateToProps = (state: ApplicationState) => {
    const { cartId, isPlacingOrder, isCheckingOutWithPayPay } = state.pages.checkoutReviewAndSubmit;
    const cartState = cartId ? getCartState(state, cartId) : getCurrentCartState(state);
    const billToState = getBillToState(state, cartState.value?.billToId);
    const shipToState = getShipToState(state, cartState.value?.shipToId);

    const { sessionId, redirectResult } = parseQueryString<{ sessionId?: string; redirectResult?: string }>(
        getLocation(state).search,
    );

    return {
        isDisabled:
            cartState.isLoading ||
            billToState.isLoading ||
            !billToState.value ||
            shipToState.isLoading ||
            !shipToState.value ||
            !billToState.value.address1 ||
            !shipToState.value.address1 ||
            isPlacingOrder ||
            isCheckingOutWithPayPay ||
            (!!sessionId && !!redirectResult) ||
            hasProductsWithInvalidPrice(cartState.value) ||
            cartState.value?.hasInsufficientInventory === true ||
            !cartState.value?.canCheckOut,
        googlePayConfig: state.context.googlePayConfig,
    };
};

const mapDispatchToProps = {
    loadGooglePayConfig,
};

type Props = OwnProps & ReturnType<typeof mapStateToProps> & ResolveThunks<typeof mapDispatchToProps>;

export interface GooglePayButtonWrapperStyles {
    container?: InjectableCss;
    errorText?: TypographyPresentationProps;
}

export const googlePayButtonWrapperStyles: GooglePayButtonWrapperStyles = {
    container: {
        css: css`
            padding-top: 1em;
        `,
    },
    errorText: {
        color: "danger",
        weight: 600,
    },
};

const GooglePayButtonWrapper: React.FC<Props> = ({
    amount,
    currencyCode,
    gatewayMerchantId,
    isDisabled,
    onSuccess,
    onError,
    onValidate,
    extendedStyles,
    error,
    googlePayConfig,
    loadGooglePayConfig,
}) => {
    const [styles] = React.useState(() => mergeToNew(googlePayButtonWrapperStyles, extendedStyles));

    useEffect(() => {
        if (!googlePayConfig) {
            loadGooglePayConfig();
        }
    }, [googlePayConfig, loadGooglePayConfig]);

    // Don't render if config is not loaded yet
    if (!googlePayConfig?.merchantId || !googlePayConfig?.merchantName) {
        return null;
    }

    // Use testMode to determine environment if provided, otherwise use the environment prop
    const googlePayEnvironment = googlePayConfig.testMode ? "TEST" : "PRODUCTION";

    const handleLoadPaymentData = (paymentData: google.payments.api.PaymentData) => {
        onSuccess?.(paymentData);
    };

    const handleError = (error: any) => {
        onError?.(error);
    };

    const handleClick = (event: Event) => {
        if (isDisabled) {
            event.preventDefault();
            return;
        }

        const isValid = onValidate?.();
        if (isValid === false) {
            event.preventDefault();
        }
    };

    return (
        <StyledWrapper {...styles.container} data-test-selector="googlePayButton">
            <GooglePayButton
                environment={googlePayEnvironment}
                paymentRequest={{
                    apiVersion: 2,
                    apiVersionMinor: 0,
                    allowedPaymentMethods: [
                        {
                            type: "CARD",
                            parameters: {
                                allowedAuthMethods: ["PAN_ONLY", "CRYPTOGRAM_3DS"],
                                allowedCardNetworks: ["AMEX", "DISCOVER", "JCB", "MASTERCARD", "VISA"],
                            },
                            tokenizationSpecification: {
                                type: "PAYMENT_GATEWAY",
                                parameters: {
                                    gateway: "spreedly",
                                    gatewayMerchantId: gatewayMerchantId ?? "", // Should be Spreedly's environmentKey
                                },
                            },
                        },
                    ],
                    merchantInfo: {
                        merchantId: googlePayConfig.merchantId,
                        merchantName: googlePayConfig.merchantName,
                    },
                    transactionInfo: {
                        totalPriceStatus: "FINAL",
                        totalPriceLabel: translate("Total"),
                        totalPrice: amount.toString(),
                        currencyCode,
                    },
                }}
                onLoadPaymentData={handleLoadPaymentData}
                onError={handleError}
                onClick={handleClick}
                buttonColor="black"
                buttonType="checkout"
                buttonSizeMode="fill"
                style={{
                    opacity: isDisabled ? 0.6 : 1,
                    pointerEvents: isDisabled ? "none" : "auto",
                    width: "228px",
                }}
            />
            {error && (
                <Typography {...styles.errorText} data-test-selector="googlePayButtonError">
                    {error}
                </Typography>
            )}
        </StyledWrapper>
    );
};

export default connect(mapStateToProps, mapDispatchToProps)(GooglePayButtonWrapper);
