import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import { findCurrency, formatPrice, getPriceCurrencyOptions, usePaymentContext } from '@blocklet/payment-react';
import type { TProductExpanded } from '@blocklet/payment-types';
import { AddOutlined } from '@mui/icons-material';
import { Avatar, Box, ListSubheader, MenuItem, Select, Stack, Typography } from '@mui/material';
import cloneDeep from 'lodash/cloneDeep';
import { useRef, useState } from 'react';
import type { LiteralUnion } from 'type-fest';

import Empty from '@arcblock/ux/lib/Empty';
import useBus, { EventAction } from 'use-bus';
import { useProductsContext } from '../../contexts/products';

type Props = {
  mode: LiteralUnion<'waiting' | 'selecting' | 'inline', string>;
  hasSelected: (price: any) => boolean;
  onSelect: (priceId: string) => void;
  addProduct?: boolean;
  filterPrice?: (price: any) => boolean;
};

const filterPrices = (
  product: TProductExpanded,
  hasSelected: (price: any) => boolean,
  filterPrice?: (price: any) => boolean
) => {
  product.prices = product.prices.filter((x) => {
    const isActive = x.active;
    const notSelected = !hasSelected(x);
    const customFilter = filterPrice ? filterPrice(x) : true;
    return isActive && notSelected && customFilter;
  });
  return product;
};

const filterProducts = (
  products: TProductExpanded[],
  hasSelected: (price: any) => boolean,
  filterPrice?: (price: any) => boolean
) => {
  const filtered = cloneDeep(products).map((x) => filterPrices(x, hasSelected, filterPrice));
  return filtered.filter((x) => x.prices.length);
};

export default function ProductSelect({
  mode: initialMode,
  hasSelected,
  onSelect,
  addProduct = true,
  filterPrice = () => true,
}: Props) {
  const { t } = useLocaleContext();
  const [mode, setMode] = useState(initialMode);
  const { products } = useProductsContext();
  const { settings } = usePaymentContext();
  const [value, setValue] = useState('');
  const valueRef = useRef(value);
  const size = { width: 16, height: 16 };

  const handleSelect = (e: any) => {
    setValue(e.target.value);
    valueRef.current = e.target.value;
    setMode('waiting');
    onSelect(e.target.value);
  };

  useBus(
    (event: EventAction) => event.type === 'product.select.price.removed',
    (event: EventAction) => {
      if (valueRef.current === event.priceId) {
        setValue('');
        valueRef.current = '';
      }
    }
  );

  const items = (callback?: any) => {
    const filteredProducts = filterProducts(products, hasSelected, filterPrice);

    if (filteredProducts.length === 0) {
      return <Empty>{t('admin.product.empty')}</Empty>;
    }

    return filteredProducts.map((product) => [
      <ListSubheader key={product.id} sx={{ fontSize: '0.875rem', color: 'text.secondary', lineHeight: '2.1875rem' }}>
        <Stack
          direction="row"
          spacing={0.5}
          sx={{
            alignItems: 'center',
          }}>
          {product.images[0] ? (
            <Avatar src={product.images[0]} alt={product.name} variant="square" sx={size} />
          ) : (
            <Avatar variant="square" sx={size}>
              {product.name.slice(0, 1)}
            </Avatar>
          )}
          <Typography component="span">{product.name}</Typography>
        </Stack>
      </ListSubheader>,
      ...product.prices.map((price: any) => {
        const currency = findCurrency(settings.paymentMethods, price.currency_id ?? '') || settings.baseCurrency;
        return (
          <MenuItem
            key={price.id}
            sx={{ pl: 4.5 }}
            value={price.id}
            onClick={() => {
              if (callback) {
                price.productName = product.name;
                price.displayPrice = formatPrice(price, currency!);
                callback(price);
              }
            }}>
            <Typography
              sx={{
                color: 'text.primary',
              }}>
              {formatPrice(price, currency!)}
            </Typography>
            <Typography
              sx={{
                color: 'text.secondary',
                ml: 2,
              }}>
              {getPriceCurrencyOptions(price).length > 1
                ? ` +${getPriceCurrencyOptions(price).length - 1} more currencies`
                : ''}
            </Typography>
          </MenuItem>
        );
      }),
    ]);
  };

  if (mode === 'inline') {
    return <>{items(onSelect)}</>;
  }

  if (mode === 'selecting') {
    return (
      <Select
        fullWidth
        size="small"
        onChange={handleSelect}
        value={value}
        MenuProps={{
          style: { maxHeight: 480 },
        }}>
        {addProduct && (
          <MenuItem value="add">
            <AddOutlined />
            {t('admin.product.add')}
          </MenuItem>
        )}
        {items()}
      </Select>
    );
  }

  return (
    <Box sx={{ cursor: 'pointer' }} onClick={() => setMode('selecting')}>
      <Typography color="primary">{t('admin.paymentLink.addProduct')}</Typography>
    </Box>
  );
}
