/* eslint-disable @typescript-eslint/indent */
/* eslint-disable react/require-default-props */
/* eslint-disable react/no-unused-prop-types */
/* eslint-disable @typescript-eslint/naming-convention */
/* eslint-disable no-nested-ternary */
/* eslint-disable react/no-unstable-nested-components */
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import Toast from '@arcblock/ux/lib/Toast';
import type { Paginated, TInvoiceExpanded, TSubscription } from '@blocklet/payment-types';
import { OpenInNewOutlined } from '@mui/icons-material';
import { Box, Button, CircularProgress, Stack, Typography, Tooltip, Avatar } from '@mui/material';
import { styled } from '@mui/system';
import { useInfiniteScroll, useRequest, useSetState } from 'ahooks';
import React, { useEffect, useRef, useState } from 'react';
// eslint-disable-next-line import/no-extraneous-dependencies
import { useNavigate } from 'react-router-dom';

import debounce from 'lodash/debounce';
import { BN } from '@ocap/util';
import Status from '../../components/status';
import { usePaymentContext } from '../../contexts/payment';
import { useSubscription } from '../../hooks/subscription';
import api from '../../libs/api';
import StripePaymentAction from '../../components/stripe-payment-action';
import {
  formatCreditAmount,
  formatError,
  formatToDate,
  formatToDatetime,
  formatTime,
  formatExchangeRate,
  getInvoiceDescriptionAndReason,
  getInvoiceStatusColor,
  getTxLink,
  isCrossOrigin,
  getUsdAmountFromTokenUnits,
  formatUsdAmount,
  formatAmount,
} from '../../libs/util';
import Table from '../../components/table';
import { createLink, handleNavigation, LinkInfo } from '../../libs/navigation';

type Result = Paginated<TInvoiceExpanded> & { subscription: TSubscription };

const groupByDate = (items: TInvoiceExpanded[]) => {
  const grouped: { [key: string]: TInvoiceExpanded[] } = {};
  items.forEach((item) => {
    const date = new Date(item.created_at).toLocaleDateString();
    if (!grouped[date]) {
      grouped[date] = [];
    }
    grouped[date]?.push(item);
  });
  return grouped;
};

const fetchData = (params: Record<string, any> = {}): Promise<Result> => {
  const search = new URLSearchParams();
  const mergedParams: Record<string, any> = { include_quote: true, ...params };
  Object.keys(mergedParams).forEach((key) => {
    if (mergedParams[key]) {
      search.set(key, String(mergedParams[key]));
    }
  });
  return api.get(`/api/invoices?${search.toString()}`).then((res: any) => res.data);
};

const getInvoiceQuoteInfo = (invoice: TInvoiceExpanded) => {
  const lines = (invoice as any).lines || [];
  for (const line of lines) {
    const quote = (line.metadata as any)?.quote;
    if (quote?.exchange_rate) {
      return quote;
    }
  }
  return null;
};

type Props = {
  customer_id?: string;
  subscription_id?: string;
  currency_id?: string;
  include_staking?: boolean;
  include_return_staking?: boolean;
  include_recovered_from?: boolean;
  status?: string;
  pageSize?: number;
  target?: string;
  action?: string;
  type?: 'list' | 'table';
  onTableDataChange?: Function;
  relatedSubscription?: boolean;
};

const getInvoiceLink = (invoice: TInvoiceExpanded, action?: string) => {
  if (invoice.id.startsWith('in_')) {
    const path = `/customer/invoice/${invoice.id}${invoice.status === 'uncollectible' && action ? `?action=${action}` : ''}`;
    return {
      connect: invoice.status === 'uncollectible',
      link: createLink(path),
    };
  }

  return {
    connect: false,
    link: createLink(getTxLink(invoice.paymentMethod, invoice.metadata?.payment_details).link, true),
  };
};

const linkStyle = {
  cursor: 'pointer',
};

const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) => void }) => {
  const {
    pageSize,
    target,
    action,
    onPay,
    status,
    customer_id,
    currency_id,
    subscription_id,
    include_staking,
    include_return_staking,
    include_recovered_from,
    onTableDataChange,
    relatedSubscription,
  } = props;
  const listKey = 'invoice-table';
  const { t, locale } = useLocaleContext();
  const navigate = useNavigate();
  const { getCurrency } = usePaymentContext();

  const [search, setSearch] = useState<{ pageSize: number; page: number }>({
    pageSize: pageSize || 10,
    page: 1,
  });
  const {
    loading,
    data = { list: [], count: 0 },
    refresh,
  } = useRequest(
    () =>
      fetchData({
        ...search,
        status,
        customer_id,
        currency_id,
        subscription_id,
        include_staking,
        include_return_staking,
        include_recovered_from,
        ignore_zero: true,
      }),
    {
      refreshDeps: [search, status, customer_id, currency_id, subscription_id, include_staking, include_recovered_from],
    }
  );

  const prevData = useRef(data);

  useEffect(() => {
    if (onTableDataChange) {
      onTableDataChange(data, prevData.current);
      prevData.current = data;
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [data]);

  const subscription = useSubscription('events');

  const debouncedHandleInvoicePaid = debounce(
    async () => {
      Toast.close();
      Toast.success(t('payment.customer.invoice.paySuccess'));
      await refresh();
    },
    1000,
    {
      leading: false,
      trailing: true,
      maxWait: 5000,
    }
  );

  useEffect(() => {
    if (subscription && customer_id) {
      subscription.on('invoice.paid', ({ response }: { response: TInvoiceExpanded }) => {
        if (response.customer_id === customer_id) {
          debouncedHandleInvoicePaid();
        }
      });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [subscription]);

  const handleLinkClick = (e: React.MouseEvent, invoice: TInvoiceExpanded) => {
    const { link } = getInvoiceLink(invoice, action);
    handleNavigation(e, link, navigate, { target: link.external ? '_blank' : target });
  };

  const handleRelatedSubscriptionClick = (e: React.MouseEvent, invoice: TInvoiceExpanded) => {
    if (invoice.subscription_id) {
      handleNavigation(e, createLink(`/customer/subscription/${invoice.subscription_id}`), navigate);
    }
  };

  const columns = [
    {
      label: t('common.amount'),
      name: 'total',
      width: 80,
      align: 'right',
      options: {
        customBodyRenderLite: (_: string, index: number) => {
          const invoice = data?.list[index] as TInvoiceExpanded;
          const isVoid = invoice.status === 'void';
          const quoteInfo = getInvoiceQuoteInfo(invoice);
          const providers = quoteInfo?.providers || [];
          const providerNames = providers.map((provider: any) => provider.provider_name).filter(Boolean);
          const providerDisplay =
            providerNames.length > 0
              ? providerNames.join(', ')
              : quoteInfo?.rate_provider_name || quoteInfo?.rate_provider_id || '—';
          const providerRates =
            quoteInfo?.providers
              ?.map((provider: any) => {
                const name = provider.provider_name || provider.provider_id || '—';
                return provider.rate ? `${name}` : name;
              })
              .filter(Boolean) || [];
          const rateTimestamp = quoteInfo?.rate_timestamp_ms ? formatTime(quoteInfo.rate_timestamp_ms) : '—';
          const formattedRate = formatExchangeRate(quoteInfo?.exchange_rate || null);
          const rateLine = formattedRate
            ? (() => {
                const currencyMap = {
                  USD: '$',
                  CNY: '¥',
                };
                const currencySymbol = currencyMap[quoteInfo?.base_currency as keyof typeof currencyMap];
                return `1 ${invoice.paymentCurrency.symbol} ≈ ${
                  currencySymbol
                    ? `${currencySymbol}${formattedRate}`
                    : `${formattedRate} ${quoteInfo?.base_currency || 'USD'}`
                }`;
              })()
            : null;

          let usdAmount: string | null = null;
          if (quoteInfo?.base_amount) {
            usdAmount = formatUsdAmount(quoteInfo.base_amount, locale);
          } else if (quoteInfo?.exchange_rate && invoice.total) {
            const calculatedUsd = getUsdAmountFromTokenUnits(
              new BN(invoice.total),
              invoice.paymentCurrency.decimal,
              quoteInfo.exchange_rate
            );
            if (calculatedUsd) {
              usdAmount = formatUsdAmount(calculatedUsd, locale);
            }
          }

          const tooltipContent = quoteInfo ? (
            <Stack spacing={0.5} sx={{ p: 1 }}>
              <Stack direction="row" justifyContent="space-between" spacing={2}>
                <Typography variant="caption" sx={{ color: 'text.secondary' }}>
                  {t('payment.customer.invoice.quote.providers')}:
                </Typography>
                <Typography variant="caption" sx={{ color: 'text.primary' }}>
                  {(providerRates.length > 0 ? providerRates.join(', ') : providerDisplay) || '—'}
                </Typography>
              </Stack>
              {rateLine && (
                <Stack direction="row" justifyContent="space-between" spacing={2}>
                  <Typography variant="caption" sx={{ color: 'text.secondary' }}>
                    {t('payment.customer.invoice.quote.exchangeRate')}:
                  </Typography>
                  <Typography variant="caption" sx={{ color: 'text.primary' }}>
                    {rateLine}
                  </Typography>
                </Stack>
              )}
              <Stack direction="row" justifyContent="space-between" spacing={2}>
                <Typography variant="caption" sx={{ color: 'text.secondary' }}>
                  {t('payment.customer.invoice.quote.rateTimestamp')}:
                </Typography>
                <Typography variant="caption" sx={{ color: 'text.primary' }}>
                  {rateTimestamp}
                </Typography>
              </Stack>
            </Stack>
          ) : null;

          return (
            <Box onClick={(e) => handleLinkClick(e, invoice)} sx={linkStyle}>
              <Stack spacing={0.25} alignItems="flex-end">
                <Typography sx={isVoid ? { textDecoration: 'line-through' } : {}}>
                  {formatAmount(invoice.total, invoice.paymentCurrency.decimal)}&nbsp;
                  {invoice.paymentCurrency.symbol}
                </Typography>
                {(usdAmount || rateLine) && (
                  <Tooltip
                    title={tooltipContent}
                    placement="top"
                    arrow
                    slotProps={{
                      tooltip: {
                        sx: {
                          backgroundColor: 'background.paper',
                          boxShadow: 1,
                        },
                      },
                    }}>
                    <Stack spacing={0.25} alignItems="flex-end">
                      {usdAmount && (
                        <Typography
                          variant="caption"
                          sx={{
                            color: 'text.secondary',
                            fontSize: '0.75rem',
                            fontWeight: 400,
                            lineHeight: 1.2,
                          }}>
                          ≈ ${usdAmount}
                        </Typography>
                      )}
                    </Stack>
                  </Tooltip>
                )}
              </Stack>
            </Box>
          );
        },
      },
    },
    {
      label: t('common.paymentMethod'),
      name: 'paymentMethod',
      options: {
        customBodyRenderLite: (_: string, index: number) => {
          const invoice = data?.list[index] as TInvoiceExpanded;
          return (
            <Typography
              sx={{ display: 'flex', alignItems: 'center', whiteSpace: 'nowrap' }}
              onClick={(e) => handleLinkClick(e, invoice)}>
              <Avatar src={invoice.paymentMethod.logo} sx={{ width: 18, height: 18, mr: 1 }} />
              {invoice.paymentMethod.name}
            </Typography>
          );
        },
      },
    },
    {
      label: t('common.type'),
      name: 'billing_reason',
      options: {
        customBodyRenderLite: (_: string, index: number) => {
          const invoice = data.list[index] as TInvoiceExpanded;
          return (
            <Box onClick={(e) => handleLinkClick(e, invoice)} sx={linkStyle}>
              <Status label={getInvoiceDescriptionAndReason(invoice, locale)?.type} />
            </Box>
          );
        },
      },
    },
    {
      label: t('payment.customer.invoice.invoiceNumber'),
      name: 'number',
      options: {
        customBodyRenderLite: (_: string, index: number) => {
          const invoice = data?.list[index] as TInvoiceExpanded;
          return (
            <Box onClick={(e) => handleLinkClick(e, invoice)} sx={linkStyle}>
              {invoice?.number}
            </Box>
          );
        },
      },
    },
    ...(relatedSubscription
      ? [
          {
            label: t('common.purchaseItems'),
            name: 'purchase_items',
            options: {
              customBodyRenderLite: (_: string, index: number) => {
                const invoice = data?.list[index] as TInvoiceExpanded;
                const lines = (invoice as any).lines || [];
                const items = lines
                  .map((line: any) => {
                    const name = line.price?.product?.name || line.description;
                    if (!name) {
                      return null;
                    }
                    const quantity = Number(line.quantity || 0);
                    const label = Number.isFinite(quantity) && quantity > 1 ? `${name} x${quantity}` : name;
                    const lineKey = line.id || line.price?.id || line.price?.product?.id || line.description || name;
                    return { key: String(lineKey), label };
                  })
                  .filter(Boolean) as Array<{ key: string; label: string }>;

                if (items.length === 0 && invoice.subscription?.description) {
                  items.push({
                    key: `subscription-${invoice.subscription_id || invoice.id}`,
                    label: invoice.subscription.description,
                  });
                }
                const isSubscription = Boolean(invoice.subscription_id);
                const clickableProps = isSubscription
                  ? { onClick: (e: React.MouseEvent) => handleRelatedSubscriptionClick(e, invoice) }
                  : {};

                if (items.length === 0) {
                  return (
                    <Box sx={{ color: 'text.lighter' }}>
                      <Typography sx={{ fontSize: 14 }}>{t('common.none')}</Typography>
                    </Box>
                  );
                }

                return (
                  <Box {...clickableProps} sx={isSubscription ? { cursor: 'pointer' } : undefined}>
                    <Stack spacing={0.5}>
                      {items.map((item) => (
                        <Typography
                          key={`${invoice.id}-item-${item.key}`}
                          sx={{ fontSize: 14, color: isSubscription ? 'text.link' : 'text.primary' }}
                          noWrap>
                          {item.label}
                        </Typography>
                      ))}
                    </Stack>
                  </Box>
                );
              },
            },
          },
          {
            label: t('common.credits'),
            name: 'credits',
            options: {
              customBodyRenderLite: (_: string, index: number) => {
                const invoice = data?.list[index] as TInvoiceExpanded;
                const lines = (invoice as any).lines || [];
                const creditItems: Array<{ key: string; label: string }> = [];

                lines.forEach((line: any) => {
                  const lineKey = String(
                    line.id || line.price?.id || line.price?.product?.id || line.description || invoice.id
                  );
                  const pushCreditItem = (suffix: string, label: string) => {
                    creditItems.push({ key: `${lineKey}-${suffix}`, label });
                  };
                  const creditConfig = line.price?.metadata?.credit_config;
                  const creditAmount = Number(creditConfig?.credit_amount || 0);
                  if (creditAmount > 0) {
                    const quantity = Number(line.quantity || 0);
                    const totalAmount = creditAmount * (Number.isFinite(quantity) && quantity > 0 ? quantity : 1);
                    const currencySymbol =
                      getCurrency(creditConfig?.currency_id)?.symbol || creditConfig?.currency_id || 'Credits';
                    pushCreditItem('amount', `+${formatCreditAmount(String(totalAmount), currencySymbol)}`);
                    return;
                  }

                  const scheduleConfig = creditConfig?.schedule;
                  const scheduledAmount = Number(scheduleConfig?.amount_per_grant || 0);
                  if (scheduleConfig?.enabled && scheduleConfig?.delivery_mode === 'schedule' && scheduledAmount > 0) {
                    const quantity = Number(line.quantity || 0);
                    const totalAmount = scheduledAmount * (Number.isFinite(quantity) && quantity > 0 ? quantity : 1);
                    const currencySymbol =
                      getCurrency(creditConfig?.currency_id)?.symbol || creditConfig?.currency_id || 'Credits';
                    pushCreditItem('schedule', `+${formatCreditAmount(String(totalAmount), currencySymbol)}`);
                    return;
                  }

                  const creditInfo = (line.price as any)?.credit;
                  const creditInfoAmount = Number(creditInfo?.amount || 0);
                  if (creditInfoAmount > 0) {
                    const currencySymbol = creditInfo.currency?.symbol || 'Credits';
                    pushCreditItem('credit', `+${formatCreditAmount(String(creditInfoAmount), currencySymbol)}`);
                  }
                });

                if (creditItems.length === 0) {
                  return '-';
                }

                return (
                  <Stack spacing={0.5}>
                    {creditItems.map((creditItem) => (
                      <Typography
                        key={`${invoice.id}-credit-${creditItem.key}`}
                        sx={{ fontSize: 14, color: 'success.main' }}
                        noWrap>
                        {creditItem.label}
                      </Typography>
                    ))}
                  </Stack>
                );
              },
            },
          },
        ]
      : []),
    {
      label: t('common.updatedAt'),
      name: 'name',
      options: {
        customBodyRenderLite: (val: string, index: number) => {
          const invoice = data?.list[index] as TInvoiceExpanded;
          const periodTooltip =
            invoice.subscription_id && invoice.period_start && invoice.period_end
              ? `${t('common.billingPeriod')}: ${formatToDate(invoice.period_start * 1000, locale, 'YYYY-MM-DD HH:mm')} ~ ${formatToDate(invoice.period_end * 1000, locale, 'YYYY-MM-DD HH:mm')}`
              : '';

          return (
            <Tooltip title={periodTooltip} arrow placement="top-start">
              <Box onClick={(e) => handleLinkClick(e, invoice)} sx={linkStyle}>
                {formatToDate(
                  invoice.created_at,
                  locale,
                  relatedSubscription ? 'YYYY-MM-DD HH:mm' : 'YYYY-MM-DD HH:mm:ss'
                )}
              </Box>
            </Tooltip>
          );
        },
      },
    },
    {
      label: t('common.status'),
      name: 'status',
      options: {
        customBodyRenderLite: (val: string, index: number) => {
          const invoice = data?.list[index] as TInvoiceExpanded;
          const hidePay = invoice.billing_reason === 'overdraft-protection';
          const { connect } = getInvoiceLink(invoice, action);
          const isVoid = invoice.status === 'void';

          if (action && !hidePay) {
            if (connect) {
              if (invoice.paymentMethod?.type === 'stripe') {
                return (
                  <StripePaymentAction
                    invoice={invoice}
                    paymentMethod={invoice.paymentMethod as any}
                    onSuccess={() => {
                      refresh();
                    }}>
                    {(handlePay, paying) => (
                      <Button
                        variant="text"
                        size="small"
                        sx={{ color: 'text.link' }}
                        disabled={paying}
                        onClick={(e) => {
                          e.preventDefault();
                          e.stopPropagation();
                          handlePay();
                        }}>
                        {paying ? t('payment.checkout.processing') : t('payment.customer.invoice.pay')}
                      </Button>
                    )}
                  </StripePaymentAction>
                );
              }
              return (
                <Button variant="text" size="small" onClick={() => onPay(invoice.id)} sx={{ color: 'text.link' }}>
                  {t('payment.customer.invoice.pay')}
                </Button>
              );
            }
            return (
              <Button
                component="a"
                variant="text"
                size="small"
                onClick={(e) => handleLinkClick(e, invoice)}
                sx={{ color: 'text.link' }}
                rel="noreferrer">
                {t('payment.customer.invoice.pay')}
              </Button>
            );
          }
          return (
            <Box onClick={(e) => handleLinkClick(e, invoice)} sx={linkStyle}>
              {isVoid ? (
                <Tooltip title={t('payment.customer.invoice.noPaymentRequired')} arrow placement="top">
                  <span>
                    <Status label={invoice.status} color={getInvoiceStatusColor(invoice.status)} />
                  </span>
                </Tooltip>
              ) : (
                <Status label={invoice.status} color={getInvoiceStatusColor(invoice.status)} />
              )}
            </Box>
          );
        },
      },
    },
  ];

  const onTableChange = ({ page, rowsPerPage }: any) => {
    if (search.pageSize !== rowsPerPage) {
      setSearch((x) => ({ ...x, pageSize: rowsPerPage, page: 1 }));
    } else if (search.page !== page + 1) {
      setSearch((x) => ({ ...x, page: page + 1 }));
    }
  };

  return (
    <InvoiceTableRoot>
      <Table
        hasRowLink
        durable={`__${listKey}__`}
        durableKeys={['page', 'rowsPerPage', 'searchText']}
        data={data.list}
        columns={columns}
        options={{
          count: data.count,
          page: search.page - 1,
          rowsPerPage: search.pageSize,
        }}
        loading={loading}
        onChange={onTableChange}
        toolbar={false}
        sx={{ mt: 2 }}
        showMobile={false}
        mobileTDFlexDirection="row"
        emptyNodeText={t('payment.customer.invoice.emptyList')}
      />
    </InvoiceTableRoot>
  );
});

const InvoiceTableRoot = styled(Box)`
  @media (max-width: ${({ theme }) => theme.breakpoints.values.md}px) {
    .MuiTable-root > .MuiTableBody-root > .MuiTableRow-root > td.MuiTableCell-root {
      > div {
        width: fit-content;
        flex: inherit;
        font-size: 14px;
      }
    }
    .invoice-summary {
      padding-right: 20px;
    }
  }
`;

const InvoiceList = React.memo((props: Props & { onPay: (invoiceId: string) => void }) => {
  const {
    customer_id,
    subscription_id,
    include_recovered_from,
    currency_id,
    include_staking,
    status,
    pageSize,
    target,
    action,
    onPay,
    onTableDataChange,
  } = props;
  const size = pageSize || 10;

  const subscription = useSubscription('events');
  const { t, locale } = useLocaleContext();
  const navigate = useNavigate();

  const { data, loadMore, loadingMore, loading, reloadAsync } = useInfiniteScroll<Result>(
    (d) => {
      const page = d ? Math.ceil(d.list.length / size) + 1 : 1;
      return fetchData({
        page,
        pageSize: size,
        status,
        customer_id,
        currency_id,
        subscription_id,
        include_staking,
        include_recovered_from,
        ignore_zero: true,
      });
    },
    {
      reloadDeps: [customer_id, subscription_id, status, include_staking, include_recovered_from],
    }
  );

  const prevData = useRef(data);

  useEffect(() => {
    if (onTableDataChange) {
      onTableDataChange(data, prevData.current);
      prevData.current = data;
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [data]);

  const debouncedHandleInvoicePaid = debounce(
    async () => {
      Toast.close();
      Toast.success(t('payment.customer.invoice.paySuccess'));
      await reloadAsync();
    },
    1000,
    {
      leading: false,
      trailing: true,
      maxWait: 5000,
    }
  );
  // Listen to invoice.paid event and refresh data
  useEffect(() => {
    if (subscription && customer_id) {
      subscription.on('invoice.paid', ({ response }: { response: TInvoiceExpanded }) => {
        if (response.customer_id === customer_id) {
          debouncedHandleInvoicePaid();
        }
      });
    }
  }, [subscription]); // eslint-disable-line react-hooks/exhaustive-deps

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

  if (data && data.list.length === 0) {
    if (data.subscription && ['active', 'trialing'].includes(data.subscription.status)) {
      return (
        <Typography
          sx={{
            color: 'text.secondary',
            my: 0.5,
          }}>
          {t('payment.customer.invoice.next', { date: formatToDatetime(data.subscription.current_period_end * 1000) })}
        </Typography>
      );
    }

    return (
      <Typography
        sx={{
          color: 'text.secondary',
          my: 0.5,
        }}>
        {t('payment.customer.invoice.empty')}
      </Typography>
    );
  }

  const hasMore = data && data.list.length < data.count;

  const grouped = groupByDate(data.list as any);

  const handleLinkClick = (e: React.MouseEvent, link: LinkInfo) => {
    handleNavigation(e, link, navigate, { target: link.external ? '_blank' : target });
  };

  return (
    <Root direction="column" gap={1} sx={{ mt: 1 }}>
      {Object.entries(grouped).map(([date, invoices]) => (
        <Box key={date}>
          <Typography sx={{ fontWeight: 'bold', color: 'text.secondary', mt: 2, mb: 1 }}>{date}</Typography>
          {invoices.map((invoice) => {
            const { link, connect } = getInvoiceLink(invoice, action);
            const isVoid = invoice.status === 'void';
            const quoteInfo = getInvoiceQuoteInfo(invoice);
            const formattedRate = formatExchangeRate(quoteInfo?.exchange_rate || null);
            const rateLine = formattedRate
              ? `1 ${invoice.paymentCurrency.symbol} ≈ ${formattedRate} ${quoteInfo?.base_currency || 'USD'}`
              : null;
            return (
              <Stack
                key={invoice.id}
                direction="row"
                sx={{
                  gap: {
                    xs: 0.5,
                    sm: 1.5,
                    md: 3,
                  },

                  alignItems: 'center',
                  flexWrap: 'nowrap',
                  my: 1,
                }}>
                <Box
                  sx={{
                    flex: 2,
                  }}>
                  <a
                    href={link.url}
                    target={link.external ? '_blank' : target}
                    rel="noreferrer"
                    onClick={(e) => handleLinkClick(e, link)}>
                    <Stack
                      direction="row"
                      spacing={0.5}
                      sx={{
                        alignItems: 'center',
                      }}>
                      <Typography component="span">{invoice.number}</Typography>
                      {link.external && (
                        <OpenInNewOutlined
                          fontSize="small"
                          sx={{
                            color: 'text.secondary',
                            display: { xs: 'none', md: 'inline-flex' },
                          }}
                        />
                      )}
                    </Stack>
                  </a>
                </Box>
                <Box
                  sx={{
                    flex: 1,
                    textAlign: 'right',
                  }}>
                  <Typography sx={isVoid ? { textDecoration: 'line-through' } : {}}>
                    {formatAmount(invoice.total, invoice.paymentCurrency.decimal)}&nbsp;
                    {invoice.paymentCurrency.symbol}
                  </Typography>
                  {rateLine && (
                    <Typography variant="caption" sx={{ color: 'text.secondary', display: 'block' }}>
                      {rateLine}
                    </Typography>
                  )}
                </Box>
                <Tooltip
                  title={
                    invoice.subscription_id && invoice.period_start && invoice.period_end
                      ? `${t('common.billingPeriod')}: ${formatToDate(invoice.period_start * 1000, locale, 'YYYY-MM-DD HH:mm')} ~ ${formatToDate(invoice.period_end * 1000, locale, 'YYYY-MM-DD HH:mm')}`
                      : ''
                  }
                  arrow
                  placement="top-start">
                  <Box
                    sx={{
                      flex: 1,
                      textAlign: 'right',
                    }}>
                    <Typography>{formatToDate(invoice.created_at, locale, 'HH:mm:ss')}</Typography>
                  </Box>
                </Tooltip>
                {!action && (
                  <Box
                    className="invoice-description"
                    sx={{
                      flex: 2,
                      textAlign: 'right',
                      display: { xs: 'none', lg: 'inline-flex' },
                    }}>
                    <Typography>{invoice.description || invoice.id}</Typography>
                  </Box>
                )}
                <Box
                  sx={{
                    flex: 1,
                    textAlign: 'right',
                  }}>
                  {action ? (
                    connect ? (
                      invoice.paymentMethod?.type === 'stripe' ? (
                        <StripePaymentAction
                          invoice={invoice}
                          paymentMethod={invoice.paymentMethod as any}
                          onSuccess={async () => {
                            await reloadAsync();
                          }}>
                          {(handlePay, paying) => (
                            <Button
                              variant="contained"
                              color="primary"
                              size="small"
                              sx={{ whiteSpace: 'nowrap' }}
                              disabled={paying}
                              onClick={(e) => {
                                e.preventDefault();
                                e.stopPropagation();
                                handlePay();
                              }}>
                              {paying ? t('payment.checkout.processing') : t('payment.customer.invoice.pay')}
                            </Button>
                          )}
                        </StripePaymentAction>
                      ) : (
                        <Button
                          variant="contained"
                          color="primary"
                          size="small"
                          onClick={() => onPay(invoice.id)}
                          sx={{ whiteSpace: 'nowrap' }}>
                          {t('payment.customer.invoice.pay')}
                        </Button>
                      )
                    ) : (
                      <Button
                        component="a"
                        variant="contained"
                        size="small"
                        onClick={(e) => handleLinkClick(e, link)}
                        sx={{ whiteSpace: 'nowrap' }}
                        rel="noreferrer">
                        {t('payment.customer.invoice.pay')}
                      </Button>
                    )
                  ) : isVoid ? (
                    <Tooltip title={t('payment.customer.invoice.noPaymentRequired')} arrow placement="top">
                      <span>
                        <Status label={invoice.status} color={getInvoiceStatusColor(invoice.status)} />
                      </span>
                    </Tooltip>
                  ) : (
                    <Status label={invoice.status} color={getInvoiceStatusColor(invoice.status)} />
                  )}
                </Box>
              </Stack>
            );
          })}
        </Box>
      ))}
      <Box>
        {hasMore && (
          <Button variant="text" type="button" color="inherit" onClick={loadMore} disabled={loadingMore}>
            {loadingMore
              ? t('common.loadingMore', { resource: t('payment.customer.invoices') })
              : t('common.loadMore', { resource: t('payment.customer.invoices') })}
          </Button>
        )}
        {!hasMore && data.count > size && (
          <Typography
            sx={{
              color: 'text.secondary',
            }}>
            {t('common.noMore', { resource: t('payment.customer.invoices') })}
          </Typography>
        )}
      </Box>
    </Root>
  );
});

export default function CustomerInvoiceList(rawProps: Props) {
  const props = Object.assign(
    {
      customer_id: '',
      subscription_id: '',
      currency_id: '',
      include_staking: false,
      include_recovered_from: false,
      status: 'open,paid,uncollectible',
      pageSize: 10,
      target: '_self',
      action: '',
      type: 'list',
      onTableDataChange: () => {},
      relatedSubscription: false,
    },
    rawProps
  );
  // eslint-disable-next-line react/prop-types
  const { action, type } = props;
  const { t, locale } = useLocaleContext();
  const { connect } = usePaymentContext();
  const [state, setState] = useSetState({ paying: '' });

  const onPay = (invoiceId: string) => {
    if (state.paying) {
      return;
    }

    setState({ paying: invoiceId });
    connect.open({
      action: 'collect',
      saveConnect: false,
      locale: locale as 'en' | 'zh',
      useSocket: isCrossOrigin() === false,
      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,
      extraParams: { invoiceId, action },
      onSuccess: () => {
        connect.close();
        setState({ paying: '' });
      },
      onClose: () => {
        connect.close();
        setState({ paying: '' });
      },
      onError: (err: any) => {
        setState({ paying: '' });
        Toast.error(formatError(err));
      },
    });
  };

  if (type === 'table') {
    return <InvoiceTable {...props} onPay={onPay} />;
  }
  return <InvoiceList {...props} onPay={onPay} />;
}

const Root = styled(Stack)`
  @media (max-width: ${({ theme }) => theme.breakpoints.values.md}px) {
    svg.MuiSvgIcon-root {
      display: none !important;
    }
  }

  a.MuiButton-root {
    text-decoration: none !important;
  }
`;
