/* eslint-disable @typescript-eslint/indent */
import 'react-international-phone/style.css';

import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
// import { useTheme } from '@arcblock/ux/lib/Theme';
import Toast from '@arcblock/ux/lib/Toast';
import type { TCheckoutSession, TCustomer, TPaymentIntent, TPaymentMethodExpanded } from '@blocklet/payment-types';
import { Box, Button, CircularProgress, Divider, Fade, Stack, Tooltip, Typography } from '@mui/material';
import { useMemoizedFn, useSetState } from 'ahooks';
import pWaitFor from 'p-wait-for';
import { useEffect, useMemo, useRef } from 'react';
import { Controller, useFormContext, useWatch } from 'react-hook-form';
import { joinURL } from 'ufo';
import { dispatch } from 'use-bus';
import isEmail from 'validator/es/lib/isEmail';
import { fromUnitToToken } from '@ocap/util';
import DID from '@arcblock/ux/lib/DID';

import isEmpty from 'lodash/isEmpty';
import { HelpOutline, OpenInNew } from '@mui/icons-material';
import FormInput from '../../components/input';
import FormLabel from '../../components/label';
import { usePaymentContext } from '../../contexts/payment';
import { useSubscription } from '../../hooks/subscription';
import api from '../../libs/api';
import {
  flattenPaymentMethods,
  formatError,
  formatQuantityInventory,
  getPrefix,
  getStatementDescriptor,
  getTokenBalanceLink,
  isCrossOrigin,
} from '../../libs/util';
import type { CheckoutCallbacks, CheckoutContext } from '../../types';
import AddressForm from './address';
import CurrencySelector from './currency';
import PhoneInput from './phone';
import StripeCheckout from './stripe';
import { useMobile } from '../../hooks/mobile';
import { formatPhone, validatePhoneNumber } from '../../libs/phone-validator';
import LoadingButton from '../../components/loading-button';
import OverdueInvoicePayment from '../../components/over-due-invoice-payment';
import { saveCurrencyPreference } from '../../libs/currency';
import ConfirmDialog from '../../components/confirm';
import { getFieldValidation } from '../../libs/validator';

export const waitForCheckoutComplete = async (sessionId: string) => {
  let result: CheckoutContext;

  await pWaitFor(
    async () => {
      const { data } = await api.get(`/api/checkout-sessions/retrieve/${sessionId}`);
      if (
        data.paymentIntent &&
        data.paymentIntent.status === 'requires_action' &&
        data.paymentIntent.last_payment_error
      ) {
        throw new Error(data.paymentIntent.last_payment_error.message);
      }

      result = data;

      return (
        // eslint-disable-next-line @typescript-eslint/return-await
        data.checkoutSession?.status === 'complete' &&
        ['paid', 'no_payment_required'].includes(data.checkoutSession?.payment_status)
      );
    },
    { interval: 2000, timeout: 3 * 60 * 1000 }
  );

  // @ts-ignore
  return result;
};

export const hasDidWallet = (user: any) => {
  const connected = user?.connectedAccounts || user?.extraConfigs?.connectedAccounts || [];
  return connected.some((x: any) => x.provider === 'wallet');
};

type PageData = CheckoutContext &
  CheckoutCallbacks & {
    onlyShowBtn?: boolean;
    isDonation?: boolean;
  };

type UserInfo = {
  name?: string;
  fullName?: string;
  email?: string;
  phone?: string;
  address?: {
    country?: string;
    state?: string;
    province?: string;
    line1?: string;
    line2?: string;
    city?: string;
    postal_code?: string;
    postalCode?: string;
  };
  metadata?: {
    phone?: {
      country?: string;
      phoneNumber?: string;
    };
  };
};

type FastCheckoutInfo = {
  open: boolean;
  loading: boolean;
  sourceType: 'balance' | 'delegation' | 'credit';
  amount: string;
  payer?: string;
  availableCredit?: string;
  balance?: string;
};

const setUserFormValues = (
  userInfo: UserInfo,
  currentValues: any,
  setValue: Function,
  options: { preferExisting?: boolean; showPhone?: boolean; shouldValidate?: boolean } = {}
) => {
  const { preferExisting = true, shouldValidate = false } = options;
  const basicFields = {
    customer_name: userInfo.name || userInfo.fullName,
    customer_email: userInfo.email,
    customer_phone: formatPhone(userInfo.phone),
  };
  const addressFields: Record<string, any> = {
    'billing_address.state': userInfo.address?.state || userInfo.address?.province,
    'billing_address.line1': userInfo.address?.line1,
    'billing_address.line2': userInfo.address?.line2,
    'billing_address.city': userInfo.address?.city,
    'billing_address.postal_code': userInfo.address?.postal_code || userInfo.address?.postalCode,
    'billing_address.country': userInfo.address?.country || 'us',
  };

  if (options.showPhone) {
    addressFields['billing_address.country'] = userInfo.metadata?.phone?.country || userInfo.address?.country;
  }

  const allFields = { ...addressFields, ...basicFields };

  Object.entries(allFields).forEach(([field, value]) => {
    if (!preferExisting || !currentValues[field.split('.')[0]]) {
      setValue(field, value, { shouldValidate });
    }
  });
};

// FIXME: https://stripe.com/docs/elements/address-element
// TODO: https://country-regions.github.io/react-country-region-selector/
// https://www.npmjs.com/package/postal-codes-js
// https://www.npmjs.com/package/val-zip
// https://npm.runkit.com/zips
export default function PaymentForm({
  checkoutSession,
  paymentMethods,
  paymentIntent,
  paymentLink,
  customer,
  onPaid,
  onError,
  // mode,
  action,
  onlyShowBtn = false,
  isDonation = false,
}: PageData) {
  // const theme = useTheme();
  const { t, locale } = useLocaleContext();
  const { isMobile } = useMobile();
  const { session, connect, payable } = usePaymentContext();
  const subscription = useSubscription('events');
  const formErrorPosition = 'bottom';
  const {
    control,
    getValues,
    setValue,
    handleSubmit,
    formState: { errors },
    trigger,
  } = useFormContext();
  const errorRef = useRef<HTMLDivElement | null>(null);
  const quantityInventoryStatus = useMemo(() => {
    let status = true;
    for (const item of checkoutSession.line_items) {
      if (formatQuantityInventory(item.price, item.quantity)) {
        status = false;
        break;
      }
    }
    return status;
  }, [checkoutSession]);
  const [state, setState] = useSetState<{
    submitting: boolean;
    paying: boolean;
    paid: boolean;
    paymentIntent?: TPaymentIntent;
    stripeContext?: {
      client_secret: string;
      intent_type: string;
      status: string;
    };
    customer?: TCustomer;
    customerLimited?: boolean;
    stripePaying: boolean;
    fastCheckoutInfo: FastCheckoutInfo | null;
    creditInsufficientInfo: {
      open: boolean;
    } | null;
  }>({
    submitting: false,
    paying: false,
    paid: false,
    paymentIntent,
    stripeContext: undefined,
    customer,
    customerLimited: false,
    stripePaying: false,
    fastCheckoutInfo: null,
    creditInsufficientInfo: null,
  });

  const currencies = flattenPaymentMethods(paymentMethods);

  const onCheckoutComplete = useMemoizedFn(async ({ response }: { response: TCheckoutSession }) => {
    if (response.id === checkoutSession.id && state.paid === false) {
      await handleConnected();
    }
  });

  useEffect(() => {
    if (subscription) {
      subscription.on('checkout.session.completed', onCheckoutComplete);
    }
  }, [subscription]); // eslint-disable-line react-hooks/exhaustive-deps

  const mergeUserInfo = (
    customerInfo: UserInfo | (TCustomer & { fullName?: string }),
    userInfo?: UserInfo
  ): UserInfo => {
    return {
      ...(userInfo || {}),
      name: customerInfo?.name || customerInfo?.fullName || userInfo?.name || userInfo?.fullName,
      fullName: customerInfo?.name || customerInfo?.fullName || userInfo?.name || userInfo?.fullName,
      email: customerInfo?.email || userInfo?.email,
      phone: customerInfo?.phone || userInfo?.phone,
      address: {
        ...(userInfo?.address || {}),
        ...(customerInfo?.address || {}),
        country: customerInfo?.address?.country || userInfo?.address?.country,
        state: customerInfo?.address?.state || userInfo?.address?.province,
        line1: customerInfo?.address?.line1 || userInfo?.address?.line1,
        line2: customerInfo?.address?.line2 || userInfo?.address?.line2,
        city: customerInfo?.address?.city || userInfo?.address?.city,
        postal_code: customerInfo?.address?.postal_code || userInfo?.address?.postalCode,
      },
      metadata: {
        ...(userInfo?.metadata || {}),
        phone: {
          country: customerInfo?.address?.country || userInfo?.metadata?.phone?.country,
          phoneNumber: customerInfo?.phone || userInfo?.metadata?.phone?.phoneNumber,
        },
      },
    };
  };

  useEffect(() => {
    const initUserInfo = async () => {
      if (session?.user) {
        const values = getValues();
        let userInfo = session.user;
        try {
          const { data: customerInfo } = await api.get('/api/customers/me?skipSummary=1&fallback=1');
          userInfo = mergeUserInfo(customerInfo, userInfo);
        } catch (err) {
          // @ts-ignore
          userInfo = mergeUserInfo(customer || {}, userInfo);
          console.error(err);
        }
        setUserFormValues(userInfo, values, setValue, {
          preferExisting: false,
          showPhone: checkoutSession.phone_number_collection?.enabled,
        });
      } else {
        setUserFormValues(
          {
            name: '',
            email: '',
            phone: '',
            address: {
              state: '',
              line1: '',
              line2: '',
              city: '',
              postal_code: '',
            },
          },
          {},
          setValue,
          { preferExisting: false, showPhone: checkoutSession.phone_number_collection?.enabled }
        );
      }
    };
    if (state.submitting) {
      return;
    }
    initUserInfo();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [session?.user, checkoutSession.phone_number_collection?.enabled]);

  const paymentMethod = useWatch({ control, name: 'payment_method' });
  const paymentCurrencyId = useWatch({ control, name: 'payment_currency' });
  const customerName = useWatch({ control, name: 'customer_name' });
  const customerEmail = useWatch({ control, name: 'customer_email' });

  // const domSize = useSize(document.body);

  // const isColumnLayout = useCreation(() => {
  //   if (domSize) {
  //     if (domSize?.width <= theme.breakpoints.values.md) {
  //       return true;
  //     }
  //   }
  //   return false;
  // }, [domSize, theme]);

  const afterUserLoggedIn = useMemoizedFn(() => {
    handleSubmit(onFormSubmit, onFormError)();
  });

  const payee = getStatementDescriptor(checkoutSession.line_items);
  let buttonText = '';
  if (paymentLink?.donation_settings) {
    if (action) {
      buttonText = action;
    } else {
      buttonText = t('payment.checkout.donate');
    }
  } else {
    buttonText = t(`payment.checkout.${checkoutSession.mode}`);
  }
  buttonText = session?.user || isDonation ? buttonText : t('payment.checkout.connect', { action: buttonText });

  const method = paymentMethods.find((x) => x.id === paymentMethod) as TPaymentMethodExpanded;
  const paymentCurrency = currencies.find((x) => x.id === paymentCurrencyId);
  const showStake = method.type === 'arcblock' && !checkoutSession.subscription_data?.no_stake;

  const isDonationMode = checkoutSession?.submit_type === 'donate' && isDonation;
  const showForm = useMemo(() => {
    if (!session?.user) {
      return false;
    }
    if (method.type === 'stripe') {
      return true;
    }
    if (checkoutSession.phone_number_collection?.enabled) {
      return true;
    }
    const mode = checkoutSession.billing_address_collection;
    if (mode === 'required') {
      return true;
    }
    if (customerName && customerEmail) {
      return false;
    }
    return true;
  }, [session?.user, method, checkoutSession, customerName, customerEmail]);

  const handleConnected = async () => {
    setState({ paying: true });
    try {
      const result = await waitForCheckoutComplete(checkoutSession.id);
      if (state.paid === false) {
        setState({ paid: true, paying: false });
        onPaid(result);
      }
    } catch (err) {
      Toast.error(formatError(err));
    } finally {
      setState({ paying: false });
    }
  };

  useEffect(() => {
    if (errorRef.current && !isEmpty(errors) && isMobile) {
      errorRef.current.scrollIntoView({ behavior: 'smooth' });
    }
  }, [errors, isMobile]);

  const onUserLoggedIn = async () => {
    const { data: profile } = await api.get('/api/customers/me?fallback=1&skipSummary=1');
    if (profile) {
      const values = getValues();
      const userInfo = mergeUserInfo(profile, session?.user);
      setUserFormValues(userInfo, values, setValue, {
        preferExisting: false,
        showPhone: checkoutSession.phone_number_collection?.enabled,
        shouldValidate: true,
      });
      await trigger();
    }
  };

  const handleFastCheckoutConfirm = async () => {
    if (!state.fastCheckoutInfo) return;

    setState({
      fastCheckoutInfo: {
        ...state.fastCheckoutInfo,
        loading: true,
      },
    });

    try {
      const result = await api.post(`/api/checkout-sessions/${checkoutSession.id}/fast-checkout-confirm`);
      if (result.data.fastPaid) {
        setState({
          fastCheckoutInfo: null,
          paying: true,
        });
        await handleConnected();
      } else {
        Toast.error(t('payment.checkout.fastPay.failed'));
        setState({
          fastCheckoutInfo: null,
          paying: true,
        });
        openConnect();
      }
    } catch (err) {
      console.error(err);
      Toast.error(formatError(err));
      setState({
        fastCheckoutInfo: null,
      });
    }
  };

  const handleFastCheckoutCancel = () => {
    setState({ fastCheckoutInfo: null });
  };

  const handleCreditInsufficientClose = () => {
    setState({ creditInsufficientInfo: null });
  };

  const openConnect = () => {
    try {
      if (!['arcblock', 'ethereum', 'base'].includes(method.type)) {
        return;
      }
      setState({ paying: true });
      connect.open({
        locale,
        containerEl: undefined as unknown as Element,
        action: checkoutSession.mode,
        prefix: joinURL(getPrefix(), '/api/did'),
        saveConnect: false,
        useSocket: isCrossOrigin() === false,
        extraParams: { checkoutSessionId: checkoutSession.id, sessionUserDid: session?.user?.did },
        onSuccess: async () => {
          connect.close();
          await handleConnected();
        },
        onClose: () => {
          connect.close();
          setState({ submitting: false, paying: false });
        },
        onError: (err: any) => {
          console.error(err);
          setState({ submitting: false, paying: false });
          onError(err);
        },
        messages: {
          title: t('payment.checkout.connectModal.title', { action: buttonText }),
          scan: t('payment.checkout.connectModal.scan'),
          confirm: t('payment.checkout.connectModal.confirm'),
          cancel: t('payment.checkout.connectModal.cancel'),
        },
      } as any);
    } catch (err) {
      Toast.error(formatError(err));
    }
  };

  const onFormSubmit = async (data: any) => {
    setState({ submitting: true });
    try {
      let result;
      if (isDonationMode) {
        result = await api.put(`/api/checkout-sessions/${checkoutSession.id}/donate-submit`, data);
      } else {
        result = await api.put(`/api/checkout-sessions/${checkoutSession.id}/submit`, data);
      }

      setState({
        paymentIntent: result.data.paymentIntent,
        stripeContext: result.data.stripeContext,
        customer: result.data.customer,
        submitting: false,
        customerLimited: false,
      });

      if (['arcblock', 'ethereum', 'base'].includes(method.type)) {
        // 优先判断 credit 支付
        if (paymentCurrency?.type === 'credit') {
          if (result.data.creditSufficient === true) {
            // 如果是 credit 支付且有足够额度，显示 credit 确认弹窗
            setState({
              fastCheckoutInfo: {
                open: true,
                loading: false,
                sourceType: 'credit',
                amount: result.data.fastPayInfo?.amount || '0',
                payer: result.data.fastPayInfo?.payer,
                availableCredit: result.data.fastPayInfo?.amount || '0',
                balance: result.data.fastPayInfo?.token?.balance || '0',
              },
            });
          } else {
            // 如果是 credit 支付但额度不足，显示额度不足弹窗
            setState({
              creditInsufficientInfo: {
                open: true,
              },
            });
          }
        } else if (
          (result.data.balance?.sufficient || result.data.delegation?.sufficient) &&
          !isDonationMode &&
          result.data.fastPayInfo
        ) {
          setState({
            fastCheckoutInfo: {
              open: true,
              loading: false,
              sourceType: result.data.fastPayInfo.type,
              amount: result.data.fastPayInfo.amount,
              payer: result.data.fastPayInfo.payer,
            },
          });
        } else {
          openConnect();
        }
      }
      if (['stripe'].includes(method.type)) {
        if (result.data.stripeContext?.status === 'succeeded') {
          setState({ paying: true });
        } else {
          setTimeout(() => {
            setState({ stripePaying: true });
          }, 200);
        }
      }
    } catch (err: any) {
      console.error(err);
      let shouldToast = true;
      if (err.response?.data?.code) {
        dispatch(`error.${err.response?.data?.code}`);
        if (err.response.data.code === 'CUSTOMER_LIMITED') {
          shouldToast = false;
          setState({ customerLimited: true });
        }
      }
      if (shouldToast) {
        Toast.error(formatError(err));
      }
    } finally {
      setState({ submitting: false });
    }
  };

  const onFormError = (err: unknown) => {
    if (err) {
      console.error(err);
    }
    setState({ submitting: false });
  };

  const onAction = () => {
    if (state.submitting || state.paying) {
      return;
    }
    if (errorRef.current && !isEmpty(errors) && isMobile) {
      errorRef.current.scrollIntoView({ behavior: 'smooth' });
    }
    if (session?.user) {
      handleSubmit(onFormSubmit, onFormError)();
    } else {
      if (isDonationMode) {
        handleSubmit(onFormSubmit, onFormError)();
        return;
      }
      session?.login(() => {
        setState({ submitting: true });
        onUserLoggedIn()
          .then(afterUserLoggedIn)
          .catch((err) => {
            console.error(err);
            setState({ submitting: false });
          });
      });
    }
  };

  const onStripeConfirm = async () => {
    setState({ stripePaying: false, paying: true });
    await handleConnected();
  };

  const onStripeCancel = () => {
    setState({ stripePaying: false });
  };

  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (
        e.key === 'Enter' &&
        !state.submitting &&
        !state.paying &&
        !state.stripePaying &&
        quantityInventoryStatus &&
        payable
      ) {
        onAction();
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => {
      window.removeEventListener('keydown', handleKeyDown);
    };
  }, [state.submitting, state.paying, state.stripePaying, quantityInventoryStatus, payable]); // eslint-disable-line react-hooks/exhaustive-deps

  const balanceLink = getTokenBalanceLink(method, state.fastCheckoutInfo?.payer || '');

  const FastCheckoutConfirmDialog = state.fastCheckoutInfo && (
    <ConfirmDialog
      onConfirm={handleFastCheckoutConfirm}
      onCancel={handleFastCheckoutCancel}
      title={
        state.fastCheckoutInfo.sourceType === 'credit'
          ? t('payment.checkout.fastPay.credit.title')
          : t('payment.checkout.fastPay.title')
      }
      message={
        state.fastCheckoutInfo.sourceType === 'credit' ? (
          <Typography>
            {t('payment.checkout.fastPay.credit.meteringSubscriptionMessage', {
              available: `${fromUnitToToken(state.fastCheckoutInfo?.balance || '0', paymentCurrency?.decimal || 18).toString()} ${paymentCurrency?.symbol}`,
            })}
          </Typography>
        ) : (
          <Stack>
            <Typography>{t('payment.checkout.fastPay.autoPaymentReason')}</Typography>
            <Divider sx={{ mt: 1.5, mb: 1.5 }} />
            <Stack spacing={1}>
              <Stack
                sx={{
                  flexDirection: 'row',
                  alignItems: 'center',
                  justifyContent: 'space-between',
                }}>
                <Typography
                  sx={{
                    color: 'text.primary',
                    whiteSpace: 'nowrap',
                  }}>
                  {t('payment.checkout.fastPay.payer')}
                </Typography>
                <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
                  <DID did={state.fastCheckoutInfo.payer || ''} compact responsive={false} />
                  {balanceLink && (
                    <Tooltip title={t('payment.checkout.fastPay.balanceLink')} placement="top">
                      <OpenInNew
                        sx={{
                          color: 'text.lighter',
                          fontSize: '0.85rem',
                          cursor: 'pointer',
                          '&:hover': { color: 'text.primary' },
                        }}
                        onClick={() => {
                          window.open(balanceLink, '_blank');
                        }}
                      />
                    </Tooltip>
                  )}
                </Box>
              </Stack>
              <Stack
                sx={{
                  flexDirection: 'row',
                  alignItems: 'center',
                  justifyContent: 'space-between',
                }}>
                <Typography
                  sx={{
                    color: 'text.primary',
                  }}>
                  {t('payment.checkout.fastPay.amount')}
                </Typography>
                <Typography>
                  {fromUnitToToken(state.fastCheckoutInfo.amount, paymentCurrency?.decimal || 18).toString()}{' '}
                  {paymentCurrency?.symbol}
                </Typography>
              </Stack>
            </Stack>
          </Stack>
        )
      }
      loading={state.fastCheckoutInfo.loading}
      color="primary"
    />
  );

  const CreditInsufficientDialog = state.creditInsufficientInfo && (
    <ConfirmDialog
      onConfirm={handleCreditInsufficientClose}
      onCancel={handleCreditInsufficientClose}
      title={t('payment.checkout.fastPay.credit.insufficientTitle')}
      message={<Typography>{t('payment.checkout.fastPay.credit.insufficientMessage')}</Typography>}
      confirm={t('common.confirm')}
    />
  );

  if (onlyShowBtn) {
    return (
      <>
        <Box className="cko-payment-submit-btn">
          <Button
            variant="contained"
            color="primary"
            size="large"
            className="cko-submit-button"
            onClick={() => {
              if (state.submitting || state.paying) {
                return;
              }
              onAction();
            }}
            fullWidth
            disabled={state.stripePaying || !quantityInventoryStatus || !payable}>
            {(state.submitting || state.paying) && (
              <CircularProgress size={16} sx={{ mr: 0.5, color: 'primary.contrastText' }} />
            )}
            {state.submitting || state.paying ? t('payment.checkout.processing') : buttonText}
          </Button>
        </Box>
        {state.customerLimited && (
          <OverdueInvoicePayment
            customerId={customer?.id || session?.user?.did}
            onPaid={() => {
              setState({ customerLimited: false });
              onAction();
            }}
            alertMessage={t('payment.customer.pastDue.alert.customMessage')}
            detailLinkOptions={{
              enabled: true,
              onClick: () => {
                setState({ customerLimited: false });
                window.open(
                  joinURL(
                    getPrefix(),
                    `/customer/invoice/past-due?referer=${encodeURIComponent(window.location.href)}`
                  ),
                  '_self'
                );
              },
            }}
            dialogProps={{
              open: state.customerLimited,
              onClose: () => setState({ customerLimited: false }),
              title: t('payment.customer.pastDue.alert.title'),
            }}
          />
        )}
        {FastCheckoutConfirmDialog}
        {CreditInsufficientDialog}
      </>
    );
  }
  return (
    <>
      <Fade in>
        <Stack className="cko-payment-contact">
          <Typography
            title={t('payment.checkout.paymentDetails')}
            sx={{
              color: 'text.primary',
              fontSize: {
                xs: '18px',
                md: '24px',
              },
              fontWeight: '700',
              lineHeight: '32px',
              mb: 2.5,
            }}>
            {t('payment.checkout.paymentDetails')}
          </Typography>
          <Fade in>
            <Stack
              direction="column"
              className="cko-payment-methods"
              sx={{
                alignItems: 'flex-start',
              }}>
              <Stack direction="row" sx={{ width: '100%' }}>
                <Controller
                  name="payment_currency"
                  control={control}
                  render={({ field }) => (
                    <CurrencySelector
                      value={field.value}
                      currencies={currencies}
                      onChange={(id: string, methodId: string) => {
                        field.onChange(id);
                        setValue('payment_method', methodId);
                        saveCurrencyPreference(id, session?.user?.did);
                      }}
                    />
                  )}
                />
              </Stack>
              {state.stripePaying && state.stripeContext && (
                <StripeCheckout
                  clientSecret={state.stripeContext.client_secret}
                  intentType={state.stripeContext.intent_type}
                  publicKey={method.settings.stripe?.publishable_key as string}
                  customer={state.customer as TCustomer}
                  mode={checkoutSession.mode}
                  onConfirm={onStripeConfirm}
                  onCancel={onStripeCancel}
                  returnUrl={checkoutSession?.success_url}
                />
              )}
            </Stack>
          </Fade>
          {showForm && (
            <Stack
              direction="column"
              className="cko-payment-form"
              id="cko-payment-form"
              spacing={0}
              ref={!isEmpty(errors) ? (errorRef as any) : undefined}
              sx={{ flex: 1, overflow: 'auto', py: 1 }}>
              <FormLabel className="base-label">{t('payment.checkout.customer.name')}</FormLabel>
              <FormInput
                name="customer_name"
                variant="outlined"
                errorPosition={formErrorPosition}
                rules={{
                  required: t('payment.checkout.required'),
                  ...getFieldValidation('customer_name', checkoutSession.metadata?.page_info?.field_validation, locale),
                }}
              />
              <FormLabel className="base-label">{t('payment.checkout.customer.email')}</FormLabel>
              <FormInput
                name="customer_email"
                variant="outlined"
                errorPosition={formErrorPosition}
                rules={{
                  required: t('payment.checkout.required'),
                  validate: (x) => (isEmail(x) ? true : t('payment.checkout.invalid')),
                  ...getFieldValidation(
                    'customer_email',
                    checkoutSession.metadata?.page_info?.field_validation,
                    locale
                  ),
                }}
              />
              {checkoutSession.phone_number_collection?.enabled && (
                <>
                  <FormLabel className="base-label">{t('payment.checkout.customer.phone')}</FormLabel>
                  <PhoneInput
                    name="customer_phone"
                    variant="outlined"
                    errorPosition={formErrorPosition}
                    placeholder="Phone number"
                    rules={{
                      required: t('payment.checkout.required'),
                      validate: async (x: string) => {
                        const isValid = await validatePhoneNumber(x);
                        return isValid ? true : t('payment.checkout.invalid');
                      },
                      ...getFieldValidation(
                        'customer_phone',
                        checkoutSession.metadata?.page_info?.field_validation,
                        locale
                      ),
                    }}
                  />
                </>
              )}
              <AddressForm
                mode={checkoutSession.billing_address_collection as string}
                stripe={method?.type === 'stripe'}
                sx={{ marginTop: '0 !important' }}
                fieldValidation={checkoutSession.metadata?.page_info?.field_validation}
                errorPosition={formErrorPosition}
              />
            </Stack>
          )}
        </Stack>
      </Fade>
      <Divider sx={{ mt: 2.5, mb: 2.5 }} />
      <Fade in>
        <Stack className="cko-payment-submit">
          <Box className="cko-payment-submit-btn">
            <LoadingButton
              variant="contained"
              color="primary"
              size="large"
              className="cko-submit-button"
              onClick={() => {
                onAction();
              }}
              fullWidth
              loading={state.submitting || state.paying}
              disabled={state.stripePaying || !quantityInventoryStatus || !payable}>
              {state.submitting || state.paying ? t('payment.checkout.processing') : buttonText}
            </LoadingButton>
          </Box>

          {['subscription', 'setup'].includes(checkoutSession.mode) && (
            <Typography sx={{ mt: 2.5, color: 'text.lighter', fontSize: '0.7875rem', lineHeight: '0.9625rem' }}>
              {showStake
                ? t('payment.checkout.confirm.withStake', { payee })
                : t('payment.checkout.confirm.withoutStake', { payee })}
            </Typography>
          )}
          {checkoutSession.metadata?.page_info?.form_purpose_description && (
            <Box sx={{ mt: 1, display: 'flex', alignItems: 'center', gap: 0.5 }}>
              <HelpOutline sx={{ color: 'text.lighter', fontSize: '0.75rem' }} />
              <Typography variant="body2" sx={{ fontSize: '0.75rem', color: 'text.lighter' }}>
                {locale === 'zh'
                  ? checkoutSession.metadata.page_info.form_purpose_description.zh
                  : checkoutSession.metadata.page_info.form_purpose_description.en}
              </Typography>
            </Box>
          )}
        </Stack>
      </Fade>
      {state.customerLimited && (
        <OverdueInvoicePayment
          customerId={customer?.id || session?.user?.did}
          onPaid={() => {
            setState({ customerLimited: false });
            onAction();
          }}
          alertMessage={t('payment.customer.pastDue.alert.customMessage')}
          detailLinkOptions={{
            enabled: true,
            onClick: () => {
              setState({ customerLimited: false });
              window.open(
                joinURL(getPrefix(), `/customer/invoice/past-due?referer=${encodeURIComponent(window.location.href)}`),
                '_self'
              );
            },
          }}
          dialogProps={{
            open: state.customerLimited,
            onClose: () => setState({ customerLimited: false }),
            title: t('payment.customer.pastDue.alert.title'),
          }}
        />
      )}
      {FastCheckoutConfirmDialog}
      {CreditInsufficientDialog}
    </>
  );
}
