import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
import {
  api,
  findCurrency,
  formatPrice,
  getCustomerAvatar,
  useMobile,
  usePaymentContext,
} from '@blocklet/payment-react';
import type { TCustomer } from '@blocklet/payment-types';
import { Add, Close } from '@mui/icons-material';
import { Button, Menu, MenuItem, TextField } from '@mui/material';
import { Box, styled } from '@mui/system';
import { useEffect, useState } from 'react';

import { flatten } from 'lodash';
import { useRequest } from 'ahooks';
import { ProductsProvider, useProductsContext } from '../contexts/products';
import InfoCard from './info-card';
import ProductSelect from './payment-link/product-select';

const fetchUserData = (params: Record<string, any> = {}): Promise<{ list: TCustomer[]; count: number }> => {
  const search = new URLSearchParams();
  Object.keys(params).forEach((key) => {
    let v = params[key];
    if (key === 'q') {
      v = Object.entries(v)
        .map((x) => x.join(':'))
        .join(' ');
    }
    search.set(key, String(v));
  });
  return api.get(`api/customers?${search.toString()}`).then((res: any) => res.data);
};

const fetchSubscriptionItems = (params: Record<string, any> = {}): Promise<{ list: TCustomer[]; count: number }> => {
  const search = new URLSearchParams();
  Object.keys(params).forEach((key) => {
    const v = params[key];
    search.set(key, String(v));
  });
  return api.get(`api/subscription-items?${search.toString()}`).then((res: any) => res.data);
};

type Props = {
  search?: Record<string, any>;
  status?: string[];
  currency?: boolean;
  setSearch: (x: any) => void;
  donation?: string[];
  formatStatus?: (x: string) => string;
};

export default function FilterToolbar(rawProps: Props) {
  const props = Object.assign({}, defaultProps, rawProps);
  // eslint-disable-next-line react/prop-types
  const { setSearch, search, status, currency, donation, formatStatus = (v) => v } = props;
  const { isMobile } = useMobile();
  const isProduct = window.location.pathname.includes('product');
  const handleSearch = (obj: any) => {
    setSearch({
      ...search,
      ...obj,
      page: 1,
    });
  };

  return (
    <Root
      sx={{
        '.MuiTouchRipple-root': {
          display: 'none !important',
        },
      }}>
      <Box className="table-toolbar-left">
        <SearchStatus setSearch={handleSearch} search={search} status={status} formatStatus={formatStatus} />
        {!isMobile && (
          <>
            {/* eslint-disable-next-line react/prop-types */}
            {Array.isArray(donation) && donation?.length > 0 && (
              <SearchDonation setSearch={handleSearch} search={search} donation={donation} />
            )}
            {isProduct ? null : (
              <>
                <SearchCustomers search={search} setSearch={handleSearch} />
                {currency ? (
                  <SearchCurrency search={search} setSearch={handleSearch} />
                ) : (
                  <ProductsProvider>
                    <SearchProducts search={search} setSearch={handleSearch} />
                  </ProductsProvider>
                )}
              </>
            )}
          </>
        )}
      </Box>
    </Root>
  );
}

const defaultProps: Props = {
  search: {},
  status: [],
  currency: false,
  donation: [],
  formatStatus: (v: string) => v,
  setSearch: () => {},
};

function SearchStatus({
  status = defaultProps.status,
  search = defaultProps.search,
  setSearch,
  formatStatus = defaultProps.formatStatus,
}: Pick<Props, 'status' | 'search' | 'setSearch' | 'formatStatus'>) {
  const [show, setShow] = useState(null);
  const { t } = useLocaleContext();
  return (
    <section
      onClick={(e) => {
        setShow(e.currentTarget as any);
      }}>
      <Button className="option-btn" variant="text">
        {search!.status ? (
          <Close
            sx={{ color: 'text.secondary', cursor: 'pointer', fontSize: '1.05rem' }}
            onClick={(e) => {
              e.stopPropagation();
              setSearch({
                status: '',
              });
              setShow(null);
            }}
          />
        ) : (
          <Add sx={{ color: 'text.secondary', cursor: 'pointer', fontSize: '1.05rem' }} />
        )}
        {t('common.status')}
        <span>{formatStatus ? formatStatus(search!.status) : search!.status}</span>
      </Button>
      <Menu
        anchorEl={show}
        open={Boolean(show)}
        onClose={(e: any) => {
          e.stopPropagation();
          setShow(null);
        }}
        className="status-options">
        {status?.map((x: any) => (
          <MenuItem
            onClick={(e) => {
              e.stopPropagation();
              setSearch({
                status: x,
              });
              setShow(null);
            }}
            key={x}>
            {formatStatus ? formatStatus(x) : x}
          </MenuItem>
        ))}
      </Menu>
    </section>
  );
}

function filterCurrency(methods: any) {
  const out: any = {};
  methods?.forEach((m: any) => {
    const currencies = m.payment_currencies;
    currencies.forEach((c: any) => {
      out[c.symbol] = c.id;
    });
  });
  return out;
}

function SearchCurrency({ setSearch, search = defaultProps.search }: Pick<Props, 'setSearch' | 'search'>) {
  const [show, setShow] = useState(null);
  const { settings } = usePaymentContext();
  const currencies = filterCurrency(settings.paymentMethods);
  const { t } = useLocaleContext();

  return (
    <section
      onClick={(e) => {
        setShow(e.currentTarget as any);
      }}>
      <Button className="option-btn" variant="text">
        {search!.currency_id ? (
          <Close
            sx={{ color: 'text.secondary', cursor: 'pointer', fontSize: '1.05rem' }}
            onClick={(e) => {
              e.stopPropagation();
              setSearch({
                currency_id: '',
              });
              setShow(null);
            }}
          />
        ) : (
          <Add sx={{ color: 'text.secondary', cursor: 'pointer', fontSize: '1.05rem' }} />
        )}
        {t('common.currency')}
        <span>{Object.keys(currencies).find((x) => currencies[x] === search!.currency_id)}</span>
      </Button>
      <Menu
        anchorEl={show}
        open={Boolean(show)}
        onClose={(e: any) => {
          e.stopPropagation();
          setShow(null);
        }}
        className="status-options">
        {Object.keys(currencies).map((k: any) => (
          <MenuItem
            onClick={(e) => {
              e.stopPropagation();
              setSearch({
                currency_id: currencies[k],
              });
              setShow(null);
            }}
            key={k}>
            {k}
          </MenuItem>
        ))}
      </Menu>
    </section>
  );
}

function SearchCustomers({ setSearch, search = defaultProps.search }: Pick<Props, 'setSearch' | 'search'>) {
  const [customers, setCustomers] = useState<TCustomer[]>([]);
  const [show, setShow] = useState(null);
  const [searchText, setSearchText] = useState('');
  const { t } = useLocaleContext();

  const customerRequest = useRequest(
    (text: string) => {
      return fetchUserData({
        q: {
          'like-name': text,
          'like-email': text,
          'like-did': text,
          'like-metadata': text,
          'like-phone': text,
        },
        page: 1,
        pageSize: 10,
      });
    },
    {
      onSuccess: (data) => {
        setCustomers(data.list);
      },
      debounceWait: 500,
    }
  );

  useEffect(() => {
    customerRequest.run(searchText);
  }, [searchText]);

  return (
    <section>
      <Button
        className="option-btn"
        variant="text"
        onClick={(e) => {
          setShow(e.currentTarget as any);
        }}>
        {search!.customer_id ? (
          <Close
            sx={{ color: 'text.secondary', cursor: 'pointer', fontSize: '1.05rem' }}
            onClick={(e) => {
              e.stopPropagation();
              setSearch({
                customer_id: '',
              });
              setShow(null);
            }}
          />
        ) : (
          <Add sx={{ color: 'text.secondary', cursor: 'pointer', fontSize: '1.05rem' }} />
        )}
        {t('common.customer')}
        <span>{customers.find((x) => x.id === search!.customer_id)?.name}</span>
      </Button>

      <Menu
        anchorEl={show}
        open={Boolean(show)}
        onClose={(e: any) => {
          e.stopPropagation();
          setShow(null);
        }}>
        <Box sx={{ p: 1 }}>
          <TextField
            placeholder="Search customer"
            size="small"
            sx={{
              width: '100%',
            }}
            value={searchText}
            onChange={(e) => {
              setSearchText(e.target.value);
              e.stopPropagation();
            }}
            onClick={(e) => e.stopPropagation()}
            // Stop MUI <Menu>'s built-in letter-key navigation from stealing keystrokes
            // (it jumps to a MenuItem starting with the typed letter, which makes the
            // search field appear to "swallow" inputs like 'a'/'w'). See #1357.
            onKeyDown={(e) => e.stopPropagation()}
          />
        </Box>
        {customers.map((x: any) => (
          <MenuItem
            key={x.id}
            onClick={(e) => {
              e.stopPropagation();
              setSearch({
                customer_id: x.id,
              });
              setShow(null);
            }}>
            <InfoCard
              logo={getCustomerAvatar(x?.did, x?.updated_at, 48)}
              name={x.email}
              key={x.id}
              description={`${x.did.slice(0, 6)}...${x.did.slice(-6)}`}
            />
          </MenuItem>
        ))}
      </Menu>
    </section>
  );
}

function SearchProducts({ setSearch, search = defaultProps.search }: Pick<Props, 'setSearch' | 'search'>) {
  const [show, setShow] = useState(null);
  const { products } = useProductsContext();
  const { settings } = usePaymentContext();
  const defaultPrice =
    search?.price_id && products
      ? flatten(products.map((x) => x.prices)).find((x) => x.id === search?.price_id)
      : ({} as any);
  const [price, setPrice] = useState(defaultPrice);
  const [display, setDisplay] = useState(() => {
    if (search?.price_id && defaultPrice && defaultPrice.id) {
      const product = products.find((x) => x.prices.some((y) => y.id === defaultPrice.id));
      const currency = findCurrency(settings.paymentMethods, defaultPrice.currency_id ?? '') || settings.baseCurrency;
      return `${product?.name}(${formatPrice(price, currency!)})`;
    }
    return '';
  });
  const isSubscription = window.location.pathname.includes('subscriptions');
  const { t } = useLocaleContext();

  useEffect(() => {
    if (!price.id) {
      return;
    }
    fetchSubscriptionItems({
      price_id: price.id,
    }).then((data) => {
      const str = data.list.map((x: any) => x.subscription_id).join(',');
      const key = isSubscription ? 'id' : 'subscription_id';
      setSearch({
        q: {
          [key]: str,
        },
        page: 1,
        pageSize: 10,
        price_id: price.id,
      });
    });
  }, [price]);

  return (
    <section>
      <Button
        className="option-btn"
        variant="text"
        onClick={(e) => {
          setShow(e.currentTarget as any);
        }}>
        {display ? (
          <Close
            sx={{ color: 'text.secondary', cursor: 'pointer', fontSize: '1.05rem' }}
            onClick={(e) => {
              e.stopPropagation();
              setSearch({
                q: '',
                price_id: '',
              });
              setDisplay('');
              setShow(null);
            }}
          />
        ) : (
          <Add sx={{ color: 'text.secondary', cursor: 'pointer', fontSize: '1.05rem' }} />
        )}
        {t('admin.subscription.product')}
        <span>{display}</span>
      </Button>
      <Menu
        anchorEl={show}
        open={Boolean(show)}
        className="status-options"
        sx={{ height: 300 }}
        onClose={(e: any) => {
          e.stopPropagation();
          setShow(null);
        }}>
        <ProductSelect
          mode="inline"
          hasSelected={() => false}
          onSelect={(p: any) => {
            setPrice(p);
            setDisplay(`${p.productName}(${p.displayPrice})`);
            setShow(null);
          }}
        />
      </Menu>
    </section>
  );
}

function SearchDonation({
  donation = defaultProps.donation,
  search = defaultProps.search,
  setSearch,
}: Pick<Props, 'donation' | 'search' | 'setSearch'>) {
  const [show, setShow] = useState(null);
  const { t } = useLocaleContext();
  return (
    <section
      onClick={(e) => {
        setShow(e.currentTarget as any);
      }}>
      <Button className="option-btn" variant="text">
        {search!.donation ? (
          <Close
            sx={{ color: 'text.secondary', cursor: 'pointer', fontSize: '1.05rem' }}
            onClick={(e) => {
              e.stopPropagation();
              setSearch({
                donation: '',
              });
              setShow(null);
            }}
          />
        ) : (
          <Add sx={{ color: 'text.secondary', cursor: 'pointer', fontSize: '1.05rem' }} />
        )}
        {t('common.donation')}
        <span>{search!.donation}</span>
      </Button>
      <Menu
        anchorEl={show}
        open={Boolean(show)}
        onClose={(e: any) => {
          e.stopPropagation();
          setShow(null);
        }}
        className="status-options">
        {donation?.map((x: any) => (
          <MenuItem
            onClick={(e) => {
              e.stopPropagation();
              setSearch({
                donation: x,
              });
              setShow(null);
            }}
            key={x}>
            {x}
          </MenuItem>
        ))}
      </Menu>
    </section>
  );
}

const Root = styled(Box)`
  .table-toolbar-left {
    display: flex;
    align-items: center;
  }

  .table-toolbar-left section {
    position: relative;
    list-style: none;
    font-size: 14px;
    font-weight: normal;
    padding: 0 5px;
    cursor: pointer;
  }

  .option-btn {
    display: flex;
    align-items: center;
    border-radius: 25px;
    background: ${({ theme }) => theme.palette.grey[100]};
    padding: 5px 10px;
    color: ${({ theme }) => theme.palette.text.secondary};
    font-size: 14px;
    line-height: 14px;
    overflow: visible;
  }

  .option-btn span {
    color: #3773f2;
    padding: 0 3px;
    overflow: visible;
  }

  .status-options {
    position: absolute;
    box-shadow:
      0px 5px 5px -3px rgba(0, 0, 0, 0.2),
      0px 8px 10px 1px rgba(0, 0, 0, 0.14),
      0px 3px 14px 2px rgba(0, 0, 0, 0.12);
    padding: 0;
    background: ${({ theme }) => theme.palette.background.paper};
    border: 1px solid;
    border-color: ${({ theme }) => theme.palette.divider};
    z-index: 999999;
    top: 15px;
    display: block;
    max-height: 500px;
    overflow-y: auto;
    overflow-x: hidden;
  }

  .status-options li {
    list-style: none;
    line-height: normal;
  }
`;
