import React, {
  FC,
  useContext,
  useRef,
  useState,
  useCallback,
  ReactNode,
  useMemo,
  useEffect,
} from 'react';
import useMedia from 'react-use/lib/useMedia';
import { CSSTransition } from 'react-transition-group';
import classNames from 'classnames';
import { CloseOutlined, MenuOutlined } from '@ant-design/icons';
import omit from 'lodash/omit';
import useMeasure from 'react-use/lib/useMeasure';
import Button from '../button';
import { MenuDataItem, MessageDescriptor, RouterTypes } from './typings';
import Navigation, { NavigationProps } from '../navigation';
import getMenuData from './utils/getMenuData';
import { clearMenuItem } from './utils/clearMenuItem';
import { ConfigContext } from '../config-provider';
import { ItemProps } from '../navigation/components/Item';
import { useLayoutHeaderHeight } from './useLayoutHeaderHeight';
import { BreadcrumbProps } from '../breadcrumb';

export type FrameProps = RouterTypes & {
  menuDataRender?: (menuData: MenuDataItem[]) => MenuDataItem[];
  postMenuData?: (menusData?: MenuDataItem[]) => MenuDataItem[];
  menuExtra?: React.ReactNode;
  leftContent?: React.ReactNode;
  rightContent?: React.ReactNode;
  formatMessage?: (message: MessageDescriptor) => string;
  menuItemRender?: NavigationProps['menuItemRender'];
  contentStyle?: React.CSSProperties;
  renderNavigation?:
    | ((menu: MenuDataItem[], renderItems: (menu: MenuDataItem[]) => ItemProps[]) => ReactNode)
    | false;
  headerRender?: (defaultDom: React.ReactNode) => React.ReactNode;
  breadcrumbRender?: false | ((routers: BreadcrumbProps['routes']) => BreadcrumbProps['routes']);
};

const Frame: FC<FrameProps> = props => {
  const {
    children,
    location,
    route,
    menuDataRender,
    postMenuData,
    menuExtra,
    leftContent,
    rightContent,
    contentStyle,
    menuItemRender,
    renderNavigation,
    headerRender,
  } = props;
  const { getPrefixCls } = useContext(ConfigContext);
  const isNavigationCollapsed = useMedia('(max-width: 768px)');
  const [showMobileNavigation, setShowMobileNavigation] = useState(false);
  const [layoutHeaderHeight, setLayoutHeaderHeight] = useLayoutHeaderHeight();

  const prefixCls = getPrefixCls('frame');

  const navigationNode = useRef<HTMLDivElement>(null);

  const [headerRef, { height: headerHeight }] = useMeasure<HTMLDivElement>();

  useEffect(() => {
    setLayoutHeaderHeight(headerHeight);
  }, [headerHeight, setLayoutHeaderHeight]);

  const formatMessage = useCallback(
    ({ id, defaultMessage, ...restParams }: { id: string; defaultMessage?: string }): string => {
      if (props.formatMessage) {
        return props.formatMessage({
          id,
          defaultMessage,
          ...restParams,
        });
      }
      return defaultMessage as string;
    },
    [props],
  );

  const {
    // breadcrumb = {},
    // breadcrumbMap,
    menuData = [],
  } = getMenuData(route?.routes || [], {}, formatMessage, menuDataRender);

  const clearMenuData = clearMenuItem(menuData);

  const finallyData = postMenuData ? postMenuData(clearMenuData) : clearMenuData;

  const getIntlName = useCallback(
    (item: MenuDataItem) => {
      const { name, locale } = item;
      if (locale) {
        return formatMessage?.({
          id: locale,
          defaultMessage: name,
        });
      }
      return name || '';
    },
    [formatMessage],
  );

  const renderItems = useCallback(
    (menu: MenuDataItem[]) =>
      menu.map(menuDataItem => {
        if (menuDataItem.children) {
          return {
            ...omit(menuDataItem, 'exact'),
            path: menuDataItem.path || '/',
            name: getIntlName(menuDataItem),
            subNavigationItems: menuDataItem.children.map(item => ({
              ...omit(item, 'exact'),
              path: item.path || '/',
              name: getIntlName(item),
            })),
          };
        }

        return {
          ...omit(menuDataItem, 'exact'),
          path: menuDataItem.path || '/',
          name: getIntlName(menuDataItem),
        };
      }),
    [getIntlName],
  );

  const header = useMemo(() => {
    const defaultDom = (
      <div className={`${prefixCls}-header-container`}>
        {isNavigationCollapsed && (
          <Button
            type="text"
            style={{
              padding: '6px 10px',
              marginLeft: -10,
            }}
            onClick={() => setShowMobileNavigation(!showMobileNavigation)}
          >
            <MenuOutlined />
          </Button>
        )}
        <div style={{ flex: '1 1 0%' }}>
          <div className={`${prefixCls}-header-left`}>{leftContent}</div>
        </div>
        <div className={`${prefixCls}-header-right`}>{rightContent}</div>
      </div>
    );

    return (
      <div className={`${prefixCls}-header`} ref={headerRef}>
        {headerRender ? headerRender(defaultDom) : defaultDom}
      </div>
    );
  }, [
    headerRef,
    headerRender,
    isNavigationCollapsed,
    leftContent,
    prefixCls,
    rightContent,
    showMobileNavigation,
  ]);

  return (
    <div className={prefixCls}>
      {header}
      <CSSTransition
        nodeRef={navigationNode}
        appear={isNavigationCollapsed}
        exit={isNavigationCollapsed}
        in={showMobileNavigation}
        timeout={300}
        classNames={{
          enter: `${prefixCls}-navigation-enter`,
          enterActive: `${prefixCls}-navigation-enter-active`,
          enterDone: `${prefixCls}-navigation-enter-active`,
          exit: `${prefixCls}-navigation-exit`,
          exitActive: `${prefixCls}-navigation-exit-active`,
        }}
      >
        <div
          className={classNames({
            [`${prefixCls}-navigation`]: true,
            [`${prefixCls}-navigation-visible`]: showMobileNavigation,
          })}
          ref={navigationNode}
          style={{ top: layoutHeaderHeight, height: `calc(100% - ${layoutHeaderHeight}px)` }}
        >
          <Navigation
            location={location.pathname || '/'}
            title={menuExtra}
            menuItemRender={menuItemRender}
          >
            {isNavigationCollapsed && leftContent && (
              <div className={`${prefixCls}-header-top`}>{leftContent}</div>
            )}
            {renderNavigation ? (
              renderNavigation(finallyData, renderItems)
            ) : (
              <Navigation.Section items={renderItems(finallyData)} />
            )}
          </Navigation>
          <button
            type="button"
            className={`${prefixCls}-navigation-dismiss`}
            onClick={() => setShowMobileNavigation(false)}
          >
            <CloseOutlined />
          </button>
        </div>
      </CSSTransition>
      {showMobileNavigation && isNavigationCollapsed && (
        <div
          className={`${prefixCls}-backdrop`}
          onClick={() => setShowMobileNavigation(false)}
          onTouchStart={() => setShowMobileNavigation(false)}
        />
      )}
      <main className={`${prefixCls}-main`} style={{ paddingTop: layoutHeaderHeight }}>
        <div className={`${prefixCls}-main-content`} style={contentStyle}>
          {children}
        </div>
      </main>
    </div>
  );
};

export default Frame;
