import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import { useForm } from 'react-hook-form';
import {
  Button,
  CircularProgress,
  Stack,
  TextField,
  Typography,
  FormControlLabel,
  Alert,
  Box,
  Card,
  CardActionArea,
  Grid,
  Tooltip,
  FormControl,
  RadioGroup,
  Radio,
  Link,
  Skeleton,
} from '@mui/material';
import Dialog from '@arcblock/ux/lib/Dialog';
import { EventHandler, useState } from 'react';
import { api, formatAmountPrecisionLimit, Switch, useMobile } from '@blocklet/payment-react';
import { useRequest, useUnmount } from 'ahooks';
import { BN, fromTokenToUnit, fromUnitToToken } from '@ocap/util';
import type { TPaymentCurrency, TSubscriptionExpanded } from '@blocklet/payment-types';
import { joinURL } from 'ufo';
import { HelpOutline, OpenInNewOutlined } from '@mui/icons-material';
import Currency from '../currency';
import { formatSmartDuration, TimeUnit } from '../../libs/dayjs';
import { MAX_SAFE_AMOUNT } from '../../libs/util';

const fetchCycleAmount = (
  subscriptionId: string,
  params: { overdraftProtection: boolean }
): Promise<{ amount: string; gas: string; currency: TPaymentCurrency }> => {
  return api.get(`/api/subscriptions/${subscriptionId}/cycle-amount`, { params }).then((res: any) => res.data);
};

function safeAdd(currency: { decimal: number }, ...numbers: string[]) {
  if (!numbers.length) return '0';

  const decimal = currency?.decimal || 18;
  const sum = numbers.reduce((total, num) => {
    if (!num || typeof num !== 'string' || !/^-?\d*\.?\d*$/.test(num.trim())) {
      return total;
    }

    const cleanNum = num.trim();
    if (cleanNum === '' || cleanNum === '-') {
      return total;
    }

    try {
      const unitAmount = fromTokenToUnit(cleanNum, decimal);
      return new BN(total).add(new BN(unitAmount));
    } catch (error) {
      // 转换失败时也当作 0 处理
      return total;
    }
  }, new BN(0));

  return fromUnitToToken(sum.toString(), decimal);
}

type OverdraftProtectionDialogProps = {
  value: {
    enabled: boolean;
    remaining: string;
    unused: string;
    used: string;
  };
  loading: boolean;
  onSave: (data: { enabled: boolean; additionalCount?: number; returnRemaining?: boolean }) => Promise<void>;
  onCancel: EventHandler<any>;
  open: boolean;
  stakingAddress?: string;
  payerAddress?: string;
  currency: {
    symbol: string;
    logo: string;
    decimal: number;
    maximum_precision?: number;
  };
  subscription: TSubscriptionExpanded;
  initValues?: {
    enabled: boolean;
    return_stake: boolean;
  } | null;
};

export default function OverdraftProtectionDialog({
  value,
  loading,
  onSave,
  onCancel,
  open,
  stakingAddress = '',
  payerAddress = '',
  currency,
  subscription,
  initValues = null,
}: OverdraftProtectionDialogProps) {
  const { t, locale } = useLocaleContext();
  const { isMobile } = useMobile();
  const [customAmount, setCustomAmount] = useState(false);
  const [presetAmounts, setPresetAmounts] = useState<{ amount: string; cycles: number; label: string }[]>([]);

  const {
    data: cycleAmount = {
      amount: '0',
      gas: '0',
    },
    loading: cycleAmountLoading,
  } = useRequest(
    () =>
      fetchCycleAmount(subscription.id, {
        overdraftProtection: true,
      }),
    {
      refreshDeps: [subscription.id],
      onSuccess: (data) => {
        const presets = (() => {
          const { interval, interval_count: intervalCount } = subscription.pending_invoice_item_interval;

          switch (interval) {
            case 'hour':
              return [
                { cycles: Math.ceil(24 / intervalCount), label: '1 day' },
                { cycles: Math.ceil((24 * 7) / intervalCount), label: '1 week' },
                { cycles: Math.ceil((24 * 30) / intervalCount), label: '1 month' },
                { cycles: Math.ceil((24 * 90) / intervalCount), label: '3 months' },
                { cycles: Math.ceil((24 * 180) / intervalCount), label: '6 months' },
              ];
            case 'day':
              return [
                { cycles: Math.ceil(7 / intervalCount), label: '1 week' },
                { cycles: Math.ceil(30 / intervalCount), label: '1 month' },
                { cycles: Math.ceil(90 / intervalCount), label: '3 months' },
                { cycles: Math.ceil(180 / intervalCount), label: '6 months' },
                { cycles: Math.ceil(365 / intervalCount), label: '1 year' },
              ];
            default:
              return [
                { cycles: 1, label: '1x' },
                { cycles: 2, label: '2x' },
                { cycles: 3, label: '6x' },
                { cycles: 6, label: '6x' },
                { cycles: 12, label: '12x' },
              ];
          }
        })();

        const getCycleAmount = (cycles: number) =>
          fromUnitToToken(new BN(data.amount).mul(new BN(cycles)).toString(), data?.currency?.decimal);

        setPresetAmounts(
          presets.map(({ cycles, label }) => ({
            amount: getCycleAmount(cycles),
            cycles,
            label,
          }))
        );
      },
    }
  );

  const methods = useForm<{
    enabled: boolean;
    return_stake: boolean;
    amount: string;
  }>({
    defaultValues: {
      enabled: !!subscription.overdraft_protection?.enabled,
      return_stake: false,
      amount: '0',
      ...(initValues || {}),
    },
    mode: 'onChange',
  });

  const isEnabled = methods.watch('enabled');
  const amount = methods.watch('amount');

  const estimateAmount = fromUnitToToken(cycleAmount.amount, currency?.decimal);
  const availableAmount = fromUnitToToken(value.unused, currency?.decimal);
  const dueAmount = fromUnitToToken(value.used, currency?.decimal);
  const minStake = fromUnitToToken(new BN(cycleAmount.amount).sub(new BN(value.unused)).toString(), currency?.decimal);

  const handleCustomSelect = () => {
    setCustomAmount(true);
    methods.setValue('amount', Number(minStake) < 0 ? estimateAmount : minStake);
  };

  const onSubmit = () => {
    methods.handleSubmit(async (formData) => {
      await onSave(formData);
    })();
  };

  const formatEstimatedDuration = (cycles: number) => {
    const { interval, interval_count: intervalCount } = subscription.pending_invoice_item_interval;
    const totalIntervals = cycles * intervalCount;
    const availableUnitKeys = ['hour', 'day', 'week', 'month', 'year'];

    if (!availableUnitKeys.includes(interval)) {
      return t('customer.overdraftProtection.estimatedDuration', {
        duration: totalIntervals,
        unit: t('customer.overdraftProtection.intervals').toLowerCase(),
      });
    }
    return t('common.estimatedDuration', {
      duration: formatSmartDuration(totalIntervals, interval as TimeUnit, {
        t,
      }),
    });
  };

  const getStakingAddressURL = () => {
    return joinURL(
      subscription.paymentMethod?.settings.arcblock?.explorer_host as string,
      '/stakes',
      stakingAddress as string,
      '/tokens'
    );
  };

  useUnmount(() => {
    if (methods) {
      methods.reset();
    }
  });

  const handleClose = (e: any) => {
    methods.reset();
    onCancel(e);
  };

  return (
    <Dialog
      open={open}
      onClose={handleClose}
      maxWidth="sm"
      fullWidth
      className="base-dialog"
      title={
        <Stack
          direction="row"
          spacing={1}
          sx={{
            alignItems: 'center',
          }}>
          <Typography variant="h6" component="span">
            {t('customer.overdraftProtection.setting')}
          </Typography>
          <Link
            href="https://www.arcblock.io/content/blog/en/payment-kit-v117-sub-guard#listen-to-the-audio-overview"
            target="_blank"
            rel="noopener noreferrer"
            underline="hover"
            sx={{
              display: 'flex',
              alignItems: 'center',
              gap: 0.5,
              fontSize: '14px',
              fontWeight: 'normal',
              ml: 1,
              color: 'text.link',
              '&:hover': { color: 'primary.main' },
              ...(isMobile ? { fontSize: '12px' } : {}),
            }}>
            <Tooltip title={t('customer.overdraftProtection.learnMore')} placement="top">
              <HelpOutline
                fontSize="small"
                sx={{
                  fontSize: '16px',
                  color: 'text.secondary',
                  cursor: 'pointer',
                  '&:hover': { color: 'primary.main' },
                }}
              />
            </Tooltip>
          </Link>
        </Stack>
      }
      actions={
        <Stack direction="row" spacing={2}>
          <Button variant="outlined" onClick={handleClose}>
            {t('common.cancel')}
          </Button>
          <Button variant="contained" color="primary" disabled={loading} onClick={onSubmit}>
            {loading && <CircularProgress size={20} sx={{ mr: 1 }} />}
            {t('common.submit')}
          </Button>
        </Stack>
      }>
      <Stack
        sx={{
          gap: 2,
        }}>
        <Alert severity="info">
          {value.used !== '0' && !isEnabled ? (
            <>{t('customer.overdraftProtection.disableConfirm')}</>
          ) : (
            <Box>
              {t('customer.overdraftProtection.tip')}
              <Tooltip
                title={t('customer.overdraftProtection.ruleTip', {
                  gas: fromUnitToToken(cycleAmount.gas, currency?.decimal),
                  symbol: currency.symbol,
                })}
                placement="top">
                <Typography variant="body2" sx={{ color: 'text.link', cursor: 'pointer', mt: 1 }}>
                  {t('customer.overdraftProtection.rule')}
                </Typography>
              </Tooltip>
            </Box>
          )}
        </Alert>

        <Stack
          spacing={2}
          direction="row"
          sx={{
            alignItems: 'center',
          }}>
          <Typography
            variant="subtitle1"
            sx={{
              color: 'text.secondary',
            }}>
            {t('customer.overdraftProtection.title')}
          </Typography>
          <FormControlLabel
            control={<Switch checked={isEnabled} onChange={(e) => methods.setValue('enabled', e.target.checked)} />}
            label=""
          />
        </Stack>

        {isEnabled ? (
          <Stack
            sx={{
              gap: 1,
              mt: '-8px',
            }}>
            {payerAddress && (
              <Stack
                sx={
                  isMobile
                    ? {
                        flexDirection: 'column',
                        gap: 1,
                      }
                    : {
                        flexDirection: 'row',
                        alignItems: 'center',
                        gap: 2,
                      }
                }>
                <Typography
                  variant="subtitle2"
                  sx={{
                    color: 'text.secondary',
                  }}>
                  {t('customer.overdraftProtection.payerAddress')}
                </Typography>
                <Typography variant="body2" sx={{ wordBreak: 'break-all', fontFamily: 'monospace', fontWeight: '700' }}>
                  {payerAddress}
                </Typography>
              </Stack>
            )}

            {stakingAddress && (
              <Stack
                sx={
                  isMobile
                    ? {
                        flexDirection: 'column',
                        gap: 1,
                      }
                    : {
                        flexDirection: 'row',
                        alignItems: 'center',
                        gap: 2,
                      }
                }>
                <Typography
                  variant="subtitle2"
                  sx={{
                    color: 'text.secondary',
                  }}>
                  {t('customer.overdraftProtection.stakingAddress')}
                </Typography>
                <Link
                  href={getStakingAddressURL()}
                  target="_blank"
                  rel="noopener noreferrer"
                  sx={{
                    wordBreak: 'break-all',
                    fontFamily: 'monospace',
                    fontWeight: '700',
                    textDecoration: 'none',
                    color: 'text.link',
                    display: 'flex',
                    flexWrap: 'wrap',
                    alignItems: 'center',
                    gap: 1,
                  }}>
                  {stakingAddress}
                  {!isMobile && <OpenInNewOutlined fontSize="small" />}
                </Link>
              </Stack>
            )}

            <Typography
              variant="body2"
              sx={{
                color: 'text.secondary',
              }}>
              {(() => {
                if (Number(dueAmount) > 0 && !value.enabled) {
                  return t('customer.overdraftProtection.remainingNotEnough', {
                    due: dueAmount,
                    symbol: currency.symbol,
                    min: Number(minStake) < 0 ? estimateAmount : minStake,
                    unused: availableAmount,
                  });
                }
                if (value.remaining === '0') {
                  return t('customer.overdraftProtection.noRemaining', {
                    estimateAmount,
                    symbol: currency.symbol,
                  });
                }
                return t('customer.overdraftProtection.remaining', {
                  amount: availableAmount,
                  symbol: currency.symbol,
                  estimateAmount,
                });
              })()}
            </Typography>

            <Grid
              container
              spacing={2}
              sx={{
                ml: -2,
                mt: -1,
              }}>
              {cycleAmountLoading ? (
                // 加载状态的占位
                <>
                  {[1, 2, 3, 4, 5].map((key) => (
                    <Grid size={{ xs: 6, sm: 4 }} key={key}>
                      <Card variant="outlined" sx={{ height: '100%' }}>
                        <CardActionArea sx={{ height: '100%', p: 1 }}>
                          <Stack
                            spacing={1}
                            sx={{
                              alignItems: 'center',
                            }}>
                            <Skeleton variant="rectangular" width={80} height={32} />
                            <Skeleton width={100} />
                          </Stack>
                        </CardActionArea>
                      </Card>
                    </Grid>
                  ))}
                  <Grid size={{ xs: 6, sm: 4 }}>
                    <Card variant="outlined" sx={{ height: '100%' }}>
                      <CardActionArea sx={{ height: '100%', p: 2 }}>
                        <Stack
                          spacing={1}
                          sx={{
                            alignItems: 'center',
                          }}>
                          <Skeleton variant="rectangular" width={80} height={24} />
                        </Stack>
                      </CardActionArea>
                    </Card>
                  </Grid>
                </>
              ) : (
                <>
                  {presetAmounts.map(({ amount: presetAmount, cycles }) => (
                    <Grid size={{ xs: 6, sm: 4 }} key={presetAmount}>
                      <Card
                        variant="outlined"
                        sx={{
                          height: '100%',
                          transition: 'all 0.3s',
                          cursor: 'pointer',
                          '&:hover': {
                            transform: 'translateY(-4px)',
                            boxShadow: 3,
                          },
                          ...(amount === presetAmount && !customAmount
                            ? { borderColor: 'primary.main', borderWidth: 1 }
                            : {}),
                        }}>
                        <CardActionArea
                          onClick={() => {
                            methods.setValue('amount', presetAmount);
                            setCustomAmount(false);
                          }}
                          sx={{ height: '100%', p: 1 }}>
                          <Stack
                            spacing={1}
                            sx={{
                              alignItems: 'center',
                            }}>
                            <Typography variant="h6" sx={{ fontWeight: 600 }}>
                              {presetAmount} {currency.symbol}
                            </Typography>
                            <Typography
                              variant="caption"
                              sx={{
                                color: 'text.secondary',
                              }}>
                              {formatEstimatedDuration(cycles)}
                            </Typography>
                          </Stack>
                        </CardActionArea>
                      </Card>
                    </Grid>
                  ))}
                  <Grid size={{ xs: 6, sm: 4 }}>
                    <Card
                      variant="outlined"
                      sx={{
                        height: '100%',
                        transition: 'all 0.3s',
                        cursor: 'pointer',
                        '&:hover': {
                          transform: 'translateY(-4px)',
                          boxShadow: 3,
                        },
                        ...(customAmount ? { borderColor: 'primary.main', borderWidth: 1 } : {}),
                      }}>
                      <CardActionArea onClick={handleCustomSelect} sx={{ height: '100%', p: 2 }}>
                        <Stack
                          spacing={1}
                          sx={{
                            alignItems: 'center',
                          }}>
                          <Typography variant="h6" sx={{ fontWeight: 600 }}>
                            {t('common.custom')}
                          </Typography>
                        </Stack>
                      </CardActionArea>
                    </Card>
                  </Grid>
                </>
              )}
            </Grid>

            {customAmount && (
              <Stack spacing={2} sx={{ mt: 1 }}>
                <FormControl fullWidth>
                  <TextField
                    {...methods.register('amount', {
                      required: true,
                      validate: (val) => {
                        const required = Number(minStake) < 0 ? Number(estimateAmount) : Number(minStake);
                        if (Number(val) < required) {
                          return t('customer.overdraftProtection.min', {
                            min: required,
                            symbol: currency.symbol,
                          });
                        }
                        if (Number(val) > MAX_SAFE_AMOUNT) {
                          return t('common.maxAmount', {
                            max: MAX_SAFE_AMOUNT,
                          });
                        }
                        const validPrecision = formatAmountPrecisionLimit(
                          val.toString(),
                          locale,
                          currency?.maximum_precision || 6
                        );
                        if (validPrecision) {
                          return validPrecision;
                        }
                        return true;
                      },
                    })}
                    label={t('common.amount')}
                    type="number"
                    error={!!methods.formState.errors.amount}
                    helperText={methods.formState.errors.amount?.message}
                    fullWidth
                    variant="outlined"
                    slotProps={{
                      input: {
                        endAdornment: (
                          <Box sx={{ ml: 1, display: 'flex', alignItems: 'center' }}>
                            <Currency logo={currency.logo} name={currency.symbol} />
                          </Box>
                        ),
                      },
                      htmlInput: {
                        min: 0,
                        max: MAX_SAFE_AMOUNT,
                        step: Number(estimateAmount),
                      },
                    }}
                  />
                </FormControl>
              </Stack>
            )}
            {amount && Number(amount) > 0 && Number(estimateAmount) > 0 && !methods.formState.errors.amount && (
              <Typography
                variant="body2"
                sx={{
                  fontSize: 12,
                  color: 'text.lighter',
                  mt: '8px !important',
                }}>
                {t('customer.overdraftProtection.total', {
                  total: safeAdd(currency, amount, availableAmount),
                  symbol: currency.symbol,
                })}
                {formatEstimatedDuration(
                  Math.floor(Number(safeAdd(currency, amount, availableAmount)) / Number(estimateAmount))
                )}
              </Typography>
            )}
          </Stack>
        ) : (
          Number(availableAmount) > 0 && (
            <Stack
              direction="row"
              sx={{
                alignItems: 'flex-start',
                gap: 2,
              }}>
              <Typography
                variant="subtitle2"
                sx={{
                  color: 'text.secondary',
                  height: 39,
                  display: 'flex',
                  alignItems: 'center',
                  width: 56,
                }}>
                {t('customer.overdraftProtection.stake')}
              </Typography>
              <RadioGroup
                aria-labelledby="return-stake-group-label"
                value={methods.watch('return_stake')}
                onChange={(e) => methods.setValue('return_stake', e.target.value === 'true')}>
                <FormControlLabel
                  value={false}
                  control={<Radio />}
                  label={t('customer.overdraftProtection.keepStake')}
                />
                <FormControlLabel
                  value
                  control={<Radio color="warning" />}
                  label={t('customer.overdraftProtection.returnStake')}
                />
              </RadioGroup>
            </Stack>
          )
        )}
      </Stack>
    </Dialog>
  );
}
