// @flow
import { Combobox, ComboboxInput, ComboboxPopover, ComboboxList, ComboboxOption } from '@reach/combobox';
// import '@reach/combobox/styles.css'; --> 'scss/third-party.scss'
import { matchSorter } from 'match-sorter';
import React from 'react';
import classnames from 'classnames';
import Button from 'component/button';
import ClaimList from 'component/claimList';
import Icon from 'component/common/icon';
import Paginate from 'component/common/paginate';
import Yrbl from 'component/yrbl';
import * as ICONS from 'constants/icons';
import useThrottle from 'effects/use-throttle';

const PAGE_SIZE = 10;

function reduceUriToChannelName(uri: string) {
  // 'parseURI' is too slow to handle a large list. Since our list should be
  // kosher in the first place, just do a quick substring call. Add a
  // try-catch just in case.
  try {
    return uri.substring(uri.indexOf('@') + 1, uri.indexOf('#'));
  } catch {
    return uri;
  }
}

// ****************************************************************************
// BlockList
// ****************************************************************************

type Props = {
  uris: Array<string>,
  help: string,
  titleEmptyList: string,
  subtitleEmptyList: string,
  getActionButtons?: (url: string) => React$Node,
  className: ?string,
};

export default function BlockList(props: Props) {
  const { uris: list, help, titleEmptyList, subtitleEmptyList, getActionButtons, className } = props;

  // Keep a local list to allow for undoing actions in this component
  const [localList, setLocalList] = React.useState(undefined);
  const stringifiedList = JSON.stringify(list);
  const hasLocalList = localList && localList.length > 0;
  const justBlocked = list && localList && localList.length < list.length;

  const [page, setPage] = React.useState(1);
  const [searchList, setSearchList] = React.useState(null); // null: not searching; []: no results;
  const isShowingSearchResults = searchList !== null;

  let totalPages = 0;
  let paginatedLocalList;
  if (localList) {
    paginatedLocalList = localList.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE);
    totalPages = Math.ceil(localList.length / PAGE_SIZE);
  }

  // **************************************************************************
  // **************************************************************************

  function getRenderActions() {
    if (getActionButtons) {
      return (claim) => <div className="section__actions">{getActionButtons(claim.permanent_url)}</div>;
    }
    return undefined;
  }

  function formatSearchSuggestion(suggestion: string) {
    return reduceUriToChannelName(suggestion);
  }

  function filterSearchResults(results: ?Array<string>) {
    setSearchList(results);
  }

  // **************************************************************************
  // **************************************************************************

  React.useEffect(() => {
    const list = stringifiedList && JSON.parse(stringifiedList);
    if (!hasLocalList) {
      setLocalList(list && list.length > 0 ? list : []);
    }
  }, [stringifiedList, hasLocalList]);

  React.useEffect(() => {
    if (justBlocked && stringifiedList) {
      setLocalList(JSON.parse(stringifiedList));
    }
  }, [stringifiedList, justBlocked, setLocalList]);

  // **************************************************************************
  // **************************************************************************

  if (paginatedLocalList === undefined) {
    return null;
  }

  if (!hasLocalList) {
    return (
      <div className="main--empty">
        <Yrbl
          title={titleEmptyList}
          subtitle={subtitleEmptyList}
          actions={
            <div className="section__actions">
              <Button button="primary" label={__('Go Home')} navigate="/" />
            </div>
          }
        />
      </div>
    );
  }

  return (
    <>
      <div className="help--notice">{help}</div>
      <div className="section">
        <SearchList
          list={localList}
          placeholder={__('e.g. odysee')}
          formatter={formatSearchSuggestion}
          onResultsUpdated={filterSearchResults}
        />
      </div>
      <div className={classnames('section block-list', className)}>
        <ClaimList
          uris={searchList || paginatedLocalList}
          showUnresolvedClaims
          showHiddenByUser
          hideMenu
          renderActions={getRenderActions()}
        />
      </div>
      {!isShowingSearchResults && <Paginate totalPages={totalPages} disableHistory onPageChange={(p) => setPage(p)} />}
    </>
  );
}

// ****************************************************************************
// SearchList
// ****************************************************************************

type LsbProps = {
  list: ?Array<string>,
  placeholder?: string,
  formatter?: (suggestion: string) => string,
  onResultsUpdated?: (?Array<string>) => void,
};

function SearchList(props: LsbProps) {
  const { list, placeholder, formatter, onResultsUpdated } = props;
  const [term, setTerm] = React.useState('');
  const results = useAuthorMatch(term, list);
  const handleChange = (event) => setTerm(event.target.value);
  const handleSelect = (e) => setTerm(e);

  React.useEffect(() => {
    if (onResultsUpdated) {
      onResultsUpdated(results);
    }
  }, [results]); // eslint-disable-line react-hooks/exhaustive-deps

  return (
    <div className="wunderbar__wrapper">
      <label>{__('Search blocked channel name')}</label>
      <Combobox className="wunderbar" onSelect={handleSelect}>
        <Icon icon={ICONS.SEARCH} />
        <ComboboxInput selectOnClick className="wunderbar__input" onChange={handleChange} placeholder={placeholder} />
        {results && (
          <ComboboxPopover className="wunderbar__suggestions" portal={false}>
            {results.length > 0 ? (
              <ComboboxList>
                {results.slice(0, 10).map((result, index) => (
                  <ComboboxOption
                    className="wunderbar__more-results"
                    key={index}
                    value={formatter ? formatter(result) : result}
                  />
                ))}
              </ComboboxList>
            ) : (
              <span style={{ display: 'block', margin: 8 }}>{__('No results')}</span>
            )}
          </ComboboxPopover>
        )}
      </Combobox>
    </div>
  );
}

function useAuthorMatch(term, list) {
  const throttledTerm = useThrottle(term, 200);
  return React.useMemo(() => {
    return !throttledTerm || throttledTerm.trim() === ''
      ? null
      : matchSorter(list, throttledTerm, {
          keys: [(item) => reduceUriToChannelName(item)],
          threshold: matchSorter.rankings.CONTAINS,
        });
  }, [throttledTerm]); // eslint-disable-line react-hooks/exhaustive-deps
}
