import React, { useState, useRef, useEffect, useMemo } from 'react';
import { PlusMinor } from '@shopify/polaris-icons';
import { classNames } from '../../utilities/css.js';
import styles from './AlphaFilters.scss.js';
import { SearchField } from './components/SearchField/SearchField.js';
import { FilterPill } from './components/FilterPill/FilterPill.js';
import { useI18n } from '../../utilities/i18n/hooks.js';
import { Text } from '../Text/Text.js';
import { UnstyledButton } from '../UnstyledButton/UnstyledButton.js';
import { Spinner } from '../Spinner/Spinner.js';
import { Box } from '../Box/Box.js';
import { HorizontalStack } from '../HorizontalStack/HorizontalStack.js';
import { Popover } from '../Popover/Popover.js';
import { ActionList } from '../ActionList/ActionList.js';
import { Button } from '../Button/Button.js';

const TRANSITION_DURATION = 'var(--p-motion-duration-150)';
const TRANSITION_MARGIN = '-36px';
const defaultStyle = {
  transition: `opacity ${TRANSITION_DURATION} var(--p-motion-ease)`,
  opacity: 0
};
const transitionStyles = {
  entering: {
    opacity: 1
  },
  entered: {
    opacity: 1
  },
  exiting: {
    opacity: 0
  },
  exited: {
    opacity: 0
  },
  unmounted: {
    opacity: 0
  }
};
const defaultFilterStyles = {
  transition: `opacity ${TRANSITION_DURATION} var(--p-motion-ease), margin ${TRANSITION_DURATION} var(--p-motion-ease)`,
  opacity: 0,
  marginTop: TRANSITION_MARGIN
};
const transitionFilterStyles = {
  entering: {
    opacity: 1,
    marginTop: 0
  },
  entered: {
    opacity: 1,
    marginTop: 0
  },
  exiting: {
    opacity: 0,
    marginTop: TRANSITION_MARGIN
  },
  exited: {
    opacity: 0,
    marginTop: TRANSITION_MARGIN
  },
  unmounted: {
    opacity: 0,
    marginTop: TRANSITION_MARGIN
  }
};
function AlphaFilters({
  queryValue,
  queryPlaceholder,
  focused,
  filters,
  appliedFilters,
  onQueryChange,
  onQueryClear,
  onQueryBlur,
  onQueryFocus,
  onClearAll,
  children,
  disabled,
  hideFilters,
  hideQueryField,
  disableQueryField,
  borderlessQueryField,
  loading,
  disableFilters,
  mountedState,
  onAddFilterClick
}) {
  const i18n = useI18n();
  const [popoverActive, setPopoverActive] = useState(false);
  const [localPinnedFilters, setLocalPinnedFilters] = useState([]);
  const hasMounted = useRef(false);
  useEffect(() => {
    hasMounted.current = true;
  });

  const togglePopoverActive = () => setPopoverActive(popoverActive => !popoverActive);

  const handleAddFilterClick = () => {
    onAddFilterClick === null || onAddFilterClick === void 0 ? void 0 : onAddFilterClick();
    togglePopoverActive();
  };

  const appliedFilterKeys = appliedFilters === null || appliedFilters === void 0 ? void 0 : appliedFilters.map(({
    key
  }) => key);
  const pinnedFiltersFromPropsAndAppliedFilters = filters.filter(({
    pinned,
    key
  }) => (Boolean(pinned) || (appliedFilterKeys === null || appliedFilterKeys === void 0 ? void 0 : appliedFilterKeys.includes(key))) && // Filters that are pinned in local state display at the end of our list
  !localPinnedFilters.find(filterKey => filterKey === key));
  const pinnedFiltersFromLocalState = localPinnedFilters.map(key => filters.find(filter => filter.key === key)).reduce((acc, filter) => filter ? [...acc, filter] : acc, []);
  const pinnedFilters = [...pinnedFiltersFromPropsAndAppliedFilters, ...pinnedFiltersFromLocalState];

  const onFilterClick = ({
    key,
    onAction
  }) => () => {
    // PopoverOverlay will cause a rerender of the component and nuke the
    // popoverActive state, so we set this as a microtask
    setTimeout(() => {
      setLocalPinnedFilters(currentLocalPinnedFilters => [...new Set([...currentLocalPinnedFilters, key])]);
      onAction === null || onAction === void 0 ? void 0 : onAction();
      togglePopoverActive();
    }, 0);
  };

  const filterToActionItem = filter => ({ ...filter,
    content: filter.label,
    onAction: onFilterClick(filter)
  });

  const unpinnedFilters = filters.filter(filter => !pinnedFilters.some(({
    key
  }) => key === filter.key));
  const unsectionedFilters = unpinnedFilters.filter(filter => !filter.section).map(filterToActionItem);
  const sectionedFilters = unpinnedFilters.filter(filter => filter.section).reduce((acc, filter) => {
    const filterActionItem = filterToActionItem(filter);
    const sectionIndex = acc.findIndex(section => section.title === filter.section);

    if (sectionIndex === -1) {
      acc.push({
        title: filter.section,
        items: [filterActionItem]
      });
    } else {
      acc[sectionIndex].items.push(filterActionItem);
    }

    return acc;
  }, []);
  const hasOneOrMorePinnedFilters = pinnedFilters.length >= 1;
  const addFilterActivator = /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Text, {
    variant: "bodySm",
    as: "p"
  }, /*#__PURE__*/React.createElement(UnstyledButton, {
    type: "button",
    className: styles.AddFilter,
    onClick: handleAddFilterClick,
    "aria-label": i18n.translate('Polaris.Filters.addFilter'),
    disabled: disabled || unsectionedFilters.length === 0 && sectionedFilters.length === 0 || disableFilters
  }, /*#__PURE__*/React.createElement("span", null, i18n.translate('Polaris.Filters.addFilter')), /*#__PURE__*/React.createElement(PlusMinor, null))));

  const handleClearAllFilters = () => {
    setLocalPinnedFilters([]);
    onClearAll === null || onClearAll === void 0 ? void 0 : onClearAll();
  };

  const shouldShowAddButton = filters.some(filter => !filter.pinned);
  const additionalContent = useMemo(() => {
    return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
      className: styles.Spinner
    }, loading ? /*#__PURE__*/React.createElement(Spinner, {
      size: "small"
    }) : null), children);
  }, [loading, children]);
  const queryFieldMarkup = hideQueryField ? null : /*#__PURE__*/React.createElement("div", {
    className: styles.Container
  }, /*#__PURE__*/React.createElement(Box, {
    paddingBlockStart: {
      xs: '3',
      md: '2'
    },
    paddingBlockEnd: {
      xs: '3',
      md: '2'
    },
    paddingInlineStart: "2",
    paddingInlineEnd: {
      xs: '4',
      md: '3'
    }
  }, /*#__PURE__*/React.createElement(HorizontalStack, {
    align: "start",
    blockAlign: "center",
    gap: {
      xs: '4',
      md: '3'
    }
  }, /*#__PURE__*/React.createElement("div", {
    className: styles.SearchField,
    style: mountedState ? { ...defaultStyle,
      ...transitionStyles[mountedState]
    } : undefined
  }, /*#__PURE__*/React.createElement(SearchField, {
    onChange: onQueryChange,
    onFocus: onQueryFocus,
    onBlur: onQueryBlur,
    onClear: onQueryClear,
    value: queryValue,
    placeholder: queryPlaceholder,
    focused: focused,
    disabled: disabled || disableQueryField,
    borderlessQueryField: borderlessQueryField
  })), additionalContent)));
  const mountedStateStyles = mountedState && !hideQueryField ? { ...defaultFilterStyles,
    ...transitionFilterStyles[mountedState]
  } : undefined;
  const pinnedFiltersMarkup = pinnedFilters.map(({
    key: filterKey,
    ...pinnedFilter
  }) => {
    const appliedFilter = appliedFilters === null || appliedFilters === void 0 ? void 0 : appliedFilters.find(({
      key
    }) => key === filterKey);

    const handleFilterPillRemove = () => {
      setLocalPinnedFilters(currentLocalPinnedFilters => currentLocalPinnedFilters.filter(key => key !== filterKey));
      appliedFilter === null || appliedFilter === void 0 ? void 0 : appliedFilter.onRemove(filterKey);
    };

    return /*#__PURE__*/React.createElement(FilterPill, Object.assign({
      key: filterKey
    }, pinnedFilter, {
      initialActive: hasMounted.current && !pinnedFilter.pinned && !appliedFilter,
      label: (appliedFilter === null || appliedFilter === void 0 ? void 0 : appliedFilter.label) || pinnedFilter.label,
      filterKey: filterKey,
      selected: appliedFilterKeys === null || appliedFilterKeys === void 0 ? void 0 : appliedFilterKeys.includes(filterKey),
      onRemove: handleFilterPillRemove,
      disabled: pinnedFilter.disabled || disableFilters
    }));
  });
  const addButton = shouldShowAddButton ? /*#__PURE__*/React.createElement("div", {
    className: classNames(styles.AddFilterActivator, hasOneOrMorePinnedFilters && styles.AddFilterActivatorMultiple)
  }, /*#__PURE__*/React.createElement(Popover, {
    active: popoverActive && !disabled,
    activator: addFilterActivator,
    onClose: togglePopoverActive
  }, /*#__PURE__*/React.createElement(ActionList, {
    actionRole: "menuitem",
    items: unsectionedFilters,
    sections: sectionedFilters
  }))) : null;
  const clearAllMarkup = appliedFilters !== null && appliedFilters !== void 0 && appliedFilters.length || localPinnedFilters.length ? /*#__PURE__*/React.createElement("div", {
    className: classNames(styles.ClearAll, hasOneOrMorePinnedFilters && shouldShowAddButton && styles.MultiplePinnedFilterClearAll)
  }, /*#__PURE__*/React.createElement(Button, {
    size: "micro",
    plain: true,
    onClick: handleClearAllFilters,
    removeUnderline: true
  }, i18n.translate('Polaris.Filters.clearFilters'))) : null;
  const filtersMarkup = hideFilters || filters.length === 0 ? null : /*#__PURE__*/React.createElement("div", {
    className: classNames(styles.FiltersWrapper, shouldShowAddButton && hasOneOrMorePinnedFilters && styles.FiltersWrapperWithAddButton),
    "aria-live": "polite",
    style: mountedStateStyles
  }, /*#__PURE__*/React.createElement("div", {
    className: classNames(styles.FiltersInner)
  }, /*#__PURE__*/React.createElement("div", {
    className: classNames(styles.FiltersStickyArea)
  }, pinnedFiltersMarkup, addButton, clearAllMarkup)), hideQueryField ? /*#__PURE__*/React.createElement(Box, {
    paddingInlineEnd: "3",
    paddingBlockStart: "2",
    paddingBlockEnd: "2"
  }, /*#__PURE__*/React.createElement(HorizontalStack, {
    align: "start",
    blockAlign: "center",
    gap: {
      xs: '4',
      md: '3'
    }
  }, additionalContent)) : null);
  return /*#__PURE__*/React.createElement("div", {
    className: classNames(styles.Filters, hideQueryField && styles.hideQueryField)
  }, queryFieldMarkup, filtersMarkup);
}

export { AlphaFilters };
