import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import type { DonationSettings, TLineItemExpanded, TPaymentCurrency } from '@blocklet/payment-types';
import { HelpOutline } from '@mui/icons-material';
import { Box, Divider, Fade, Grow, Stack, Tooltip, Typography, Collapse, IconButton } from '@mui/material';
import type { IconButtonProps } from '@mui/material';
import { BN, fromTokenToUnit, fromUnitToToken } from '@ocap/util';
import { useRequest, useSetState } from 'ahooks';
import noop from 'lodash/noop';
import useBus from 'use-bus';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { styled } from '@mui/material/styles';
import Status from '../components/status';
import api from '../libs/api';
import { formatAmount, formatCheckoutHeadlines, getPriceUintAmountByCurrency } from '../libs/util';
import PaymentAmount from './amount';
import ProductDonation from './product-donation';
import ProductItem from './product-item';
import Livemode from '../components/livemode';
import { usePaymentContext } from '../contexts/payment';
import { useMobile } from '../hooks/mobile';
import LoadingButton from '../components/loading-button';

// const shake = keyframes`
//   0% {
//     transform: rotate(0deg);
//   }
//   25% {
//     transform: rotate(2deg);
//   }
//   50% {
//     transform: rotate(0eg);
//   }
//   75% {
//     transform: rotate(-2deg);
//   }
//   100% {
//     transform: rotate(0deg);
//   }
// `;

interface ExpandMoreProps extends IconButtonProps {
  expand: boolean;
}

const ExpandMore = styled((props: ExpandMoreProps) => {
  const { expand, ...other } = props;
  return <IconButton {...other} />;
})(({ theme, expand }) => ({
  transform: !expand ? 'rotate(0deg)' : 'rotate(180deg)',
  marginLeft: 'auto',
  transition: theme.transitions.create('transform', {
    duration: theme.transitions.duration.shortest,
  }),
}));

type Props = {
  items: TLineItemExpanded[];
  currency: TPaymentCurrency;
  trialInDays: number;
  trialEnd?: number;
  billingThreshold: number;
  showStaking?: boolean;
  onUpsell?: Function;
  onDownsell?: Function;
  onQuantityChange?: Function;
  onChangeAmount?: Function;
  onApplyCrossSell?: Function;
  onCancelCrossSell?: Function;
  checkoutSessionId?: string;
  crossSellBehavior?: string;
  donationSettings?: DonationSettings; // only include backend part
  action?: string;
  completed?: boolean;
};

async function fetchCrossSell(id: string) {
  try {
    const { data } = await api.get(`/api/checkout-sessions/${id}/cross-sell`);
    if (!data.error) {
      return data;
    }

    return null;
  } catch (err) {
    return null;
  }
}

function getStakingSetup(items: TLineItemExpanded[], currency: TPaymentCurrency, billingThreshold = 0) {
  const staking = {
    licensed: new BN(0),
    metered: new BN(0),
  };

  const recurringItems = items
    .map((x) => x.upsell_price || x.price)
    .filter((x) => x.type === 'recurring' && x.recurring);

  if (recurringItems.length > 0) {
    if (+billingThreshold) {
      return fromTokenToUnit(billingThreshold, currency.decimal).toString();
    }

    items.forEach((x) => {
      const price = x.upsell_price || x.price;
      const unit = getPriceUintAmountByCurrency(price, currency);
      const amount = new BN(unit).mul(new BN(x.quantity));
      if (price.type === 'recurring' && price.recurring) {
        if (price.recurring.usage_type === 'licensed') {
          staking.licensed = staking.licensed.add(amount);
        }
        if (price.recurring.usage_type === 'metered') {
          staking.metered = staking.metered.add(amount);
        }
      }
    });

    return staking.licensed.add(staking.metered).toString();
  }

  return '0';
}
export default function PaymentSummary({
  items,
  currency,
  trialInDays,
  billingThreshold,
  onUpsell = noop,
  onDownsell = noop,
  onQuantityChange = noop,
  onApplyCrossSell = noop,
  onCancelCrossSell = noop,
  onChangeAmount = noop,
  checkoutSessionId = '',
  crossSellBehavior = '',
  showStaking = false,
  donationSettings = undefined,
  action = '',
  trialEnd = 0,
  completed = false,
  ...rest
}: Props) {
  const { t, locale } = useLocaleContext();
  const { isMobile } = useMobile();
  const settings = usePaymentContext();
  const [state, setState] = useSetState({ loading: false, shake: false, expanded: items?.length < 3 });
  const { data, runAsync } = useRequest(() =>
    checkoutSessionId ? fetchCrossSell(checkoutSessionId) : Promise.resolve(null)
  );
  const headlines = formatCheckoutHeadlines(items, currency, { trialEnd, trialInDays }, locale);
  const staking = showStaking ? getStakingSetup(items, currency, billingThreshold) : '0';

  const totalAmount = fromUnitToToken(
    new BN(fromTokenToUnit(headlines.actualAmount, currency?.decimal)).add(new BN(staking)).toString(),
    currency?.decimal
  );
  useBus(
    'error.REQUIRE_CROSS_SELL',
    () => {
      setState({ shake: true });
      setTimeout(() => {
        setState({ shake: false });
      }, 1000);
    },
    []
  );

  const handleUpsell = async (from: string, to: string) => {
    await onUpsell!(from, to);
    runAsync();
  };

  const handleQuantityChange = async (itemId: string, quantity: number) => {
    await onQuantityChange!(itemId, quantity);
    runAsync();
  };

  const handleDownsell = async (from: string) => {
    await onDownsell!(from);
    runAsync();
  };

  const handleApplyCrossSell = async () => {
    if (data) {
      try {
        setState({ loading: true });
        await onApplyCrossSell!(data.id);
      } catch (err) {
        console.error(err);
      } finally {
        setState({ loading: false });
      }
    }
  };

  const handleCancelCrossSell = async () => {
    try {
      setState({ loading: true });
      await onCancelCrossSell!();
    } catch (err) {
      console.error(err);
    } finally {
      setState({ loading: false });
    }
  };

  const ProductCardList = (
    <Stack
      className="cko-product-list"
      sx={{
        flex: '0 1 auto',
        overflow: 'auto',
      }}>
      <Stack spacing={{ xs: 1, sm: 2 }}>
        {items.map((x: TLineItemExpanded) =>
          x.price.custom_unit_amount && onChangeAmount && donationSettings ? (
            <ProductDonation
              key={`${x.price_id}-${currency.id}`}
              item={x}
              settings={donationSettings}
              onChange={onChangeAmount}
              currency={currency}
            />
          ) : (
            <ProductItem
              key={`${x.price_id}-${currency.id}`}
              item={x}
              items={items}
              trialInDays={trialInDays}
              trialEnd={trialEnd}
              currency={currency}
              onUpsell={handleUpsell}
              onDownsell={handleDownsell}
              adjustableQuantity={x.adjustable_quantity}
              completed={completed}
              onQuantityChange={handleQuantityChange}>
              {x.cross_sell && (
                <Stack
                  direction="row"
                  sx={{
                    alignItems: 'center',
                    justifyContent: 'space-between',
                    width: 1,
                  }}>
                  <Typography />
                  <LoadingButton
                    size="small"
                    loadingPosition="end"
                    endIcon={null}
                    color="error"
                    variant="text"
                    loading={state.loading}
                    onClick={handleCancelCrossSell}>
                    {t('payment.checkout.cross_sell.remove')}
                  </LoadingButton>
                </Stack>
              )}
            </ProductItem>
          )
        )}
      </Stack>
      {data && items.some((x) => x.price_id === data.id) === false && (
        <Grow in>
          <Stack
            sx={{
              mt: 1,
            }}>
            <ProductItem
              item={{ quantity: 1, price: data, price_id: data.id, cross_sell: true } as TLineItemExpanded}
              items={items}
              trialInDays={trialInDays}
              currency={currency}
              trialEnd={trialEnd}
              onUpsell={noop}
              onDownsell={noop}>
              <Stack
                direction="row"
                sx={{
                  alignItems: 'center',
                  justifyContent: 'space-between',
                  width: 1,
                }}>
                <Typography>
                  {crossSellBehavior === 'required' && (
                    <Status label={t('payment.checkout.required')} color="info" variant="outlined" sx={{ mr: 1 }} />
                  )}
                </Typography>
                <LoadingButton
                  size="small"
                  loadingPosition="end"
                  endIcon={null}
                  color={crossSellBehavior === 'required' ? 'info' : 'info'}
                  variant={crossSellBehavior === 'required' ? 'text' : 'text'}
                  loading={state.loading}
                  onClick={handleApplyCrossSell}>
                  {t('payment.checkout.cross_sell.add')}
                </LoadingButton>
              </Stack>
            </ProductItem>
          </Stack>
        </Grow>
      )}
    </Stack>
  );
  return (
    <Fade in>
      <Stack className="cko-product" direction="column" {...rest}>
        <Box
          sx={{
            display: 'flex',
            alignItems: 'center',
            mb: 2.5,
          }}>
          <Typography
            title={t('payment.checkout.orderSummary')}
            sx={{
              color: 'text.primary',
              fontSize: {
                xs: '18px',
                md: '24px',
              },
              fontWeight: '700',
              lineHeight: '32px',
            }}>
            {action || t('payment.checkout.orderSummary')}
          </Typography>
          {!settings.livemode && <Livemode />}
        </Box>
        {isMobile && !donationSettings ? (
          <>
            <Stack
              onClick={() => setState({ expanded: !state.expanded })}
              sx={{
                justifyContent: 'space-between',
                flexDirection: 'row',
                alignItems: 'center',
                mb: 1.5,
              }}>
              <Typography>{t('payment.checkout.productListTotal', { total: items.length })}</Typography>
              <ExpandMore expand={state.expanded} aria-expanded={state.expanded} aria-label="show more">
                <ExpandMoreIcon />
              </ExpandMore>
            </Stack>
            <Collapse in={state.expanded || !isMobile} timeout="auto" unmountOnExit>
              {ProductCardList}
            </Collapse>
          </>
        ) : (
          ProductCardList
        )}

        <Divider sx={{ mt: 2.5, mb: 2.5 }} />
        {staking > 0 && (
          <>
            <Stack
              direction="row"
              spacing={1}
              sx={{
                justifyContent: 'space-between',
                alignItems: 'center',
              }}>
              <Stack
                direction="row"
                spacing={0.5}
                sx={{
                  alignItems: 'center',
                }}>
                <Typography sx={{ color: 'text.secondary' }}>{t('payment.checkout.paymentRequired')}</Typography>
                <Tooltip title={t('payment.checkout.stakingConfirm')} placement="top" sx={{ maxWidth: '150px' }}>
                  <HelpOutline fontSize="small" sx={{ color: 'text.lighter' }} />
                </Tooltip>
              </Stack>
              <Typography>{headlines.amount}</Typography>
            </Stack>
            <Stack
              direction="row"
              spacing={1}
              sx={{
                justifyContent: 'space-between',
                alignItems: 'center',
              }}>
              <Stack
                direction="row"
                spacing={0.5}
                sx={{
                  alignItems: 'center',
                }}>
                <Typography sx={{ color: 'text.secondary' }}>{t('payment.checkout.staking.title')}</Typography>
                <Tooltip title={t('payment.checkout.staking.tooltip')} placement="top" sx={{ maxWidth: '150px' }}>
                  <HelpOutline fontSize="small" sx={{ color: 'text.lighter' }} />
                </Tooltip>
              </Stack>
              <Typography>
                {formatAmount(staking, currency.decimal)} {currency.symbol}
              </Typography>
            </Stack>
          </>
        )}
        <Stack
          sx={{
            display: 'flex',
            justifyContent: 'space-between',
            flexDirection: 'row',
            alignItems: 'center',
            width: '100%',
          }}>
          <Box className="base-label">{t('common.total')} </Box>
          <PaymentAmount amount={`${totalAmount} ${currency.symbol}`} sx={{ fontSize: '16px' }} />
        </Stack>
        {headlines.then && headlines.showThen && (
          <Typography
            component="div"
            sx={{ fontSize: '0.7875rem', color: 'text.lighter', textAlign: 'right', margin: '-2px 0 8px' }}>
            {headlines.then}
          </Typography>
        )}
      </Stack>
    </Fade>
  );
}
