import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import { usePaymentContext } from '@blocklet/payment-react';
import { AddOutlined, ArrowDropDown } from '@mui/icons-material';
import { ListSubheader, MenuItem, Select, Stack, SxProps, Typography } from '@mui/material';
import { useState, useEffect, useMemo } from 'react';
import type { LiteralUnion } from 'type-fest';

import Currency from '../currency';

type Props = {
  mode: LiteralUnion<'waiting' | 'selecting' | 'selected', string>;
  hasSelected: (currency: any) => boolean;
  onSelect: (currencyId: string) => void;
  value: string;
  width?: string;
  disabled?: boolean;
  selectSX?: SxProps;
  currencyFilter?: (currency: any) => boolean;
  hideMethod?: boolean;
  includeAllOption?: boolean;
  allOption?: {
    value: string;
    label: string;
  };
  selectedSx?: SxProps;
};

export default function CurrencySelect({
  mode: initialMode,
  hasSelected,
  onSelect,
  value,
  width = '100%',
  disabled = false,
  selectSX = {},
  currencyFilter = () => true,
  hideMethod = false,
  includeAllOption = false,
  allOption = { value: 'all', label: 'All' },
  selectedSx = {},
}: Props) {
  const { t } = useLocaleContext();
  const { settings } = usePaymentContext();
  const [mode, setMode] = useState(initialMode);

  const currencyGroups = useMemo(() => {
    return (settings.paymentMethods || []).map((method) => ({
      method,
      currencies: (method.payment_currencies || []).map((currency: any) => ({
        ...currency,
        method,
      })),
    }));
  }, [settings.paymentMethods]);

  const allCurrencies = useMemo(() => currencyGroups.flatMap((group) => group.currencies), [currencyGroups]);

  useEffect(() => {
    if (value && initialMode === 'selected' && allCurrencies.length > 0) {
      const currency = allCurrencies.find((c) => c.id === value);
      if (currency && !hasSelected(currency)) {
        const timer = setTimeout(() => {
          onSelect(value);
        }, 0);
        return () => clearTimeout(timer);
      }
    }
    return undefined;
  }, [value, initialMode, allCurrencies, hasSelected]);

  const handleSelect = (e: any) => {
    if (disabled) {
      return;
    }
    setMode(initialMode);
    onSelect(e.target.value);
  };

  const selectedCurrency = allCurrencies.find((x) => x.id === value);

  const selectedPaymentMethod = currencyGroups.find((group) =>
    group.currencies.some((currency) => currency.id === value)
  )?.method;

  const availableGroups = useMemo(() => {
    return currencyGroups
      .map((group) => ({
        method: group.method,
        currencies: group.currencies.filter((currency) => currencyFilter(currency) && !hasSelected(currency)),
      }))
      .filter((group) => group.currencies.length > 0);
  }, [currencyGroups, hasSelected]);

  const canSelect = availableGroups.length > 0 && !disabled;

  if (mode === 'selected') {
    const isAllSelected = includeAllOption && value === allOption.value;
    let displayLabel = '';
    if (isAllSelected) {
      displayLabel = allOption.label;
    } else if (selectedCurrency?.symbol) {
      displayLabel = hideMethod
        ? selectedCurrency.symbol
        : `${selectedCurrency.symbol} (${selectedPaymentMethod?.name || ''})`;
    } else if (!hideMethod && selectedPaymentMethod?.name) {
      displayLabel = `(${selectedPaymentMethod.name})`;
    }

    return (
      <Typography
        onClick={() => {
          if (canSelect) {
            setMode('selecting');
          }
        }}
        sx={{
          cursor: canSelect ? 'pointer' : 'default',
          display: 'inline-flex',
          minWidth: '120px',
          justifyContent: 'flex-end',
          textAlign: 'right',
          width: '100%',
          ...selectedSx,
        }}>
        {displayLabel}
        {canSelect && <ArrowDropDown sx={{ color: 'text.secondary', fontSize: 21 }} />}
      </Typography>
    );
  }

  if (!canSelect) {
    return null;
  }

  if (mode === 'selecting') {
    return (
      <Select
        size="small"
        value={value}
        renderValue={() => {
          if (includeAllOption && value === allOption.value) {
            return (
              <Typography variant="body1" sx={{ display: 'inline-flex', fontSize: '12px', color: 'text.secondary' }}>
                {allOption.label}
              </Typography>
            );
          }

          const symbolText = selectedCurrency?.symbol || '';
          const methodText = !hideMethod && selectedPaymentMethod?.name ? ` (${selectedPaymentMethod.name})` : '';

          return (
            <Typography variant="body1" sx={{ display: 'inline-flex', fontSize: '12px', color: 'text.secondary' }}>
              {`${symbolText}${methodText}`.trim()}
            </Typography>
          );
        }}
        onChange={handleSelect}
        open
        sx={{ width, ...selectSX }}
        disabled={disabled}
        onClose={() => setMode(initialMode)}>
        {includeAllOption ? (
          <MenuItem value={allOption.value}>
            <Typography
              sx={{
                fontWeight: 'bold',
              }}>
              {allOption.label}
            </Typography>
          </MenuItem>
        ) : null}
        {availableGroups.flatMap((group) => {
          const header = hideMethod ? null : (
            <ListSubheader
              key={group.method.id}
              sx={{ fontSize: '0.875rem', color: 'text.secondary', lineHeight: '2.1875rem' }}>
              {group.method.name}
            </ListSubheader>
          );

          const items = group.currencies.map((currency) => (
            <MenuItem key={currency.id} sx={{ pl: 3 }} value={currency.id}>
              <Stack direction="row" sx={{ width: '100%', justifyContent: 'space-between', gap: 2 }}>
                {hideMethod ? null : <Currency logo={currency.logo} name={currency.name} />}
                <Typography
                  sx={{
                    fontWeight: hideMethod ? 'normal' : 'bold',
                  }}>
                  {currency.symbol}
                </Typography>
              </Stack>
            </MenuItem>
          ));

          return header ? [header, ...items] : items;
        })}
      </Select>
    );
  }

  return (
    <span>
      <Stack
        direction="row"
        onClick={() => setMode('selecting')}
        sx={{
          alignItems: 'center',
          cursor: 'pointer',
          display: 'inline-flex',
        }}>
        <AddOutlined color="primary" />
        <Typography color="primary">{t('admin.price.currency.add')}</Typography>
      </Stack>
    </span>
  );
}
