/* eslint-disable jsx-a11y/anchor-is-valid */
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import Toast from '@arcblock/ux/lib/Toast';
import {
  Status,
  TxGas,
  TxLink,
  api,
  formatAmount,
  formatError,
  formatTime,
  getInvoiceDescriptionAndReason,
  getInvoiceStatusColor,
  getPrefix,
  usePaymentContext,
  PaymentBeneficiaries,
  useMobile,
  StripePaymentAction,
} from '@blocklet/payment-react';
import type { TCheckoutSession, TCreditGrantExpanded, TInvoiceExpanded, TPaymentLink } from '@blocklet/payment-types';
import { ArrowBackOutlined } from '@mui/icons-material';
import { Alert, Box, Button, CircularProgress, Divider, Stack, Tooltip, Typography, useTheme } from '@mui/material';
import { styled } from '@mui/system';
import { useRequest, useSetState } from 'ahooks';
import { useEffect } from 'react';
import { Link, useParams, useSearchParams } from 'react-router-dom';

import { joinURL } from 'ufo';
import { isEmpty } from 'lodash';
import { useSessionContext } from '../../../contexts/session';
import Currency from '../../../components/currency';
import CustomerLink from '../../../components/customer/link';
import InfoRow from '../../../components/info-row';
import { Download } from '../../../components/invoice-pdf/pdf';
import InvoiceTable from '../../../components/invoice/table';
import { goBackOrFallback } from '../../../libs/util';
import CustomerRefundList from '../refund/list';
import InfoMetric from '../../../components/info-metric';
import InfoRowGroup from '../../../components/info-row-group';
import RelatedCreditGrants from '../../../components/customer/related-credit-grants';
import { useArcsphere } from '../../../hooks/browser';

const fetchData = (
  id: string
): Promise<
  TInvoiceExpanded & {
    relatedInvoice?: TInvoiceExpanded;
    checkoutSession: TCheckoutSession;
    paymentLink: TPaymentLink;
    relatedCreditGrants?: TCreditGrantExpanded[];
  }
> => {
  return api.get(`/api/invoices/${id}`).then((res: any) => res.data);
};

export default function CustomerInvoiceDetail() {
  const { t, locale } = useLocaleContext();
  const [searchParams] = useSearchParams();
  const { isMobile } = useMobile();
  const { connect } = usePaymentContext();
  const params = useParams<{ id: string }>();
  const muiTheme = useTheme();
  const inArcsphere = useArcsphere();
  const [state, setState] = useSetState({
    downloading: false,
    paying: false,
  });

  const { loading, error, data, runAsync } = useRequest(() => fetchData(params.id as string));

  const action = searchParams.get('action');
  const { session } = useSessionContext();
  const isDonation = data?.checkoutSession?.submit_type === 'donate';

  const handleExternalPayment = () => {
    setState({ paying: true });

    connect.open({
      action: 'collect',
      saveConnect: false,
      locale: locale as 'en' | 'zh',
      extraParams: { invoiceId: params.id, action, allowCreatePI: data?.status === 'uncollectible' },
      messages: {
        scan: '',
        title: t(`payment.customer.invoice.${action || 'pay'}`),
        success: t(`payment.customer.invoice.${action || 'pay'}Success`),
        error: t(`payment.customer.invoice.${action || 'pay'}Error`),
        confirm: '',
      } as any,
      onSuccess: async () => {
        connect.close();
        setState({ paying: false });
        await runAsync();
      },
      onClose: () => {
        connect.close();
        setState({ paying: false });
      },
      onError: (err: any) => {
        setState({ paying: false });
        Toast.error(formatError(err));
      },
    });
  };

  const closePay = () => {
    setState({ paying: true });
    connect.close();
  };

  useEffect(() => {
    // @ts-expect-error
    if (error?.response?.status === 403) {
      closePay();
    } else if (
      ['pay', 'renew'].includes(action as string) &&
      ['open', 'uncollectible'].includes(data?.status as string)
    ) {
      handleExternalPayment();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [error]);

  if (data?.customer?.did && session?.user?.did && data.customer.did !== session.user.did) {
    return <Alert severity="error">{t('common.accessDenied')}</Alert>;
  }

  if (error) {
    return <Alert severity="error">{formatError(error)}</Alert>;
  }

  if (loading || !data) {
    return <CircularProgress />;
  }

  const isStake =
    data.paymentMethod?.type === 'arcblock' && ['stake', 'stake_overdraft_protection'].includes(data.billing_reason);
  const isSlashStake = data.paymentMethod?.type === 'arcblock' && data.billing_reason.includes('slash_stake');

  const hidePayButton = data.billing_reason === 'overdraft_protection';
  const paymentDetails = data.paymentIntent?.payment_details || data.metadata?.payment_details;

  const showDownloadButton =
    ['open', 'paid', 'uncollectible'].includes(data.status) && !isDonation && !isEmpty(data.lines);
  return (
    <InvoiceDetailRoot direction="column" spacing={3}>
      <Stack
        direction="row"
        sx={{
          justifyContent: 'space-between',
        }}>
        {!inArcsphere ? (
          <Stack
            direction="row"
            onClick={() => goBackOrFallback('/customer')}
            sx={{
              alignItems: 'center',
              fontWeight: 'normal',
              padding: '10px 0',
              cursor: 'pointer',
            }}>
            <ArrowBackOutlined fontSize="small" sx={{ mr: 0.5, color: 'text.secondary' }} />
            <Typography variant="h6" sx={{ color: 'text.secondary', fontWeight: 'normal' }}>
              {t('common.previous')}
            </Typography>
          </Stack>
        ) : (
          <Box />
        )}
        <Stack
          direction="row"
          spacing={1}
          sx={{
            justifyContent: 'flex-end',
            alignItems: 'center',
          }}>
          {showDownloadButton && <Download data={data} />}
          {data?.paymentLink?.donation_settings?.reference && (
            <Button
              variant="outlined"
              onClick={() => {
                window.open(data?.paymentLink?.donation_settings?.reference, '_blank');
              }}>
              {t('customer.payout.viewReference')}
            </Button>
          )}
          {['open', 'uncollectible'].includes(data.status) &&
            !hidePayButton &&
            (data.paymentMethod?.type === 'stripe' ? (
              <StripePaymentAction
                invoice={data}
                paymentMethod={data.paymentMethod}
                onSuccess={async () => {
                  Toast.close();
                  setState({ paying: false });
                  await runAsync();
                }}
                onError={() => {
                  setState({ paying: false });
                }}
                onClose={() => {
                  setState({ paying: false });
                }}>
                {(onPay: () => void, paying: boolean) => {
                  return (
                    <Button
                      variant="outlined"
                      color="primary"
                      size="small"
                      sx={{ borderColor: 'divider' }}
                      disabled={state.paying || paying}
                      onClick={() => {
                        setState({ paying: true });
                        onPay();
                      }}>
                      {t('payment.customer.invoice.pay')}
                    </Button>
                  );
                }}
              </StripePaymentAction>
            ) : (
              <Button
                variant="outlined"
                color="primary"
                size="small"
                sx={{ borderColor: 'divider' }}
                disabled={state.paying}
                onClick={handleExternalPayment}>
                {t('payment.customer.invoice.pay')}
              </Button>
            ))}
        </Stack>
      </Stack>
      {data.status === 'uncollectible' && data.metadata?.slippage?.below_threshold && (
        <Alert severity="warning" sx={{ mt: 2 }}>
          <Typography variant="body2">
            {t('payment.customer.invoice.slippageExceededDetail', {
              currentRate: data.metadata.slippage.rate_at_invoice || '—',
              minRate: data.metadata.slippage.min_acceptable_rate || '—',
            })}
          </Typography>
        </Alert>
      )}
      <Box
        sx={{
          mt: isMobile ? '0 !important' : 4,
          display: 'flex',
          border: isMobile ? `1px solid ${muiTheme.palette.divider}` : 'none',
          borderRadius: isMobile ? 1 : 0,
          p: isMobile ? 2 : 0,

          gap: {
            xs: 2,
            sm: 2,
            md: 5,
          },

          flexWrap: 'wrap',

          flexDirection: {
            xs: 'column',
            sm: 'column',
            md: 'row',
          },

          alignItems: {
            xs: 'flex-start',
            sm: 'flex-start',
            md: 'center',
          },
        }}>
        <Stack
          direction="row"
          sx={{
            justifyContent: 'space-between',
            alignItems: 'center',
          }}>
          <Stack
            direction="row"
            sx={{
              alignItems: 'center',
              flexWrap: 'wrap',
              gap: 1,
            }}>
            <Typography variant="h1">{data.number}</Typography>
          </Stack>
        </Stack>
        <Stack
          className="section-body"
          sx={{
            justifyContent: 'flex-start',
            flexWrap: 'wrap',

            'hr.MuiDivider-root:last-child': {
              display: 'none',
            },
            '.info-metric-label': {
              mb: isMobile ? 0.5 : 1,
            },

            flexDirection: {
              xs: 'column',
              sm: 'column',
              md: 'row',
            },

            alignItems: {
              xs: 'flex-start',
              sm: 'flex-start',
              md: 'center',
            },

            gap: {
              xs: 1,
              sm: 1,
              md: 3,
            },
          }}>
          <InfoMetric
            label={t('common.status')}
            value={
              <Stack direction="row" spacing={1} alignItems="center">
                <Tooltip
                  title={data.status === 'void' ? t('payment.customer.invoice.noPaymentRequired') : ''}
                  arrow
                  placement="top">
                  <span>
                    <Status label={data.status} color={getInvoiceStatusColor(data.status)} />
                  </span>
                </Tooltip>
                {data.status === 'uncollectible' && data.metadata?.slippage?.below_threshold && (
                  <Tooltip
                    title={t('payment.customer.invoice.slippageExceededDetail', {
                      currentRate: data.metadata.slippage.rate_at_invoice || '—',
                      minRate: data.metadata.slippage.min_acceptable_rate || '—',
                    })}
                    arrow
                    placement="top">
                    <span>
                      <Status label={t('payment.customer.invoice.slippageExceeded')} color="warning" />
                    </span>
                  </Tooltip>
                )}
              </Stack>
            }
            divider
          />
          {data.subscription && (
            <InfoMetric
              label={t('admin.subscription.name')}
              value={
                <Link to={`/customer/subscription/${data.subscription.id}`}>
                  <Typography
                    variant="body1"
                    sx={{
                      color: 'text.link',
                    }}>
                    {data.subscription.description || data.subscription.id}
                  </Typography>
                </Link>
              }
              divider
            />
          )}
          <InfoMetric label={t('common.createdAt')} value={formatTime(data.created_at)} divider />
          {data.period_start > 0 && data.period_end > 0 && (
            <InfoMetric
              label={t('admin.subscription.currentPeriod')}
              value={[formatTime(data.period_start * 1000), formatTime(data.period_end * 1000)].join(' ~ ')}
              divider
            />
          )}
        </Stack>
      </Box>
      <Divider />
      <Box
        className="section"
        sx={{
          containerType: 'inline-size',
          border: isMobile ? (theme) => `1px solid ${theme.palette.divider}` : 'none',
          borderRadius: isMobile ? 1 : 0,
          p: isMobile ? 2 : 0,
        }}>
        <Typography
          variant="h3"
          className="section-header"
          sx={{
            mb: 3,
          }}>
          {t('payment.customer.invoice.details')}
        </Typography>
        <InfoRowGroup
          sx={{
            display: 'grid',
            columnGap: 16,
            gridTemplateColumns: {
              xs: 'repeat(1, 1fr)',
              lg: 'repeat(2, 1fr)',
            },
            '@container (min-width: 980px)': {
              gridTemplateColumns: 'repeat(2, 1fr)',
            },
            '.info-row-wrapper': {
              gap: isMobile ? 0.5 : 1,
              flexDirection: {
                xs: 'column',
                lg: 'row',
              },
              alignItems: {
                xs: 'flex-start',
                lg: 'center',
              },
              '@container (min-width: 980px)': {
                flexDirection: 'row',
                alignItems: 'center',
              },
            },
            '.currency-name': {
              color: 'text.secondary',
              fontSize: 14,
              lineHeight: 1,
            },
            '.tx-link-text': {
              fontSize: 14,
              lineHeight: 1,
            },
          }}>
          <InfoRow
            label={t('admin.invoice.billTo')}
            value={<CustomerLink customer={data.customer} linked={false} size="small" />}
          />
          <InfoRow label={t('admin.invoice.from')} value={data.statement_descriptor || blocklet.appName} />
          <InfoRow
            label={t('admin.invoice.description')}
            value={getInvoiceDescriptionAndReason(data, locale)?.description}
          />
          {data.status_transitions?.paid_at && (
            <InfoRow label={t('admin.invoice.paidAt')} value={formatTime(data.status_transitions.paid_at * 1000)} />
          )}
          <InfoRow
            label={t('admin.paymentCurrency.name')}
            value={
              <Currency
                logo={data.paymentCurrency.logo}
                name={`${data.paymentCurrency.symbol} (${data.paymentMethod.name})`}
              />
            }
          />
          {(isStake || isSlashStake) && (
            <InfoRow
              label={isSlashStake ? t('common.slashStakeAmount') : t('common.stakeAmount')}
              value={`${formatAmount(data.total, data.paymentCurrency.decimal)} ${data.paymentCurrency.symbol}`}
            />
          )}
          {(!!data.paymentIntent?.payment_details?.ethereum || !!data.paymentIntent?.payment_details?.base) && (
            <InfoRow
              label={t('common.txGas')}
              value={<TxGas details={data.paymentIntent.payment_details as any} method={data.paymentMethod} />}
            />
          )}
          {paymentDetails && (
            <InfoRow
              label={
                isStake ? t('common.stakeTxHash') : t(`common.${paymentDetails?.arcblock?.type || 'transfer'}TxHash`)
              }
              value={<TxLink details={paymentDetails} method={data.paymentMethod} mode="customer" />}
            />
          )}
          {data?.relatedInvoice && (
            <InfoRow
              label={t('customer.invoice.relatedInvoice')}
              value={
                <Typography
                  variant="body1"
                  component="a"
                  onClick={() => {
                    window.open(joinURL(getPrefix(), `/customer/invoice/${data.relatedInvoice?.id}`), '_self');
                  }}
                  sx={{
                    color: 'text.link',
                    cursor: 'pointer',
                  }}>
                  {data.relatedInvoice?.number}
                </Typography>
              }
            />
          )}
        </InfoRowGroup>
      </Box>
      {isDonation && !isEmpty(data.paymentIntent?.beneficiaries) && (
        <>
          <Divider />
          <Box className="section">
            <Typography variant="h3" className="section-header">
              {t('customer.invoice.donation')}
            </Typography>
          </Box>
          <Box sx={{ maxWidth: 800 }}>
            <PaymentBeneficiaries
              data={data?.paymentIntent?.beneficiaries as any}
              currency={data.paymentCurrency}
              totalAmount={data?.amount_paid}
            />
          </Box>
        </>
      )}
      {data?.relatedCreditGrants && data.relatedCreditGrants.length > 0 && (
        <RelatedCreditGrants grants={data.relatedCreditGrants} />
      )}
      {!isSlashStake && !isDonation && (
        <>
          {!isStake && (
            <>
              <Divider />
              <Box className="section">
                <Typography
                  variant="h3"
                  className="section-header"
                  sx={{
                    mb: 1.5,
                  }}>
                  {t('admin.invoiceItems')}
                </Typography>
                <InvoiceTable invoice={data} simple />
              </Box>
            </>
          )}
          <Divider />
          <Box className="section">
            <Typography variant="h3" className="section-header">
              {t('admin.refunds')}
            </Typography>
            <Box className="section-body">
              <CustomerRefundList invoice_id={data.id} type="table" />
            </Box>
          </Box>
        </>
      )}
    </InvoiceDetailRoot>
  );
}

const InvoiceDetailRoot = styled(Stack)`
  .invoice-summary-wrapper {
    display: 'grid';
    grid-template-columns: '50% 50%';
  }
  @media (max-width: ${({ theme }) => theme.breakpoints.values.md}px) {
    .section-header {
      font-size: 18px;
    }
  }
`;
