import React, {
  useRef, useEffect, useState,
} from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { BreadcrumbItemContainer } from './BreadcrumbItemContainer';
import { BreadcrumbItem } from './BreadcrumbItem';

const propTypes = {
  /**
   * The component used for the root node.
   * Either a string to use a DOM element or a component.
   */
  tag: PropTypes.elementType,
  children: PropTypes.node,
  className: PropTypes.string,
  defaultClassName: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
  /**
   * Array of dependencies that will trigger breadcrumb to recalculate which items to display
   */
  deps: PropTypes.array,
};

const defaultProps = {
  tag: 'div',
  children: '',
  className: '',
  defaultClassName: 'sui-m-breadcrumb',
  deps: [],
};

export const Breadcrumb = ({
  tag: Tag,
  children,
  className,
  defaultClassName,
  deps,
  ...attributes
}) => {
  const containerRef = useRef();
  const [itemsToDisplay, setItemsToDisplay] = useState(0);

  const classes = classnames(
    defaultClassName,
    className
  );

  const getItemsToDisplay = (toDisplay) => {
    const container = containerRef.current;

    if (!container) {
      return toDisplay;
    }

    const items = [...container.querySelectorAll('.sui-m-breadcrumb__item')];
    const itemsWidthArray = items.map((x) => x.offsetWidth);

    if (toDisplay >= items.length) {
      return toDisplay;
    }

    const containerWidth = container.offsetWidth;

    const itemsWidthArrayFiltered = toDisplay >= itemsWidthArray.length
      ? itemsWidthArray
      : [
        ...itemsWidthArray.slice(0, 2), // First item + Ellipsis
        ...itemsWidthArray.slice(itemsWidthArray.length - toDisplay + 1), // Last items
      ];

    const itemsWidth = itemsWidthArrayFiltered
      .reduce((acc, cur) => acc + cur, 0);

    if (itemsWidth < containerWidth) {
      return getItemsToDisplay(toDisplay + 1);
    }

    return toDisplay - 1;
  };

  const updateItemsToDisplay = () => {
    const toDisplay = getItemsToDisplay(0);
    setItemsToDisplay(toDisplay >= 1 ? toDisplay : 1);
  };

  useEffect(() => {
    updateItemsToDisplay();
  }, [deps]);

  useEffect(() => {
    window.addEventListener('resize', updateItemsToDisplay);

    return () => {
      window.removeEventListener('resize', updateItemsToDisplay);
    };
  }, []);

  const itemsList = React.Children.toArray(children);
  const itemsListDisplay = [
    ...itemsList.slice(0, 1),
    <BreadcrumbItem>...</BreadcrumbItem>,
    ...itemsList.slice(1),
  ];

  const shouldDisplayItem = (index) => {
    const isFirstItem = index === 0;
    const isLastItem = index >= itemsListDisplay.length - 1;
    const isEllipsisItem = index === 1;
    const isLastItemsToDisplay = index >= itemsListDisplay.length - itemsToDisplay + 1;

    // If only one item to display, show last item and ellipsis item
    if (itemsToDisplay <= 1) {
      return isLastItem || isEllipsisItem;
    }

    // Hide ellipsis if all items are displayed
    if (itemsList.length <= itemsToDisplay && isEllipsisItem) {
      return false;
    }

    // Show first item, ellipsis and last items
    if (isFirstItem || isEllipsisItem || isLastItemsToDisplay) {
      return true;
    }

    // Hide other items
    return false;
  };

  return (
    <div className={classes} {...attributes} ref={containerRef}>
      {itemsListDisplay.map((x, i) => (
        <BreadcrumbItemContainer
          // eslint-disable-next-line react/no-array-index-key
          key={i}
          isHidden={!shouldDisplayItem(i)}
          style={{
            minWidth: itemsToDisplay <= 1 && i >= itemsListDisplay.length - 1 ? 0 : null,
          }}
        >
          {x}
        </BreadcrumbItemContainer>
      ))}
    </div>
  );
};

Breadcrumb.propTypes = propTypes;
Breadcrumb.defaultProps = defaultProps;
