import React, { useState, ReactNode, useRef, useEffect, useMemo } from 'react';
import { Layout, Menu, Breadcrumb, Spin } from '@arco-design/web-react';
import cs from 'classnames';
import {
  IconApps,
  IconMenuFold,
  IconMenuUnfold,
  IconArchive,
  IconUnorderedList,
  IconMindMapping,
  IconCommon,
  IconCode,
  IconHome,
  IconStorage
} from '@arco-design/web-react/icon';
import { useSelector } from 'react-redux';
import { useRouter } from 'next/router';
import Link from 'next/link';
import qs from 'query-string';
import Navbar from '../components/NavBar';
import Footer from '../components/Footer';
import useRoute, { IRoute } from '@/routes';
import useLocale from '@/utils/useLocale';
import getUrlParams from '@/utils/getUrlParams';
import styles from '@/style/layout.module.less';
import NoAccess from '@/pages/exception/403';
import { openWindow, OpenWindowOptions } from '@/utils/common';

const MenuItem = Menu.Item;
const SubMenu = Menu.SubMenu;

const Sider = Layout.Sider;
const Content = Layout.Content;

function getIconFromKey(key) {
  switch (key) {
    case 'dashboard/workplace':
      return <IconHome className={styles.icon} />;
    case 'scene':
      return <IconArchive className={styles.icon} />;
    case 'application':
      return <IconApps className={styles.icon} />;
    case 'instance':
      return <IconUnorderedList className={styles.icon} />;
    case 'componentDevelopment':
      return <IconCode className={styles.icon} />;
    case 'componentLibrary':
      return <IconMindMapping className={styles.icon} />;
    case 'compositeCompLibrary':
      return <IconCommon className={styles.icon} />;
    case 'componentMarket':
      return <IconStorage className={styles.icon} />;
    default:
      return <div className={styles['icon-empty']} />;
  }
}

function PageLayout({ children }: { children: ReactNode }) {
  const urlParams = getUrlParams();
  const router = useRouter();
  const pathname = router.pathname;
  const currentComponent = qs.parseUrl(pathname).url.slice(1);
  const locale = useLocale();
  const { settings } = useSelector((state) => state.global);
  const { userInfo, userLoading } = useSelector((state) => state.user);

  const [collapsed, setCollapsed] = useState<boolean>(false);

  const [routes, defaultRoute] = useRoute(userInfo?.permissions);

  const defaultSelectedKeys = [currentComponent || defaultRoute];
  const paths = (currentComponent || defaultRoute).split('/');
  const defaultOpenKeys = paths.slice(0, paths.length - 1);

  const [selectedKeys, setSelectedKeys] =
    useState<string[]>(defaultSelectedKeys);
  const [openKeys, setOpenKeys] = useState<string[]>(defaultOpenKeys);

  const navbarHeight = 60;
  const menuWidth = collapsed ? 48 : settings?.menuWidth;

  const showNavbar = settings?.navbar && urlParams.navbar !== false;
  const showMenu = settings?.menu && urlParams.menu !== false && !pathname.includes('ideContainer');
  const showFooter = settings?.footer && urlParams.footer !== false;
  const showWrapperPadding = settings?.noWrapperPadding || pathname.includes('ideContainer');

  const routeMap = useRef<Map<string, ReactNode[]>>(new Map());
  const menuMap = useRef<
    Map<string, { menuItem?: boolean; subMenu?: boolean }>
  >(new Map());

  const [breadcrumb, setBreadCrumb] = useState([]);

  function onClickMenuItem(key: string) {
    if (key === 'componentDevelopment') {
      const url = `/ideContainer`;
      const params: OpenWindowOptions = {
        target: '_blank',
        menu: false,
        identity: key
      };
      openWindow(url, params);
    }
    else setSelectedKeys([key]);
  }

  function toggleCollapse() {
    setCollapsed((collapsed) => !collapsed);
  }

  const paddingLeft = showMenu ? { paddingLeft: menuWidth } : {};
  const paddingTop = showNavbar ? { paddingTop: navbarHeight } : {};
  const paddingStyle = { ...paddingLeft, ...paddingTop };

  const routeMapMemo = useMemo(() => {
    const map = new Map<string, ReactNode[]>();

    function buildRouteMap(_routes: IRoute[], parentNode = []) {
      _routes.forEach((route) => {
        const { breadcrumb = true, ignore } = route;

        map.set(
          `/${route.key}`,
          breadcrumb ? [...parentNode, route.name] : []
        );

        const visibleChildren = (route.children || []).filter((child) => {
          const { ignore, breadcrumb = true } = child;
          if (ignore || route.ignore) {
            map.set(
              `/${child.key}`,
              breadcrumb ? [...parentNode, route.name, child.name] : []
            );
          }
          return !ignore;
        });

        if (!ignore && visibleChildren.length) {
          buildRouteMap(visibleChildren, [...parentNode, route.name]);
        }
      });
    }

    buildRouteMap(routes);
    return map;
  }, [routes]);

  function renderRoutes(locale) {
    return function travel(_routes: IRoute[], level, parentNode = []) {
      return _routes.map((route) => {
        const { ignore } = route;
        const iconDom = getIconFromKey(route.key);
        const titleDom = (
          <>
            {iconDom} {locale[route.name] || route.name}
          </>
        );

        const visibleChildren = (route.children || []).filter((child) => {
          return !child.ignore;
        });

        if (ignore) {
          return '';
        }

        if (visibleChildren.length) {
          menuMap.current.set(route.key, { subMenu: true });
          return (
            <SubMenu key={route.key} title={titleDom}>
              {travel(visibleChildren, level + 1, [...parentNode, route.name])}
            </SubMenu>
          );
        }

        menuMap.current.set(route.key, { menuItem: true });

        if (route?.openWindow) {
          return (
            <MenuItem key={route.key}>
              <a suppressHydrationWarning>{titleDom}</a>
            </MenuItem>
          );
        }
        else {
          return (
            <MenuItem key={route.key}>
              <Link href={`/${route.key}`} passHref>
                <a suppressHydrationWarning>{titleDom}</a>
              </Link>
            </MenuItem>
          );
        }
      });
    };
  }

  function updateMenuStatus() {
    const pathKeys = pathname.split('/');
    const newSelectedKeys: string[] = [];
    const newOpenKeys: string[] = [...openKeys];
    while (pathKeys.length > 0) {
      const currentRouteKey = pathKeys.join('/');
      const menuKey = currentRouteKey.replace(/^\//, '');
      const menuType = menuMap.current.get(menuKey);
      if (menuType && menuType.menuItem) {
        newSelectedKeys.push(menuKey);
      }
      if (menuType && menuType.subMenu && !openKeys.includes(menuKey)) {
        newOpenKeys.push(menuKey);
      }
      pathKeys.pop();
    }
    setSelectedKeys(newSelectedKeys);
    setOpenKeys(newOpenKeys);
  }

  useEffect(() => {
    const routeConfig = routeMapMemo.get(pathname);
    setBreadCrumb(routeConfig || []);
    updateMenuStatus();
  }, [pathname]);

  return (
    <Layout className={styles.layout}>
      <div
        className={cs(styles['layout-navbar'], {
          [styles['layout-navbar-hidden']]: !showNavbar
        })}
      >
        <Navbar show={showNavbar} />
      </div>
      {userLoading ? (
        <Spin className={styles['spin']} />
      ) : (
        <Layout>
          {showMenu && (
            <Sider
              className={styles['layout-sider']}
              width={menuWidth}
              collapsed={collapsed}
              onCollapse={setCollapsed}
              trigger={null}
              collapsible
              breakpoint="xl"
              style={paddingTop}
            >
              <div className={styles['menu-wrapper']}>
                <Menu
                  collapse={collapsed}
                  onClickMenuItem={onClickMenuItem}
                  selectedKeys={selectedKeys}
                  openKeys={openKeys}
                  onClickSubMenu={(_, openKeys) => {
                    setOpenKeys(openKeys);
                  }}
                >
                  {renderRoutes(locale)(routes, 1)}
                </Menu>
              </div>
              <div className={styles['collapse-btn']} onClick={toggleCollapse}>
                {collapsed ? <IconMenuUnfold /> : <IconMenuFold />}
              </div>
            </Sider>
          )}
          <Layout className={styles['layout-content']} style={paddingStyle}>
            <div
              className={showWrapperPadding ? styles['layout-content-wrapper-no-padding '] : styles['layout-content-wrapper']}>
              {!!breadcrumb.length && (
                <div className={styles['layout-breadcrumb']}>
                  <Breadcrumb>
                    {breadcrumb.map((node, index) => (
                      <Breadcrumb.Item key={index}>
                        {typeof node === 'string' ? locale[node] || node : node}
                      </Breadcrumb.Item>
                    ))}
                  </Breadcrumb>
                </div>
              )}
              <Content>
                {routeMapMemo.has(pathname) ? children : <NoAccess />}
              </Content>
            </div>
            {/*{showFooter && <Footer />}*/}
          </Layout>
        </Layout>
      )}
    </Layout>
  );
}

export default PageLayout;
