import React, { useEffect } from 'react';
import memoizeOne from 'memoize-one';
//@ts-ignore
import isEqual from 'lodash/isEqual';
import API from '@/api';
import _ from 'lodash';
import pathToRegexp from 'path-to-regexp';
import { Base64 } from 'js-base64';
import { urlToList } from '@/utils';
import { history } from 'umi';
import { buildIcon } from '@/lib';
import { Storage } from '@/utils';
import { MenuDataItem } from '@/layouts/BaseLayout/typings';

/**
 * Recursively flatten the data
 * [{path:string},{path:string}] => {path,path2}
 * @param  menus
 */
const getFlatMenuKeys: (menuData: any) => Array<string> = (menuData) => {
  let keys = [] as Array<string>;
  menuData.forEach((item: any) => {
    keys.push(item.path);
    if (item.routes) {
      keys = keys.concat(getFlatMenuKeys(item.routes));
    }
  });
  return keys;
};

/**
 * 获取面包屑映射
 * @param {Object} menuData 菜单配置
 */
const getBreadcrumbNameMap: (menuData: any) => any = (menuData) => {
  if (!menuData) {
    return {};
  }
  const routerMap = {};

  const flattenMenuData = (data: any) => {
    data.forEach((menuItem: any) => {
      if (menuItem.routes) {
        flattenMenuData(menuItem.routes);
      }
      // Reduce memory usage
      routerMap[menuItem.path] = menuItem;
    });
  };
  flattenMenuData(menuData);
  return routerMap;
};

const memoizeOneGetBreadcrumbNameMap = memoizeOne(
  getBreadcrumbNameMap,
  isEqual,
);

const buildMenuData: (menus: any) => AnyObject[] = (menus) => {
  let root = [] as AnyObject[];
  const map = _.reduce(
    menus,
    (ret: any, menu: any) => {
      const node = {
        ...menu,
      };
      if (!node.pid || node.pid === '0') {
        root.push(node);
      }
      _.set(ret, menu.id, node);
      return ret;
    },
    {},
  );

  _.forEach(map, (menu: any) => {
    if (menu.pid) {
      let parent = map[menu.pid];
      if (parent) {
        if (!parent.routes) {
          parent.routes = [];
        }
        parent.routes.push(menu);
      }
    }
  });

  root = _.sortBy(root, 'order');

  return root;
};

const getMenuMatches = (flatMenuKeys: string[], path: string) =>
  flatMenuKeys.filter((item: string) => {
    if (item) {
      return pathToRegexp(item.split('?')[0]).test(path.split('?')[0]);
    }
    return false;
  });

/**
 * 获得默认展开菜单
 */
const getDefaultCollapsedSubMenus = (
  flatMenuKeys: string[],
  breadcrumbMap: any,
  originalMenu: any,
) => {
  const {
    location: { pathname, query },
  } = history;
  if (query && query.embed_url) {
    const path = Base64.decode(query.embed_url as string);
    const menu = _.find(breadcrumbMap, (menu: MenuDataItem, k: string) => {
      if (path.indexOf(k) === 0) {
        return menu;
      }
      return null;
    });
    if (_.isEmpty(menu)) {
      return [];
    }
    return [menu.pid];
  }

  let currentMenu = breadcrumbMap[pathname];
  if (_.isEmpty(currentMenu)) {
    return [];
  }

  const ret = [];
  do {
    ret.push(currentMenu.pid);
    currentMenu = _.find(
      originalMenu,
      (menu: MenuDataItem) => menu.id === currentMenu.pid,
    );
  } while (currentMenu && currentMenu.pid);

  return ret;
};

/**
 * 获得默认选中菜单
 */
const getDefaultSelectMenus: (
  flatMenuKeys: string[],
  breadcrumbNameMap: any,
) => string[] = (flatMenuKeys, breadcrumbNameMap) => {
  const {
    location: { pathname },
  } = history;
  const selectMenuPaths = urlToList(pathname)
    .map((item: string) => getMenuMatches(flatMenuKeys, item)[0])
    .filter((item: string) => item);
  return _.reduce(
    selectMenuPaths,
    (ret: string[], path: string) => {
      if (breadcrumbNameMap[path]) {
        ret.push(_.get(breadcrumbNameMap[path], 'key'));
      }
      return ret;
    },
    [],
  );
};

const filterMenu = (originalMenus: any[], key: string) => {
  const filtered = _.filter(originalMenus, (menu: any) => menu?.name?.indexOf(key) >= 0);
  return buildMenuData(filtered);
}

/**
 * 获取用户权限菜单hook
 * @param
 * @returns [menuData, originalMenu, breadCrumbMap]
 * - menuData 菜单数据
 * - originalMenu 原始菜单数据
 * - breadCrumbMap 面包屑数据
 */
export function useMenu<S extends AnyObject>() {
  const [menuData, setMenuData] = React.useState<AnyObject[]>([]);
  const [originalMenu, setOriginalMenu] = React.useState<AnyObject[]>([]);
  const [breadCrumbMap, setBreadCrumbMap] = React.useState({});
  const [defaultCollapseMenus, setDefaultCollapseMenus] = React.useState<
    Array<string>
  >([]);
  const [defaultSelectMenus, setDefaultSelectMenus] = React.useState<
    Array<string>
  >([]);

  // iconContent: "icon-changyongtubiao-mianxing-17"
  // iconStyle: "{}"
  // iconType: "FONT"

  useEffect(() => {
    API.MenuService.getAccountMenu().then(({ success, data }) => {
      if (success) {
        let menus = _.map(data.data || [], (menu: any) => ({
          key: menu.id,
          id: menu.id,
          pid: menu.pid,
          name: menu.name,
          path: menu.url,
          dataPath: menu.path,
          icon: _.isEmpty(menu.iconContent)
            ? 'icon-appstore'
            : buildIcon(
              menu.iconType,
              menu.iconContent,
              /\{.*\}/.test(menu.iconStyle) ? JSON.parse(menu.iconStyle) : {},
            ),
          order: menu.order,
        }));
        setOriginalMenu(menus);
        const buildMenus = buildMenuData(menus);
        setMenuData(buildMenus);
        const flatMenuKeys = getFlatMenuKeys(buildMenus);
        const breadCrumbMap = memoizeOneGetBreadcrumbNameMap(buildMenus);
        const defaultCollapseMenus = getDefaultCollapsedSubMenus(
          flatMenuKeys,
          breadCrumbMap,
          menus,
        );
        const defaultSelectMenus = getDefaultSelectMenus(
          flatMenuKeys,
          breadCrumbMap,
        );
        if (_.isEmpty(defaultSelectMenus)) {
          const sessionStoreKey = Storage.session.get('ACTIVE_MENU_KEY');
          defaultSelectMenus.push(sessionStoreKey)
        }
        if (_.isEmpty(defaultCollapseMenus)) {
          const sessionStoreKey = Storage.session.get('OPEN_MENU_KEY');
          defaultCollapseMenus.push(...(sessionStoreKey || []))
        }
        setBreadCrumbMap(breadCrumbMap);
        setDefaultCollapseMenus(defaultCollapseMenus);
        setDefaultSelectMenus(defaultSelectMenus);
      }
    });
  }, []);

  return [
    menuData,
    breadCrumbMap,
    defaultCollapseMenus,
    defaultSelectMenus,
    originalMenu,
    filterMenu,
  ] as const;
}
