import {ReactElement, ReactNode} from "react";

export type CartTotals = {
    currency_code: string
    currency_decimal_separator: string
    currency_minor_unit: number
    currency_prefix: string
    currency_suffix: string
    currency_symbol: string
    currency_thousand_separator: string
    tax_lines: string[]
    total_discount: string
    total_discount_tax: string
    total_fees: string
    total_fees_tax: string
    total_items: string
    total_items_tax: string
    total_price: string
    total_shipping: string
    total_shipping_tax: string
    total_tax: string
};

export type PaymentDetails = {
    cart: Record<string, unknown>,
    cartTotals: CartTotals,
    cartNeedsShipping: boolean,
    shippingAddress: Record<string, unknown>,
    billingAddress: Record<string, unknown>,
    selectedShippingMethods: Record<string, unknown>,
    paymentRequirements: string[]
}

export type PaymentMethodOptions = {
    /**
     * This should be a unique string (wise to try to pick something unique for your gateway that wouldn't be used by another implementation) that is used as the identifier for the gateway client side. If paymentMethodId is not provided, name is used for paymentMethodId as well.
     */
    name: string;
    /**
     * This should be a React node that will output in the express payment method area when the block is rendered in the frontend. It will be cloned in the rendering process. When cloned, this React node will receive props passed in from the checkout payment method interface that will allow your component to interact with checkout data (more on these props later).
     */
    content: ReactElement<PaymentMethodProps>;
    /**
     * This should be a React node that will be output in the express payment method area when the block is rendered in the editor. It will be cloned in the rendering process. When cloned, this React node will receive props from the payment method interface to checkout (but they will contain preview data).
     */
    edit: ReactElement<PaymentMethodProps>;
    /**
     * A callback to determine whether the payment method should be available as an option for the shopper. The function will be passed an object containing data about the current order.
     * Returns a boolean value - true if payment method is available for use. If your gateway needs to perform async initialization to determine availability, you can return a promise (resolving to boolean). This allows a payment method to be hidden based on the cart, e.g. if the cart has physical/shippable products (example: Cash on delivery); or for payment methods to control whether they are available depending on other conditions.
     *
     * canMakePayment only runs on the frontend of the Store. In editor context, rather than use canMakePayment, the editor will assume the payment method is available (true) so that the defined edit component is shown to the merchant.
     *
     * Keep in mind this function could be invoked multiple times in the lifecycle of the checkout and thus any expensive logic in the callback provided on this property should be memoized.
     */
    canMakePayment(paymentDetails: PaymentDetails): void;

    /**
     * This is the only optional configuration object. The value of this property is what will accompany the checkout processing request to the server and is used to identify what payment method gateway class to load for processing the payment (if the shopper selected the gateway). So for instance if this is stripe, then WC_Gateway_Stripe::process_payment will be invoked for processing the payment.
     */
    paymentMethodId?: string;

    /**
     * This should be a React node that contains logic handling any processing your payment method has to do with saved payment methods if your payment method supports them. This component will be rendered whenever a customer's saved token using your payment method for processing is selected for making the purchase.
     */
    savedTokenComponent?: ReactNode;
    /**
     * This should be a React node that will be used to output the label for the option where the payment methods are. For example it might be <strong>Credit/Debit Cart</strong> or you might output images.
     */
    label?: ReactNode;
    /**
     * This is the label that will be read out via screen-readers when the payment method is selected
     */
    ariaLabel: string;
    /**
     * This is an optional label which will change the default "Place Order" button text to something else when the payment method is selected. As an example, the PayPal Standard payment method changes the text of the button to "Proceed to PayPal" when it is selected as the payment method for checkout because the payment method takes the shopper offsite to PayPal for completing the payment.
     */
    placeOrderButtonLabel?: ReactNode;
    /**
     * This is an object containing information about what features your payment method supports. The following keys are valid here:
     */
    supports?: {
        /**
         * This is an array of payment features supported by the gateway. It is used to crosscheck if the payment method can be used for the content of the cart. By default payment methods should support at least products feature. If no value is provided then this assumes that ['products'] are supported.
         */
        features?: string[];
        /**
         * This value will determine whether saved cards associated with your payment method are shown to the customer.
         */
        showSavedCards?: boolean;
        /**
         * This value will control whether to show the checkbox which allows customers to save their payment method for future payments.
         */
        showSaveOptions?: boolean;
    };
};

export type PaymentMethodProps = {
    /**
     * The slug of the current active payment method in the checkout.	-
     */
    activePaymentMethod: string
    /**
     * Contains everything related to billing.
     */
    billing: {
        billingAddress: string
        cartTotal: string
        currency: string
        cartTotalItems: string
        displayPricesIncludingTax: string
        appliedCoupons: string
        customerId: string
    }
    /**
     * Data exposed from the cart including items, fees, and any registered extension data. Note that this data should be treated as immutable (should not be modified/mutated) or it will result in errors in your application.
     */
    cartData: {
        readonly cartItems: unknown[]
        readonly cartFees: unknown[]
        readonly extensions: unknown[]
    }
    /**
     * The current checkout status exposed as various boolean state.	isCalculating, isComplete, isIdle, isProcessing
     */
    checkoutStatus: {
        isCalculating: boolean;
        isComplete: boolean;
        isIdle: boolean;
        isProcessing: boolean;
    }

    /**
     * It exposes React components that can be implemented by your payment method for various common interface elements used by payment methods.
     */
    components: {
        /**
         * a container for holding validation errors which typically you'll include after any inputs
         */
        ValidationInputError: ReactNode;
        /**
         * use this component for the payment method label, including an optional icon
         */
        PaymentMethodLabel: ReactNode;
        /**
         * a React component used for displaying payment method icons
         */
        PaymentMethodIcons: ReactNode;
        /**
         * a wrapper component that handles displaying a loading state when the isLoading prop is true. Exposes the LoadingMask component
         */
        LoadingMask: ReactNode;
    }
    /**
     * Contains some constants that can be helpful when using the event emitter. Read the Emitting Events section for more details.
     */
    emitResponse: {
        /**
         * This is an object containing properties referencing areas where notices can be targeted in the checkout.
         */
        noticeContexts: {
            /**
             * This is a reference to the notice area in the payment methods step.
             */
            PAYMENTS: ReactNode[];
            /**
             * This is a reference to the notice area in the express payment methods step.
             */
            EXPRESS_PAYMENTS: ReactNode[];
        }
        /**
         * This is an object containing properties referencing the various response types that can be returned by observers for some event emitters. It makes it easier for autocompleting the types and avoiding typos due to human error. The types are SUCCESS, FAIL, ERROR. The values for these types also correspond to the payment status types from the checkout endpoint response from the server.
         */
        responseTypes: ['success', 'failure', 'pending', 'error'];
    }
    /**
     * Contains all the checkout event emitter registration functions. These are functions the payment method can register observers on to interact with various points in the checkout flow (see this doc for more info).	onCheckoutValidation, onCheckoutSuccess, onCheckoutFail, onPaymentSetup, onShippingRateSuccess, onShippingRateFail, onShippingRateSelectSuccess, onShippingRateSelectFail
     */
    eventRegistration: object
    /**
     * Provided to express payment methods that should be triggered when the payment method button is clicked (which will signal to checkout the payment method has taken over payment processing)
     */
    onClick: () => void;
    /**
     * Provided to express payment methods that should be triggered when the express payment method modal closes and control is returned to checkout.
     */
    onClose: () => void;
    /**
     * Submits the checkout and begins processing
     */
    onSubmit: () => void;
    /**
     * Various payment status helpers. Note, your payment method does not have to handle setting this status client side. Checkout will handle this via the responses your payment method gives from observers registered to checkout event emitters.	isPristine, isStarted, isProcessing, isFinished, hasError, hasFailed, isSuccessful (see below for explanation)
     */
    paymentStatus: {
        /**
         * This is true when the current payment status is PRISTINE.
         */
        isPristine(): boolean;
        /**
         * This is true when the current payment status is EXPRESS_STARTED.
         */
        isStarted(): boolean;
        /**
         * This is true when the current payment status is PROCESSING.
         */
        isProcessing(): boolean;
        /**
         * This is true when the current payment status is one of ERROR, FAILED, orSUCCESS.
         */
        isFinished(): boolean;
        /**
         * This is true when the current payment status is ERROR.
         */
        hasError(): boolean;
        /**
         * This is true when the current payment status is FAILED.
         */
        hasFailed(): boolean;
        /**
         * This is true when the current payment status is SUCCESS
         */
        isSuccessful(): boolean;
    }
    /**
     * Receives a string and allows express payment methods to set an error notice for the express payment area on demand. This can be necessary because some express payment method processing might happen outside of checkout events.
     */
    setExpressPaymentError(error: string): void
    /**
     * Contains all shipping related data (outside of the shipping status).	shippingRates, shippingRatesLoading, selectedRates, setSelectedRates, isSelectingRate, shippingAddress, setShippingAddress, and needsShipping
     */
    shippingData: {
        shippingRates: unknown
        shippingRatesLoading: unknown
        selectedRates: unknown
        setSelectedRates: unknown
        isSelectingRate: unknown
        shippingAddress: unknown
        setShippingAddress: unknown
        needsShipping: unknown
    }
    /**
     * Various shipping status helpers.
     */
    shippingStatus: {
        /**
         * an object with various error statuses that might exist for shipping
         */
        shippingErrorStatus: unknown
        /**
         * an object containing all the possible types for shipping error status
         */
        shippingErrorTypes: unknown
    }
    /**
     * Indicates whether or not the shopper has selected to save their payment method details (for payment methods that support saved payments). True if selected, false otherwise. Defaults to false.
     */
    shouldSavePayment: boolean
}
