import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import type { DonationSettings, TLineItemExpanded, TPaymentCurrency } from '@blocklet/payment-types';
import { Avatar, Box, Card, CardActionArea, Grid, Stack, TextField, Typography, IconButton } from '@mui/material';
import AutoAwesomeIcon from '@mui/icons-material/AutoAwesome';
import { useSetState } from 'ahooks';
import { useEffect, useRef } from 'react';

import { formatAmountPrecisionLimit } from '../libs/util';
import { usePaymentContext } from '../contexts/payment';
import { usePreventWheel } from '../hooks/scroll';
import { useTabNavigation } from '../hooks/keyboard';

// LocalStorage key base for preset selection
const DONATION_PRESET_KEY_BASE = 'payment-donation-preset';
const DONATION_CUSTOM_AMOUNT_KEY_BASE = 'payment-donation-custom-amount';

const formatAmount = (amount: string | number): string => {
  return String(amount);
};

export default function ProductDonation({
  item,
  settings,
  onChange,
  currency,
}: {
  item: TLineItemExpanded;
  settings: DonationSettings;
  onChange: Function;
  currency: TPaymentCurrency;
}) {
  const { t, locale } = useLocaleContext();
  const { setPayable, session } = usePaymentContext();
  usePreventWheel();
  const presets = (settings?.amount?.presets || []).map(formatAmount);

  const getUserStorageKey = (base: string) => {
    const userDid = session?.user?.did;
    return userDid ? `${base}:${userDid}` : base;
  };

  const getSavedCustomAmount = () => {
    try {
      return localStorage.getItem(getUserStorageKey(DONATION_CUSTOM_AMOUNT_KEY_BASE)) || '';
    } catch (e) {
      console.warn('Failed to access localStorage', e);
      return '';
    }
  };

  const getDefaultPreset = () => {
    try {
      const savedPreset = localStorage.getItem(getUserStorageKey(DONATION_PRESET_KEY_BASE));
      if (savedPreset) {
        if (presets.includes(formatAmount(savedPreset))) {
          return formatAmount(savedPreset);
        }
        if (savedPreset === 'custom' && supportCustom) {
          return 'custom';
        }
      }
    } catch (e) {
      console.warn('Failed to access localStorage', e);
    }
    if (presets.length > 0) {
      const middleIndex = Math.floor(presets.length / 2);
      return presets[middleIndex];
    }
    return '0';
  };

  const supportPreset = presets.length > 0;
  const supportCustom = !!settings?.amount?.custom;
  const defaultPreset = getDefaultPreset();
  const defaultCustomAmount = defaultPreset === 'custom' ? getSavedCustomAmount() : '';

  const [state, setState] = useSetState({
    selected: defaultPreset === 'custom' ? '' : defaultPreset,
    input: defaultCustomAmount,
    custom: !supportPreset || defaultPreset === 'custom',
    error: '',
    animating: false,
  });

  const customInputRef = useRef<HTMLInputElement>(null);
  const containerRef = useRef<HTMLDivElement>(null);

  const handleSelect = (amount: string) => {
    setPayable(true);
    setState({ selected: formatAmount(amount), custom: false, error: '' });
    onChange({ priceId: item.price_id, amount: formatAmount(amount) });
    localStorage.setItem(getUserStorageKey(DONATION_PRESET_KEY_BASE), formatAmount(amount));
  };

  const handleCustomSelect = () => {
    // Set custom mode and prepare for random amount
    setState({
      custom: true,
      selected: '',
      animating: true,
    });

    // Prepare random amount range with correctly sorted presets
    const hasPresets = presets.length > 0;
    let sortedPresets: number[] = [];
    if (hasPresets) {
      sortedPresets = [...presets].map((p) => parseFloat(p)).sort((a, b) => a - b);
    }

    // Get min and max values for random amount
    const minPreset = hasPresets ? sortedPresets[sortedPresets.length - 1] : 1;
    let maxPreset = hasPresets ? sortedPresets[sortedPresets.length - 1] * 5 : 100;
    const systemMax = settings.amount.maximum ? parseFloat(settings.amount.maximum) : Infinity;
    maxPreset = Math.min(maxPreset, systemMax);

    // Detect precision from existing presets
    const detectPrecision = () => {
      let maxPrecision = 2; // Default to 2 decimal places for currency

      // If no presets, default to 0 precision (integers) for simplicity
      if (!hasPresets) return 0;

      const allIntegers = presets.every((preset) => {
        const num = parseFloat(preset);
        return num === Math.floor(num);
      });

      if (allIntegers) return 0;

      presets.forEach((preset) => {
        const decimalPart = preset.toString().split('.')[1];
        if (decimalPart) {
          maxPrecision = Math.max(maxPrecision, decimalPart.length);
        }
      });

      return maxPrecision;
    };

    const precision = detectPrecision();

    // Generate random amount with matching precision
    let randomAmount;
    if (precision === 0) {
      randomAmount = (Math.round(Math.random() * (maxPreset - minPreset) + minPreset) || 1).toString();
    } else {
      randomAmount = (Math.random() * (maxPreset - minPreset) + minPreset).toFixed(precision);
    }

    // Get starting value for animation - use either current input, cached value, or 0
    const startValue = state.input ? parseFloat(state.input) : 0;
    const targetValue = parseFloat(randomAmount);
    const difference = targetValue - startValue;

    // Animate value change
    const startTime = Date.now();
    const duration = 800;

    const updateCounter = () => {
      const currentTime = Date.now();
      const elapsed = currentTime - startTime;

      if (elapsed < duration) {
        const progress = elapsed / duration;
        const intermediateValue = startValue + difference * progress;
        const currentValue =
          precision === 0 ? Math.floor(intermediateValue).toString() : intermediateValue.toFixed(precision);

        setState({ input: currentValue });
        requestAnimationFrame(updateCounter);
      } else {
        // Animation complete
        setState({
          input: randomAmount,
          animating: false,
          error: '',
        });
        onChange({ priceId: item.price_id, amount: formatAmount(randomAmount) });
        setPayable(true);
        localStorage.setItem(getUserStorageKey(DONATION_CUSTOM_AMOUNT_KEY_BASE), formatAmount(randomAmount));

        setTimeout(() => {
          customInputRef.current?.focus();
        }, 200);
      }
    };

    requestAnimationFrame(updateCounter);
    localStorage.setItem(getUserStorageKey(DONATION_PRESET_KEY_BASE), 'custom');
  };

  const handleTabSelect = (selectedItem: string | 'custom') => {
    if (selectedItem === 'custom') {
      handleCustomSelect();
    } else {
      handleSelect(selectedItem as string);
    }
  };

  const { handleKeyDown } = useTabNavigation(presets, handleTabSelect, {
    includeCustom: supportCustom,
    currentValue: state.custom ? undefined : state.selected,
    isCustomSelected: state.custom,
    enabled: true,
    selector: '.tab-navigable-card button',
    containerRef,
  });

  useEffect(() => {
    const currentPreset = getDefaultPreset();
    const isCustom = currentPreset === 'custom';

    setState({
      selected: isCustom ? '' : currentPreset,
      custom: !supportPreset || currentPreset === 'custom',
      input: defaultCustomAmount,
      error: '',
    });

    if (!isCustom) {
      onChange({ priceId: item.price_id, amount: currentPreset });
      setPayable(true);
    } else if (defaultCustomAmount) {
      onChange({ priceId: item.price_id, amount: defaultCustomAmount });
      setPayable(true);
    } else {
      setPayable(false);
    }
  }, [settings.amount.preset, settings.amount.presets, supportPreset]); // eslint-disable-line

  useEffect(() => {
    if (containerRef.current) {
      containerRef.current.focus();
    }
    if (state.custom) {
      setTimeout(() => {
        customInputRef.current?.focus();
      }, 0);
    }
  }, [state.custom]);

  const handleInput = (event: any) => {
    const { value } = event.target;
    const min = parseFloat(settings.amount.minimum || '0');
    const max = settings.amount.maximum ? parseFloat(settings.amount.maximum) : Infinity;
    const precision = currency?.maximum_precision || 6;

    if (formatAmountPrecisionLimit(value, locale)) {
      setState({ input: value, error: formatAmountPrecisionLimit(value, locale, precision) });
      setPayable(false);
      return;
    }

    if (value < min || value > max) {
      setState({ input: value, error: t('payment.checkout.donation.between', { min, max }) });
      setPayable(false);
      return;
    }
    setPayable(true);
    setState({ error: '', input: value });
    onChange({ priceId: item.price_id, amount: formatAmount(value) });
    localStorage.setItem(getUserStorageKey(DONATION_CUSTOM_AMOUNT_KEY_BASE), formatAmount(value));
  };

  return (
    <Box
      ref={containerRef}
      onKeyDown={handleKeyDown}
      tabIndex={0}
      sx={{
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'flex-start',
        gap: 1.5,
        outline: 'none',
      }}>
      {supportPreset && (
        <Grid container spacing={2}>
          {presets.map((amount) => (
            <Grid
              size={{
                xs: 6,
                sm: 3,
              }}
              key={amount}>
              <Card
                variant="outlined"
                className="tab-navigable-card"
                sx={{
                  minWidth: 115,
                  textAlign: 'center',
                  transition: 'all 0.3s',
                  cursor: 'pointer',
                  '&:hover': {
                    transform: 'translateY(-4px)',
                    boxShadow: 3,
                  },
                  '.MuiCardActionArea-focusHighlight': {
                    backgroundColor: 'transparent',
                  },
                  height: '42px',
                  ...(formatAmount(state.selected) === formatAmount(amount) && !state.custom
                    ? { borderColor: 'primary.main', borderWidth: 1 }
                    : {}),
                }}>
                <CardActionArea
                  onClick={() => handleSelect(amount)}
                  tabIndex={0}
                  aria-selected={formatAmount(state.selected) === formatAmount(amount) && !state.custom}>
                  <Stack
                    direction="row"
                    spacing={0.5}
                    sx={{
                      alignItems: 'center',
                      justifyContent: 'center',
                      py: 1.5,
                      px: 1.5,
                    }}>
                    <Avatar src={currency?.logo} sx={{ width: 16, height: 16, mr: 0.5 }} alt={currency?.symbol} />
                    <Typography
                      component="strong"
                      variant="h3"
                      sx={{
                        lineHeight: 1,
                        fontVariantNumeric: 'tabular-nums',
                        fontWeight: 400,
                      }}>
                      {amount}
                    </Typography>
                    <Typography
                      sx={{
                        lineHeight: 1,
                        fontSize: 14,
                        color: 'text.secondary',
                      }}>
                      {currency?.symbol}
                    </Typography>
                  </Stack>
                </CardActionArea>
              </Card>
            </Grid>
          ))}
          {supportCustom && (
            <Grid
              size={{
                xs: 6,
                sm: 3,
              }}
              key="custom">
              <Card
                variant="outlined"
                className="tab-navigable-card"
                sx={{
                  textAlign: 'center',
                  transition: 'all 0.3s',
                  cursor: 'pointer',
                  '&:hover': {
                    transform: 'translateY(-4px)',
                    boxShadow: 3,
                  },
                  '.MuiCardActionArea-focusHighlight': {
                    backgroundColor: 'transparent',
                  },
                  height: '42px',
                  ...(state.custom ? { borderColor: 'primary.main', borderWidth: 1 } : {}),
                }}>
                <CardActionArea onClick={handleCustomSelect} tabIndex={0} aria-selected={state.custom}>
                  <Stack
                    direction="row"
                    spacing={0.5}
                    sx={{
                      alignItems: 'center',
                      justifyContent: 'center',
                      py: 1.5,
                      px: 1.5,
                    }}>
                    <Typography
                      variant="h3"
                      sx={{
                        lineHeight: 1,
                        fontWeight: 400,
                      }}>
                      {t('common.custom')}
                    </Typography>
                  </Stack>
                </CardActionArea>
              </Card>
            </Grid>
          )}
        </Grid>
      )}
      {state.custom && (
        <TextField
          type="number"
          value={state.input}
          onChange={handleInput}
          margin="none"
          fullWidth
          error={!!state.error}
          helperText={state.error}
          inputRef={customInputRef}
          sx={{
            mt: defaultPreset !== '0' ? 0 : 1,
            '& .MuiInputBase-root': {
              transition: 'all 0.3s ease',
            },
            '& input[type=number]': {
              MozAppearance: 'textfield',
            },
            '& input[type=number]::-webkit-outer-spin-button': {
              WebkitAppearance: 'none',
              margin: 0,
            },
            '& input[type=number]::-webkit-inner-spin-button': {
              WebkitAppearance: 'none',
              margin: 0,
            },
            '& input': {
              transition: 'all 0.25s ease',
            },
          }}
          slotProps={{
            input: {
              endAdornment: (
                <Stack
                  direction="row"
                  spacing={0.5}
                  sx={{
                    alignItems: 'center',
                    ml: 1,
                  }}>
                  <IconButton
                    size="small"
                    onClick={handleCustomSelect}
                    disabled={state.animating}
                    sx={{
                      mr: 0.5,
                      opacity: state.animating ? 0.5 : 1,
                      transition: 'all 0.2s ease',
                      '&:hover': {
                        transform: 'scale(1.2)',
                        transition: 'transform 0.3s ease',
                      },
                    }}
                    aria-label={t('common.random')}>
                    <AutoAwesomeIcon fontSize="small" />
                  </IconButton>
                  <Avatar src={currency?.logo} sx={{ width: 16, height: 16 }} alt={currency?.symbol} />
                  <Typography>{currency?.symbol}</Typography>
                </Stack>
              ),
              autoComplete: 'off',
            },
          }}
          autoComplete="off"
        />
      )}
    </Box>
  );
}
