/*
Copyright (c) Uber Technologies, Inc.

This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
*/
import React from 'react';
import { Button, SHAPE, SIZE } from '../button';
import { Filter as FilterIcon } from '../icon';
import { Input, SIZE as INPUT_SIZE } from '../input';
import { Popover, PLACEMENT } from '../popover';
import { useStyletron } from '../styles';
import { useUIDSeed } from 'react-uid';
import { COLUMNS } from './constants';
import { matchesQuery } from './text-search';
import { LocaleContext } from '../locale';
import { isFocusVisible } from '../utils/focusVisible';

const ColumnIcon = props => {
  if (props.column.kind === COLUMNS.BOOLEAN) {
    return /*#__PURE__*/React.createElement(React.Fragment, null, "01");
  }

  if (props.column.kind === COLUMNS.CATEGORICAL) {
    return /*#__PURE__*/React.createElement(React.Fragment, null, "abc");
  }

  if (props.column.kind === COLUMNS.DATETIME) {
    return /*#__PURE__*/React.createElement(React.Fragment, null, "dt");
  }

  if (props.column.kind === COLUMNS.NUMERICAL) {
    return /*#__PURE__*/React.createElement(React.Fragment, null, "#");
  }

  return /*#__PURE__*/React.createElement(FilterIcon, null);
};

function Options(props) {
  const [css, theme] = useStyletron();
  const locale = React.useContext(LocaleContext);
  const inputRef = React.useRef(null);
  React.useEffect(() => {
    if (inputRef.current) {
      // @ts-ignore
      inputRef.current.focus();
    }
  }, [inputRef.current]);
  const [focusVisible, setFocusVisible] = React.useState(false);
  const seed = useUIDSeed();
  const buiRef = React.useRef(props.columns.map(col => seed(col)));
  const activeDescendant = buiRef.current[props.highlightIndex] ? `bui-${buiRef.current[props.highlightIndex]}` : undefined;
  const optionsLabelId = seed('options-label');

  const handleFocus = event => {
    if (isFocusVisible(event)) {
      setFocusVisible(true);
    }
  }; // eslint-disable-next-line @typescript-eslint/no-unused-vars


  const handleBlur = event => {
    if (focusVisible !== false) {
      setFocusVisible(false);
    }
  };

  return /*#__PURE__*/React.createElement("div", {
    className: css({
      backgroundColor: theme.colors.menuFill,
      minWidth: '320px',
      outline: focusVisible ? `3px solid ${theme.colors.borderAccent}` : 'none',
      paddingTop: theme.sizing.scale600,
      paddingBottom: theme.sizing.scale600
    })
  }, /*#__PURE__*/React.createElement("p", {
    id: optionsLabelId,
    className: css({ ...theme.typography.font100,
      marginTop: 'unset',
      paddingRight: theme.sizing.scale600,
      paddingLeft: theme.sizing.scale600
    })
  }, locale.datatable.optionsLabel), props.searchable && /*#__PURE__*/React.createElement("div", {
    className: css({
      marginBottom: theme.sizing.scale500,
      marginRight: theme.sizing.scale600,
      marginLeft: theme.sizing.scale600
    })
  }, /*#__PURE__*/React.createElement(Input, {
    inputRef: inputRef,
    value: props.query,
    onChange: event => props.onQueryChange(event.target.value),
    placeholder: locale.datatable.optionsSearch,
    size: INPUT_SIZE.compact,
    clearable: true
  })), !props.columns.length && /*#__PURE__*/React.createElement("div", {
    className: css({ ...theme.typography.font100,
      paddingRight: theme.sizing.scale600,
      paddingLeft: theme.sizing.scale600
    })
  }, locale.datatable.optionsEmpty), /*#__PURE__*/React.createElement("ul", {
    onKeyDown: props.onKeyDown,
    onFocus: handleFocus,
    onBlur: handleBlur,
    tabIndex: 0,
    role: "listbox",
    "aria-activedescendant": activeDescendant,
    "aria-labelledby": optionsLabelId,
    className: css({
      listStyleType: 'none',
      marginBlockStart: 'unset',
      marginBlockEnd: 'unset',
      maxHeight: '256px',
      paddingInlineStart: 'unset',
      outline: 'none',
      overflowY: 'auto'
    })
  }, props.columns.map((column, index) => {
    const isHighlighted = index === props.highlightIndex;
    return (
      /*#__PURE__*/
      // handled on the wrapper element
      // eslint-disable-next-line jsx-a11y/click-events-have-key-events
      React.createElement("li", {
        id: `bui-${buiRef.current[index]}`,
        role: "option",
        "aria-selected": isHighlighted,
        onMouseEnter: () => props.onMouseEnter(index),
        onClick: () => props.onClick(column),
        key: column.title,
        className: css({ ...theme.typography.font100,
          alignItems: 'center',
          // @ts-ignore
          backgroundColor: isHighlighted ? theme.colors.menuFillHover : null,
          cursor: 'pointer',
          display: 'flex',
          paddingTop: theme.sizing.scale100,
          paddingRight: theme.sizing.scale600,
          paddingBottom: theme.sizing.scale100,
          paddingLeft: theme.sizing.scale600
        })
      }, /*#__PURE__*/React.createElement("div", {
        className: css({ ...theme.typography.font150,
          fontSize: '8px',
          alignItems: 'center',
          backgroundColor: theme.colors.backgroundTertiary,
          borderRadius: theme.borders.radius200,
          display: 'flex',
          height: theme.sizing.scale800,
          justifyContent: 'center',
          marginRight: theme.sizing.scale300,
          width: theme.sizing.scale800
        })
      }, /*#__PURE__*/React.createElement(ColumnIcon, {
        column: column
      })), column.title)
    );
  })));
}

function FilterMenu(props) {
  const [, theme] = useStyletron();
  const locale = React.useContext(LocaleContext);
  const [isOpen, setIsOpen] = React.useState(false);
  const [highlightIndex, setHighlightIndex] = React.useState(-1);
  const [query, setQuery] = React.useState('');
  const [activeColumn, setActiveColumn] = React.useState(null);
  const handleOptionClick = React.useCallback(setActiveColumn, []);
  const handleClose = React.useCallback(() => {
    setIsOpen(false);
    setActiveColumn(null);
    setHighlightIndex(-1);
    setQuery('');
  }, []);
  const filterableColumns = React.useMemo(() => {
    return props.columns.filter(column => {
      return column.filterable && !props.filters.has(column.title);
    });
  }, [props.columns, props.filters]);
  const columns = React.useMemo(() => {
    return filterableColumns.filter(column => matchesQuery(column.title, query));
  }, [filterableColumns, query]);
  const Filter = React.useMemo(() => {
    if (!activeColumn) return null; // @ts-ignore

    return activeColumn.renderFilter;
  }, [activeColumn]);
  const activeColumnData = React.useMemo(() => {
    const columnIndex = props.columns.findIndex(c => c === activeColumn);
    if (columnIndex < 0) return [];
    return props.rows.map(row => props.columns[columnIndex].mapDataToValue(row.data));
  }, [props.columns, props.rows, activeColumn]); // @ts-ignore

  function handleKeyDown(event) {
    if (event.keyCode === 13) {
      event.preventDefault(); // @ts-ignore

      setActiveColumn(columns[highlightIndex]);
    }

    if (event.keyCode === 38) {
      event.preventDefault();
      setHighlightIndex(Math.max(0, highlightIndex - 1));
    }

    if (event.keyCode === 40) {
      event.preventDefault();

      if (!isOpen) {
        setIsOpen(true);
      } else {
        setHighlightIndex(Math.min(columns.length - 1, highlightIndex + 1));
      }
    }
  }

  return /*#__PURE__*/React.createElement(Popover, {
    focusLock: true,
    returnFocus: true,
    placement: PLACEMENT.bottomLeft,
    content: () => {
      if (Filter && activeColumn) {
        return /*#__PURE__*/React.createElement(Filter, {
          data: activeColumnData,
          close: handleClose // @ts-ignore
          ,
          setFilter: filterParams => props.onSetFilter(activeColumn.title, filterParams)
        });
      }

      return /*#__PURE__*/React.createElement(Options, {
        columns: columns,
        highlightIndex: highlightIndex // @ts-ignore
        ,
        onClick: handleOptionClick,
        onKeyDown: handleKeyDown,
        onMouseEnter: setHighlightIndex,
        onQueryChange: setQuery,
        query: query,
        searchable: filterableColumns.length >= 10
      });
    },
    onClick: () => {
      if (isOpen) {
        handleClose();
      } else {
        setIsOpen(true);
      }
    },
    onClickOutside: handleClose,
    onEsc: handleClose,
    isOpen: isOpen,
    ignoreBoundary: true
  }, /*#__PURE__*/React.createElement(Button, {
    shape: SHAPE.pill,
    size: SIZE.compact,
    overrides: {
      BaseButton: {
        style: {
          marginLeft: theme.sizing.scale500,
          marginBottom: theme.sizing.scale500
        }
      }
    }
  }, locale.datatable.filterAdd));
}

export default FilterMenu;