import React, { FC, useContext, useEffect, useRef, useState } from 'react';

import classNames from 'classnames';
import { EllipsisOutlined } from '@ant-design/icons';
import Collapsible from '../../../collapsible';
import { Item, ItemProps } from '../Item';
import { ConfigContext } from '../../../config-provider';

function noop() {}

const noWindowMatches: MediaQueryList = {
  media: '',
  addListener: noop,
  removeListener: noop,
  matches: false,
  onchange: noop,
  addEventListener: noop,
  removeEventListener: noop,
  dispatchEvent: () => true,
};

function navigationBarCollapsed() {
  return typeof window === 'undefined' ? noWindowMatches : window.matchMedia(`(max-width: 768px)`);
}

export interface SectionProps {
  items: ItemProps[];
  icon?: React.ReactNode;
  title?: string;
  fill?: boolean;
  rollup?: {
    after: number;
    view: string;
    hide: string;
    activePath: string;
  };
  action?: {
    icon: React.ReactNode;
    onClick(): void;
  };
  separator?: boolean;
}

export const Section: FC<SectionProps> = ({ title, fill, action, items, rollup, separator }) => {
  const { getPrefixCls } = useContext(ConfigContext);
  const prefixCls = getPrefixCls('navigation');

  const [expanded, setExpanded] = useState(false);
  const animationFrame = useRef<number | null>(null);

  const handleClick = (onClick: ItemProps['onClick'], hasSubNavItems: boolean) => () => {
    if (onClick) {
      onClick();
    }

    if (animationFrame.current) {
      cancelAnimationFrame(animationFrame.current);
    }

    if (!hasSubNavItems || !navigationBarCollapsed().matches) {
      animationFrame.current = requestAnimationFrame(() => setExpanded(false));
    }
  };

  useEffect(() => () => {
    if (animationFrame.current) {
      cancelAnimationFrame(animationFrame.current);
    }
  });

  const className = classNames({
    [`${prefixCls}-section`]: true,
    [`${prefixCls}-section-with-separator`]: separator,
    [`${prefixCls}-section-fill`]: fill,
  });

  const actionMarkup = action && (
    <button type="button" className={`${prefixCls}-action`} onClick={action.onClick}>
      {action.icon}
    </button>
  );

  const sectionHeadingMarkup = title && (
    <li className={`${prefixCls}-section-heading`}>
      <span className={`${prefixCls}-text`}>{title}</span>
      {actionMarkup}
    </li>
  );

  const itemsMarkup = items.map(item => {
    const { onClick, name, subNavigationItems, ...rest } = item;
    const hasSubNavItems = subNavigationItems != null && subNavigationItems.length > 0;

    return (
      <Item
        {...rest}
        key={name}
        name={name}
        subNavigationItems={subNavigationItems}
        onClick={handleClick(onClick, hasSubNavItems)}
      />
    );
  });

  const toggleClassName = classNames([`${prefixCls}-item`, `${prefixCls}-rollup-toggle`]);

  const toggleRollup = rollup && items.length > rollup.after && (
    <div className={`${prefixCls}-list-item`} key="List Item">
      <button type="button" className={toggleClassName} onClick={() => setExpanded(!expanded)}>
        <span className={`${prefixCls}-icon`}>
          <EllipsisOutlined />
        </span>
        HorizontalDotsMinorIcon
      </button>
    </div>
  );

  const activeItemIndex = items.findIndex((item: ItemProps) => {
    if (!rollup) {
      return false;
    }

    return (
      rollup.activePath === item.path ||
      (item.path && rollup.activePath.startsWith(item.path)) ||
      (item.subNavigationItems
        ? item.subNavigationItems.some(({ path: itemUrl }) => rollup.activePath.startsWith(itemUrl))
        : false)
    );
  });

  const sectionItems = rollup ? itemsMarkup.slice(0, rollup.after) : itemsMarkup;

  const additionalItems = rollup ? itemsMarkup.slice(rollup.after) : [];

  if (rollup && activeItemIndex !== -1 && activeItemIndex > rollup.after - 1) {
    sectionItems.push(...additionalItems.splice(activeItemIndex - rollup.after, 1));
  }

  const activeItemsMarkup = rollup && additionalItems.length > 0 && (
    <li className={`${prefixCls}-rollup-section`}>
      <Collapsible open={expanded}>
        <ul className={`${prefixCls}-list`}>{additionalItems}</ul>
      </Collapsible>
      {toggleRollup}
    </li>
  );

  return (
    <ul className={className}>
      {sectionHeadingMarkup}
      {sectionItems}
      {activeItemsMarkup}
    </ul>
  );
};
