import React from 'react';
import useUser from '@plone/volto/hooks/user/useUser';
import PropTypes from 'prop-types';
import filter from 'lodash/filter';
import map from 'lodash/map';
import groupBy from 'lodash/groupBy';
import isEmpty from 'lodash/isEmpty';
import { Accordion, Button } from 'semantic-ui-react';
import { useIntl, defineMessages } from 'react-intl';
import Icon from '@plone/volto/components/theme/Icon/Icon';
import AnimateHeight from 'react-animate-height';
import config from '@plone/volto/registry';
import upSVG from '@plone/volto/icons/up-key.svg';
import downSVG from '@plone/volto/icons/down-key.svg';
import BlockChooserSearch from './BlockChooserSearch';
import { FormattedMessage } from 'react-intl';

const messages = defineMessages({
  fold: {
    id: 'Fold',
    defaultMessage: 'Fold',
  },
  unfold: {
    id: 'Unfold',
    defaultMessage: 'Unfold',
  },
});

const BlockChooser = ({
  currentBlock,
  onInsertBlock,
  onMutateBlock,
  allowedBlocks,
  showRestricted,
  blocksConfig = config.blocks.blocksConfig,
  blockChooserRef,
  properties = {},
  navRoot,
  contentType,
}) => {
  const intl = useIntl();
  const user = useUser();
  const hasAllowedBlocks = !isEmpty(allowedBlocks);

  const filteredBlocksConfig = filter(blocksConfig, (item) => {
    // Check if the block is well formed (has at least id and title)
    const blockIsWellFormed = Boolean(item.title && item.id);
    if (!blockIsWellFormed) {
      return false;
    }
    if (showRestricted) {
      if (hasAllowedBlocks) {
        return allowedBlocks.includes(item.id);
      } else {
        return true;
      }
    } else {
      if (hasAllowedBlocks) {
        return allowedBlocks.includes(item.id);
      } else {
        // Overload restricted as a function, so we can decide the availability of a block
        // depending on this function, given properties (current present blocks) and the
        // block being evaluated
        return typeof item.restricted === 'function'
          ? !item.restricted({
              properties,
              block: item,
              navRoot,
              contentType,
              user,
            })
          : !item.restricted;
      }
    }
  });

  let blocksAvailable = {};
  const mostUsedBlocks = filter(filteredBlocksConfig, (item) => item.mostUsed);
  if (mostUsedBlocks) {
    blocksAvailable.mostUsed = mostUsedBlocks;
  }
  const groupedBlocks = groupBy(filteredBlocksConfig, (item) => item.group);
  blocksAvailable = {
    ...blocksAvailable,
    ...groupedBlocks,
  };

  const groupBlocksOrder = filter(config.blocks.groupBlocksOrder, (item) =>
    Object.keys(blocksAvailable).includes(item.id),
  );
  const [activeIndex, setActiveIndex] = React.useState(0);

  function handleClick(e, titleProps) {
    const { index } = titleProps;
    const newIndex = activeIndex === index ? -1 : index;

    setActiveIndex(newIndex);
  }
  const [filterValue, setFilterValue] = React.useState('');

  const getFormatMessage = (message) =>
    intl.formatMessage({
      id: message,
      defaultMessage: message,
    });

  function blocksAvailableFilter(blocks) {
    return blocks.filter(
      (block) =>
        getFormatMessage(block.title)
          .toLowerCase()
          .includes(filterValue.toLowerCase()) ||
        filterVariations(block)?.length,
    );
  }
  function filterVariations(block) {
    return block.variations?.filter(
      (variation) =>
        getFormatMessage(variation.title)
          .toLowerCase()
          .includes(filterValue.toLowerCase()) &&
        !variation.title.toLowerCase().includes('default'),
    );
  }

  const ButtonGroup = ({ block }) => {
    const variations = filterVariations(block);
    return (
      <Button.Group key={block.id}>
        <Button
          type="button"
          icon
          basic
          className={block.id}
          onClick={(e) => {
            onInsertBlock
              ? onInsertBlock(currentBlock, {
                  '@type': block.id,
                })
              : onMutateBlock(currentBlock, {
                  '@type': block.id,
                });
            e.stopPropagation();
          }}
        >
          <Icon name={block.icon} size="36px" />
          {getFormatMessage(block.title)}
          {filterValue && variations?.[0]?.title && (
            <small>{getFormatMessage(variations[0].title)}</small>
          )}
        </Button>
      </Button.Group>
    );
  };

  return (
    <div
      className={`blocks-chooser${
        config.experimental.addBlockButton.enabled ? ' new-add-block' : ''
      }`}
      ref={blockChooserRef}
    >
      <BlockChooserSearch
        onChange={(value) => setFilterValue(value)}
        searchValue={filterValue}
      />
      {filterValue ? (
        <>
          {map(blocksAvailableFilter(filteredBlocksConfig), (block) => (
            <ButtonGroup block={block} key={block.id} />
          ))}
          {blocksAvailableFilter(filteredBlocksConfig).length === 0 && (
            <h4 style={{ textAlign: 'center', lineHeight: '40px' }}>
              <FormattedMessage
                id="No results found"
                defaultMessage="No results found"
              />
            </h4>
          )}
        </>
      ) : (
        <Accordion fluid styled className="form">
          {map(groupBlocksOrder, (groupName, index) => (
            <React.Fragment key={groupName.id}>
              <Accordion.Title
                aria-label={
                  activeIndex === index
                    ? `${intl.formatMessage(messages.fold)} ${
                        groupName.title
                      } blocks`
                    : `${intl.formatMessage(messages.unfold)} ${
                        groupName.title
                      } blocks`
                }
                active={activeIndex === index}
                index={index}
                onClick={handleClick}
              >
                {intl.formatMessage({
                  id: groupName.id,
                  defaultMessage: groupName.title,
                })}
                <div className="accordion-tools">
                  {activeIndex === 0 ? (
                    <Icon name={upSVG} size="20px" />
                  ) : (
                    <Icon name={downSVG} size="20px" />
                  )}
                </div>
              </Accordion.Title>
              <Accordion.Content
                className={groupName.id}
                active={activeIndex === index}
              >
                <AnimateHeight
                  animateOpacity
                  duration={500}
                  height={activeIndex === index ? 'auto' : 0}
                >
                  {map(blocksAvailable[groupName.id], (block) => (
                    <ButtonGroup block={block} key={block.id} />
                  ))}
                </AnimateHeight>
              </Accordion.Content>
            </React.Fragment>
          ))}
        </Accordion>
      )}
    </div>
  );
};

BlockChooser.propTypes = {
  currentBlock: PropTypes.string.isRequired,
  onMutateBlock: PropTypes.func,
  onInsertBlock: PropTypes.func,
  allowedBlocks: PropTypes.arrayOf(PropTypes.string),
  blocksConfig: PropTypes.objectOf(PropTypes.any),
};

export default React.forwardRef((props, ref) => (
  <BlockChooser {...props} blockChooserRef={ref} />
));
