/* eslint-disable @typescript-eslint/indent */
/* eslint-disable no-nested-ternary */
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import Toast from '@arcblock/ux/lib/Toast';
// eslint-disable-next-line import/no-extraneous-dependencies
import Header from '@blocklet/ui-react/lib/Header';
import type { TCustomer, TLineItemExpanded, TPaymentCurrency, TPaymentMethodExpanded } from '@blocklet/payment-types';
import { ArrowBackOutlined, ArrowForwardOutlined, HelpOutlineOutlined } from '@mui/icons-material';
import { Box, Button, Divider, Stack, Typography, type BoxProps } from '@mui/material';
import { styled } from '@mui/system';
import { fromTokenToUnit } from '@ocap/util';
import { useMount, useRequest, useSetState } from 'ahooks';
import { useEffect, useState } from 'react';
import { FormProvider, useForm, useWatch } from 'react-hook-form';
import type { LiteralUnion } from 'type-fest';

import { joinURL } from 'ufo';
import { usePaymentContext } from '../contexts/payment';
import api from '../libs/api';
import {
  findCurrency,
  formatError,
  getPrefix,
  getQueryParams,
  getStatementDescriptor,
  isMobileSafari,
  isValidCountry,
} from '../libs/util';
import type { CheckoutCallbacks, CheckoutContext, CheckoutFormData } from '../types';
import PaymentError from './error';
import PaymentForm from './form';
// import PaymentHeader from './header';
import PaymentSuccess from './success';
import { useMobile } from '../hooks/mobile';
import ProductDonation from './product-donation';
import ConfirmDialog from '../components/confirm';
import PaymentBeneficiaries, { TBeneficiary } from '../components/payment-beneficiaries';
import DonationSkeleton from './skeleton/donation';
import { formatPhone } from '../libs/phone-validator';

const getBenefits = async (id: string, url?: string) => {
  const { data } = await api.get(`/api/payment-links/${id}/benefits?${url ? `url=${url}` : ''}`);
  return data;
};
// eslint-disable-next-line react/no-unused-prop-types
type Props = CheckoutContext &
  CheckoutCallbacks & {
    completed?: boolean;
    error?: any;
    showCheckoutSummary?: boolean;
    formRender?: Record<string, any>;
    id: string;
  };

function PaymentInner({
  checkoutSession,
  paymentMethods,
  paymentLink,
  paymentIntent,
  customer,
  completed = false,
  mode,
  onPaid,
  onError,
  onChange,
  action,
  formRender = {},
  benefits,
}: MainProps) {
  const { t } = useLocaleContext();
  const { settings, session } = usePaymentContext();
  const { isMobile } = useMobile();
  const [state, setState] = useSetState({
    checkoutSession,
    submitting: false,
    paying: false,
    paid: false,
    paymentIntent,
    stripeContext: undefined,
    customer,
    customerLimited: false,
    stripePaying: false,
  });
  const query = getQueryParams(window.location.href);
  const defaultCurrencyId =
    query.currencyId || state.checkoutSession.currency_id || state.checkoutSession.line_items[0]?.price.currency_id;
  const defaultMethodId = paymentMethods.find((m) => m.payment_currencies.some((c) => c.id === defaultCurrencyId))?.id;

  const items = state.checkoutSession.line_items;
  const donationSettings = paymentLink?.donation_settings;

  const [benefitsState, setBenefitsState] = useSetState({
    open: false,
    amount: '0',
  });
  const methods = useForm<CheckoutFormData>({
    defaultValues: {
      customer_name: customer?.name || session?.user?.fullName || '',
      customer_email: customer?.email || session?.user?.email || '',
      customer_phone: formatPhone(customer?.phone || session?.user?.phone || ''),
      payment_method: defaultMethodId,
      payment_currency: defaultCurrencyId,
      billing_address: Object.assign(
        {
          country: session?.user?.address?.country || '',
          state: session?.user?.address?.province || '',
          city: session?.user?.address?.city || '',
          line1: session?.user?.address?.line1 || '',
          line2: session?.user?.address?.line2 || '',
          postal_code: session?.user?.address?.postalCode || '',
        },
        customer?.address || {},
        {
          country: isValidCountry(customer?.address?.country || session?.user?.address?.country || '')
            ? customer?.address?.country
            : 'us',
        }
      ),
    },
  });

  useEffect(() => {
    if (!isMobileSafari()) {
      return () => {};
    }
    let scrollTop = 0;
    const focusinHandler = () => {
      scrollTop = window.scrollY;
    };
    const focusoutHandler = () => {
      window.scrollTo(0, scrollTop);
    };
    document.body.addEventListener('focusin', focusinHandler);
    document.body.addEventListener('focusout', focusoutHandler);
    return () => {
      document.body.removeEventListener('focusin', focusinHandler);
      document.body.removeEventListener('focusout', focusoutHandler);
    };
  }, []);

  useEffect(() => {
    if (!methods || query.currencyId) {
      return;
    }
    if (state.checkoutSession.currency_id !== defaultCurrencyId) {
      methods.setValue('payment_currency', state.checkoutSession.currency_id);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [state.checkoutSession, defaultCurrencyId, query.currencyId]);

  const currencyId = useWatch({ control: methods.control, name: 'payment_currency', defaultValue: defaultCurrencyId });
  const currency =
    (findCurrency(paymentMethods as TPaymentMethodExpanded[], currencyId as string) as TPaymentCurrency) ||
    settings.baseCurrency;

  useEffect(() => {
    if (onChange) {
      onChange(methods.getValues());
    }
  }, [currencyId]); // eslint-disable-line

  const onChangeAmount = async ({ priceId, amount }: { priceId: string; amount: string }) => {
    const amountStr = fromTokenToUnit(amount, currency.decimal).toString();
    setBenefitsState({ amount: amountStr });
    try {
      const { data } = await api.put(`/api/checkout-sessions/${state.checkoutSession.id}/amount`, {
        priceId,
        amount: amountStr,
      });
      setState({ checkoutSession: data });
    } catch (err) {
      console.error(err);
      Toast.error(formatError(err));
    }
  };

  const handlePaid = (result: any) => {
    setState({ checkoutSession: result.checkoutSession });
    onPaid(result);
  };

  const renderBenefits = () => {
    if (!benefits) {
      return null;
    }
    if (benefits.length === 1) {
      return t('payment.checkout.donation.benefits.one', {
        name: benefits[0].name,
      });
    }
    return t('payment.checkout.donation.benefits.multiple', {
      count: benefits.length,
    });
  };

  return (
    <FormProvider {...methods}>
      <Stack className="cko-container" sx={{ gap: { sm: mode === 'standalone' ? 0 : mode === 'inline' ? 4 : 8 } }}>
        {completed ? (
          <Stack>
            <PaymentSuccess
              mode={mode}
              payee={getStatementDescriptor(state.checkoutSession.line_items)}
              action={state.checkoutSession.mode}
              invoiceId={state.checkoutSession.invoice_id}
              subscriptionId={state.checkoutSession.subscription_id}
              message={
                paymentLink?.after_completion?.hosted_confirmation?.custom_message ||
                t('payment.checkout.completed.donate')
              }
            />
            <Divider
              sx={{
                mt: {
                  xs: '16px',
                  md: '-24px',
                },
                mb: {
                  xs: '16px',
                  md: '16px',
                },
              }}
            />
            <Stack
              direction="row"
              sx={{
                justifyContent: 'flex-end',
                alignItems: 'center',
                flexWrap: 'wrap',
                gap: 1,
              }}>
              <Button
                variant="outlined"
                size="large"
                onClick={formRender?.onCancel}
                sx={{ width: 'fit-content', minWidth: 120 }}>
                {t('common.close')}
              </Button>
            </Stack>
          </Stack>
        ) : (
          <>
            {benefitsState.open && (
              <PaymentBeneficiaries data={benefits} currency={currency} totalAmount={benefitsState.amount} />
            )}

            <Stack sx={{ display: benefitsState.open ? 'none' : 'block' }}>
              <Stack
                direction="row"
                sx={{
                  justifyContent: 'space-between',
                  alignItems: 'center',
                  mb: 2,
                }}>
                <Typography
                  title={t('payment.checkout.orderSummary')}
                  sx={{
                    color: 'text.primary',
                    fontSize: '18px',
                    fontWeight: '500',
                    lineHeight: '24px',
                  }}>
                  {t('payment.checkout.donation.tipAmount')}
                </Typography>

                {!isMobile && donationSettings?.amount?.presets && donationSettings.amount.presets.length > 0 && (
                  <Typography
                    sx={{
                      color: 'text.secondary',
                      fontSize: '13px',
                      display: 'flex',
                      alignItems: 'center',
                      gap: 0.5,
                      opacity: 0.8,
                    }}>
                    <Box
                      component="span"
                      sx={{
                        border: '1px solid',
                        borderColor: 'divider',
                        borderRadius: 0.75,
                        px: 0.75,
                        py: 0.25,
                        fontSize: '12px',
                        lineHeight: 1,
                        color: 'text.secondary',
                        fontWeight: '400',
                        bgcolor: 'transparent',
                      }}>
                      Tab
                    </Box>
                    {t('payment.checkout.donation.tabHint')}
                  </Typography>
                )}
              </Stack>

              {items.map((x: TLineItemExpanded) => (
                <ProductDonation
                  key={`${x.price_id}-${currency.id}`}
                  item={x}
                  // @ts-ignore
                  settings={donationSettings}
                  onChange={onChangeAmount}
                  currency={currency}
                />
              ))}
            </Stack>

            <Divider
              sx={{
                mt: {
                  xs: '32px',
                  md: '0',
                },
                mb: {
                  xs: '16px',
                  md: '-8px',
                },
              }}
            />
            <Stack
              direction="row"
              sx={{
                justifyContent: 'space-between',
                alignItems: 'center',
                flexWrap: 'wrap',
                gap: 1,
              }}>
              {benefits &&
                benefits.length > 0 &&
                (benefitsState.open ? (
                  <Typography
                    onClick={() => setBenefitsState({ open: false })}
                    sx={{
                      cursor: 'pointer',
                      color: 'text.secondary',
                      '&:hover': {
                        color: 'text.primary',
                      },
                      display: 'flex',
                      alignItems: 'center',
                    }}>
                    <ArrowBackOutlined className="benefits-arrow" sx={{ fontSize: '18px', mr: 0.5 }} />
                    {t('common.back')}
                  </Typography>
                ) : (
                  <Box
                    onClick={() => setBenefitsState({ open: true })}
                    sx={{
                      display: 'flex',
                      gap: 0.5,
                      alignItems: 'center',
                      color: 'text.secondary',
                      cursor: 'pointer',

                      '& .benefits-arrow': {
                        opacity: 0,
                        transform: 'translateX(-4px)',
                        transition: 'all 0.2s',
                      },

                      '&:hover': {
                        color: 'text.primary',
                        '& .benefits-arrow': {
                          opacity: 1,
                          transform: 'translateX(0)',
                        },
                      },
                    }}>
                    <HelpOutlineOutlined sx={{ fontSize: '18px' }} />
                    <Typography variant="body2">{renderBenefits()}</Typography>
                    <ArrowForwardOutlined className="benefits-arrow" sx={{ fontSize: '18px' }} />
                  </Box>
                ))}
              {benefitsState.open ? null : (
                <Box
                  sx={{
                    display: 'flex',
                    gap: 2,

                    flex: {
                      xs: 1,
                      md: 'auto',
                    },

                    justifyContent: 'flex-end',
                    whiteSpace: 'nowrap',
                  }}>
                  {formRender?.cancel}
                  <PaymentForm
                    currencyId={currencyId}
                    checkoutSession={state.checkoutSession}
                    paymentMethods={paymentMethods as TPaymentMethodExpanded[]}
                    paymentIntent={paymentIntent}
                    paymentLink={paymentLink}
                    customer={customer}
                    onPaid={handlePaid}
                    onError={onError}
                    mode={mode}
                    action={action}
                    onlyShowBtn
                    isDonation
                  />
                </Box>
              )}
            </Stack>
          </>
        )}
        {state.customerLimited && (
          <ConfirmDialog
            onConfirm={() =>
              window.open(
                joinURL(getPrefix(), `/customer/invoice/past-due?referer=${encodeURIComponent(window.location.href)}`),
                '_self'
              )
            }
            onCancel={() => setState({ customerLimited: false })}
            confirm={t('payment.customer.pastDue.alert.confirm')}
            title={t('payment.customer.pastDue.alert.title')}
            message={t('payment.customer.pastDue.alert.description')}
            color="primary"
          />
        )}
      </Stack>
    </FormProvider>
  );
}

export default function DonationForm({
  checkoutSession,
  paymentMethods,
  paymentIntent,
  paymentLink,
  customer,
  completed = false,
  error = null,
  mode,
  onPaid,
  onError,
  onChange,
  goBack,
  action,
  showCheckoutSummary = true,
  formRender = {},
  id,
}: Props) {
  const { t } = useLocaleContext();
  const { refresh, livemode, setLivemode } = usePaymentContext();
  const { isMobile } = useMobile();
  const [delay, setDelay] = useState(false);
  const isMobileSafariEnv = isMobileSafari();
  const paymentLinkId = id.startsWith('plink_') ? id : undefined;

  const { data: benefits, loading: benefitLoading } = useRequest(
    () => {
      if (paymentLinkId) {
        return getBenefits(paymentLinkId);
      }
      return Promise.resolve([]);
    },
    {
      refreshDeps: [paymentLinkId || paymentLink?.id],
      ready: !!paymentLinkId || !!paymentLink?.id,
    }
  );

  useMount(() => {
    setTimeout(() => {
      // 骨架屏 delay
      setDelay(true);
    }, 500);
    // eslint-di
  });

  useEffect(() => {
    if (checkoutSession) {
      if (livemode !== checkoutSession.livemode) {
        setLivemode(checkoutSession.livemode);
      }
    }
  }, [checkoutSession, livemode, setLivemode, refresh]);

  const renderContent = () => {
    const footer = (
      <>
        <Divider sx={{ mt: { xs: '16px', md: '-24px' }, mb: { xs: '16px', md: '-16px' } }} />
        <Stack
          direction="row"
          sx={{
            justifyContent: 'flex-end',
            alignItems: 'center',
            flexWrap: 'wrap',
            gap: 1,
          }}>
          <Button variant="outlined" size="large" onClick={formRender?.onCancel}>
            {t('common.cancel')}
          </Button>
        </Stack>
      </>
    );
    if (error) {
      return (
        <>
          <PaymentError mode={mode} title="Oops" description={formatError(error)} button={null} />
          {footer}
        </>
      );
    }
    if (!checkoutSession || !delay || !paymentLink || benefitLoading) {
      return <DonationSkeleton />;
    }
    if (checkoutSession?.expires_at <= Math.round(Date.now() / 1000)) {
      return (
        <>
          <PaymentError
            mode={mode}
            title={t('payment.checkout.expired.title')}
            description={t('payment.checkout.expired.description')}
            button={null}
          />
          {footer}
        </>
      );
    }
    if (!checkoutSession.line_items.length) {
      return (
        <>
          <PaymentError
            mode={mode}
            title={t('payment.checkout.emptyItems.title')}
            description={t('payment.checkout.emptyItems.description')}
            button={null}
          />
          {footer}
        </>
      );
    }
    return (
      <PaymentInner
        formRender={formRender}
        checkoutSession={checkoutSession}
        paymentMethods={paymentMethods as TPaymentMethodExpanded[]}
        paymentLink={paymentLink}
        paymentIntent={paymentIntent}
        completed={completed || checkoutSession.status === 'complete'}
        customer={customer as TCustomer}
        onPaid={onPaid}
        onError={onError}
        onChange={onChange}
        goBack={goBack}
        mode={mode}
        action={action}
        showCheckoutSummary={showCheckoutSummary}
        benefits={benefits}
      />
    );
  };

  return (
    <Stack
      sx={{
        display: 'flex',
        flexDirection: 'column',
        height: mode === 'standalone' ? '100vh' : 'auto',
        overflow: isMobileSafariEnv ? 'visible' : 'hidden',
      }}>
      {mode === 'standalone' ? (
        <Header
          meta={undefined}
          addons={undefined}
          sessionManagerProps={undefined}
          homeLink={undefined}
          theme={undefined}
          hideNavMenu={undefined}
          maxWidth={false}
          sx={{ borderBottom: '1px solid', borderColor: 'grey.100' }}
        />
      ) : null}
      <Root
        mode={mode}
        sx={{
          flex: 1,
          overflow: {
            xs: isMobileSafariEnv ? 'visible' : 'auto',
            md: 'hidden',
          },
          ...(isMobile && mode === 'standalone'
            ? {
                '.cko-payment-submit-btn': {
                  position: 'fixed',
                  bottom: 20,
                  left: 0,
                  right: 0,
                  zIndex: 999,
                  backgroundColor: 'background.paper',
                  padding: '10px',
                  textAlign: 'center',
                  button: {
                    maxWidth: 542,
                  },
                },
              }
            : {}),
        }}>
        {goBack && (
          <ArrowBackOutlined
            sx={{ mr: 0.5, color: 'text.secondary', alignSelf: 'flex-start', margin: '16px 0', cursor: 'pointer' }}
            onClick={goBack}
            fontSize="medium"
          />
        )}
        <Stack className="cko-container" sx={{ gap: { sm: mode === 'standalone' ? 0 : mode === 'inline' ? 4 : 8 } }}>
          {renderContent()}
        </Stack>
      </Root>
    </Stack>
  );
}

type MainProps = CheckoutContext &
  CheckoutCallbacks & {
    completed?: boolean;
    showCheckoutSummary?: boolean;
    formRender?: Record<string, any>;
    benefits: TBeneficiary[];
  };

type RootProps = { mode: LiteralUnion<'standalone' | 'inline' | 'popup', string> } & BoxProps;
export const Root: React.FC<RootProps> = styled(Box)<RootProps>`
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  overflow: hidden;
  position: relative;

  .cko-container {
    overflow: hidden;
    width: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    position: relative;
    flex: 1;
  }

  .cko-overview {
    position: relative;
    flex-direction: column;
    display: ${(props) => (props.mode.endsWith('-minimal') ? 'none' : 'flex')};
    background: ${({ theme }) => theme.palette.background.default};
    min-height: 'auto';
  }

  .cko-footer {
    display: ${(props) => (props.mode.endsWith('-minimal') ? 'none' : 'block')};
    text-align: center;
    margin-top: 20px;
  }

  .cko-payment-form {
    .MuiFormLabel-root {
      color: ${({ theme }) => theme.palette.grey.A700};
      font-weight: 500;
      margin-top: 12px;
      margin-bottom: 4px;
    }
    .MuiBox-root {
      margin: 0;
    }
    .MuiFormHelperText-root {
      margin-left: 14px;
    }
  }

  @media (max-width: ${({ theme }) => theme.breakpoints.values.md}px) {
    padding-top: 0;
    overflow: auto;

    .cko-container {
      flex-direction: column;
      justify-content: flex-start;
      gap: 0;
      overflow: visible;
      min-width: 200px;
    }

    .cko-overview {
      width: 100%;
      min-height: auto;
      flex: none;
    }

    .cko-footer {
      position: relative;
      margin-bottom: 4px;
      margin-top: 0;
      bottom: 0;
      left: 0;
      transform: translateX(0);
    }
  }
`;
