/* eslint-disable @typescript-eslint/indent */
import Center from '@arcblock/ux/lib/Center';
import Dialog from '@arcblock/ux/lib/Dialog';
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import type { TCustomer } from '@blocklet/payment-types';
import { CircularProgress, Typography, useTheme } from '@mui/material';
import { styled } from '@mui/system';
import { useSetState } from 'ahooks';
import { useEffect, useCallback } from 'react';
import { useMobile } from '../../../hooks/mobile';
import LoadingButton from '../../../components/loading-button';
import { recoverStripeConfirmResult } from './confirm-recovery';

const { Elements, PaymentElement, useElements, useStripe, loadStripe, LinkAuthenticationElement } = (globalThis as any)
  .__STRIPE_COMPONENTS__;

export type StripeCheckoutFormProps = {
  clientSecret: string;
  intentType: string;
  customer: TCustomer;
  mode: string;
  onConfirm: Function;
  onSkip?: Function | null;
  returnUrl?: string;
  submitButtonText?: string;
};

const PaymentElementContainer = styled('div')`
  width: 100%;
  opacity: 0;
  transition: opacity 300ms ease;
  &.visible {
    opacity: 1;
  }
`;

// @doc https://stripe.com/docs/js/elements_object/create_payment_element
function StripeCheckoutForm({
  clientSecret,
  intentType,
  customer,
  mode,
  onConfirm,
  onSkip = null,
  returnUrl = '',
  submitButtonText = '',
}: StripeCheckoutFormProps) {
  const stripe = useStripe();
  const elements = useElements();
  const { t } = useLocaleContext();
  const theme = useTheme();

  const [state, setState] = useSetState({
    message: '',
    confirming: false,
    loaded: false,
    showBillingForm: false,
    isTransitioning: false,
    paymentMethod: 'card',
  });

  const handlePaymentMethodChange = (event: any) => {
    const method = event.value?.type;
    const needsBillingInfo = method === 'google_pay' || method === 'apple_pay';
    const shouldShowForm = needsBillingInfo && !isCompleteBillingAddress(customer.address);

    if (shouldShowForm && !state.showBillingForm) {
      setState({ isTransitioning: true });
      setTimeout(() => {
        setState({
          isTransitioning: false,
          paymentMethod: method,
          showBillingForm: true,
        });
      }, 300);
    } else {
      // if shouldShowForm is false, set showBillingForm to false immediately
      setState({
        showBillingForm: false,
        paymentMethod: method,
        isTransitioning: false,
      });
    }
  };

  const isCompleteBillingAddress = (address: any) => {
    return address && address.line1 && address.city && address.state && address.postal_code && address.country;
  };

  useEffect(() => {
    if (!stripe) {
      return;
    }

    if (!clientSecret) {
      return;
    }

    const method = intentType === 'payment_intent' ? 'retrievePaymentIntent' : 'retrieveSetupIntent';
    stripe[method](clientSecret).then(({ paymentIntent, setupIntent }: any) => {
      const intent = paymentIntent || setupIntent;
      switch (intent?.status) {
        case 'succeeded':
          setState({ message: t('paymentCredit.preparePayMessage.succeeded') });
          break;
        case 'processing':
          setState({ message: t('paymentCredit.preparePayMessage.processing') });
          break;
        case 'requires_payment_method': // 忽略该状态
        default:
          break;
      }
    });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [stripe, clientSecret]);

  const handleSubmit = useCallback(
    async (e: any) => {
      e.preventDefault();

      if (!stripe || !elements) {
        return;
      }

      try {
        setState({ confirming: true, message: '' });
        const method = intentType === 'payment_intent' ? 'confirmPayment' : 'confirmSetup';

        const { error: submitError } = await elements.submit();
        if (submitError) {
          setState({ confirming: false });
          return;
        }

        const { error, paymentIntent, setupIntent } = await stripe[method]({
          elements,
          redirect: 'if_required',
          confirmParams: {
            return_url: returnUrl || window.location.href,
            ...(!state.showBillingForm
              ? {
                  payment_method_data: {
                    billing_details: {
                      name: customer.name,
                      phone: customer.phone,
                      email: customer.email,
                      address: {
                        ...(customer.address || {}),
                        country: customer.address?.country || 'us',
                        line1: customer.address?.line1 || '',
                        line2: customer.address?.line2 || '',
                        city: customer.address?.city || '',
                        state: customer.address?.state || '',
                        postal_code: customer.address?.postal_code || '00000',
                      },
                    },
                  },
                }
              : {}),
          },
        });
        const intent = paymentIntent || setupIntent;
        if (intent?.status === 'canceled' || intent?.status === 'requires_payment_method') {
          setState({ confirming: false });
          return;
        }

        setState({ confirming: false });
        if (error) {
          if (error.type === 'validation_error') {
            return;
          }
          setState({ message: error.message as string });
          return;
        }

        onConfirm();
      } catch (err: any) {
        console.error(err);
        const recovery = await recoverStripeConfirmResult(stripe, intentType, clientSecret, err);
        setState({ confirming: false });
        if (recovery.action === 'failed') {
          setState({ message: recovery.message });
          return;
        }
        onConfirm();
      }
    },
    [customer, intentType, stripe, state.showBillingForm, returnUrl] // eslint-disable-line
  );

  return (
    <Content onSubmit={handleSubmit}>
      {(!state.paymentMethod || ['link', 'card'].includes(state.paymentMethod)) && (
        <LinkAuthenticationElement
          options={{
            defaultValues: {
              email: customer.email,
            },
          }}
        />
      )}
      <PaymentElementContainer className={!state.isTransitioning ? 'visible' : ''}>
        <PaymentElement
          options={{
            layout: 'auto',
            fields: {
              billingDetails: state.showBillingForm ? 'auto' : 'never',
            },
            readOnly: state.confirming,
            defaultValues: {
              billingDetails: {
                name: customer.name,
                phone: customer.phone,
                email: customer.email,
                address: customer.address,
              },
            },
            appearance: {
              theme: theme.palette.mode,
              variables: {
                colorPrimary: theme.palette.primary.main,
                colorBackground: theme.palette.background.paper,
                colorText: theme.palette.text.primary,
                colorDanger: theme.palette.error.main,
                borderRadius: '4px',
              },
            },
          }}
          onChange={handlePaymentMethodChange}
          onReady={() => setState({ loaded: true })}
        />
      </PaymentElementContainer>

      {(!stripe || !elements || !state.loaded) && (
        <Center relative="parent">
          <CircularProgress />
        </Center>
      )}
      {stripe && elements && state.loaded && (
        <>
          <LoadingButton
            fullWidth
            sx={{ mt: 2, mb: 1, borderRadius: 0, fontSize: '0.875rem' }}
            type="submit"
            disabled={state.confirming || !state.loaded}
            loading={state.confirming}
            variant="contained"
            color="primary"
            size="large">
            {submitButtonText || t('payment.checkout.continue', { action: t(`payment.checkout.${mode}`) })}
          </LoadingButton>
          {onSkip && (
            <LoadingButton
              fullWidth
              sx={{ mb: 1, borderRadius: 0, fontSize: '0.875rem', borderColor: 'divider' }}
              disabled={state.confirming}
              variant="outlined"
              color="primary"
              onClick={() => onSkip()}>
              {t('payment.checkout.skipPaymentMethod', { defaultValue: 'Skip, bind later' })}
            </LoadingButton>
          )}
        </>
      )}
      {state.message && <Typography sx={{ mt: 1, color: 'error.main' }}>{state.message}</Typography>}
    </Content>
  );
}

const Content = styled('form')`
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  min-height: 320px;
`;

export type StripeCheckoutProps = {
  clientSecret: string;
  intentType: string;
  publicKey: string;
  mode: string;
  customer: TCustomer;
  onConfirm: Function;
  onCancel: Function;
  onSkip?: Function | null;
  returnUrl?: string;
  title?: string;
  submitButtonText?: string;
};
export default function StripeCheckout({
  clientSecret,
  intentType,
  publicKey,
  mode,
  customer,
  onConfirm,
  onCancel,
  onSkip = null,
  returnUrl = '',
  title = '',
  submitButtonText = '',
}: StripeCheckoutProps) {
  const stripePromise = loadStripe(publicKey);
  const { isMobile } = useMobile();
  const { t, locale } = useLocaleContext();
  const theme = useTheme();
  const [state, setState] = useSetState({
    open: true,
    closable: true,
  });

  const handleClose = (_: any, reason: string) => {
    if (reason === 'backdropClick') {
      return;
    }

    setState({ open: false });
    onCancel();
  };

  return (
    <Dialog
      title={title || t('payment.checkout.cardPay', { action: t(`payment.checkout.${mode}`) })}
      showCloseButton={state.closable}
      open={state.open}
      onClose={handleClose}
      disableEscapeKeyDown
      sx={{
        '.StripeElement': {
          minWidth: isMobile ? '100%' : '500px',
          py: 1,
        },
        form: {
          justifyContent: 'flex-start',
        },
        '.StripeElement--focus': {
          borderColor: theme.palette.primary.main,
        },
        '.StripeElement--invalid': {
          borderColor: theme.palette.error.main,
        },
        '.StripeElement--complete': {
          borderColor: theme.palette.success.main,
        },
      }}
      PaperProps={{
        style: {
          minWidth: isMobile ? '100%' : '500px',
        },
      }}>
      <Elements
        options={{
          clientSecret,
          locale: locale === 'zh' ? 'zh-CN' : 'en',
          appearance: {
            theme: theme.palette.mode,
            variables: {
              colorPrimary: theme.palette.primary.main,
              colorBackground: theme.palette.background.paper,
              colorText: theme.palette.text.primary,
              colorDanger: theme.palette.error.main,
            },
          },
        }}
        stripe={stripePromise}>
        <StripeCheckoutForm
          clientSecret={clientSecret}
          intentType={intentType}
          mode={mode}
          customer={customer}
          onConfirm={onConfirm}
          onSkip={onSkip}
          returnUrl={returnUrl}
          submitButtonText={submitButtonText}
        />
      </Elements>
    </Dialog>
  );
}
