package com.qiaoba.module.system.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.qiaoba.api.system.entity.vo.MetaVo;
import com.qiaoba.api.system.entity.vo.RouterVo;
import com.qiaoba.api.system.entity.vo.SysMenuVo;
import com.qiaoba.common.base.constant.BaseConstant;
import com.qiaoba.common.base.constant.MenuConstant;
import com.qiaoba.common.base.enums.BaseEnum;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * 菜单工具类
 *
 * @author ailanyin
 * @version 1.0
 * @since 2023/5/12 10:33
 */
public class MenuUtil {

    public static List<RouterVo> menusToRouters(List<SysMenuVo> menus) {
        List<SysMenuVo> tree = TreeUtil.buildTree(menus, SysMenuVo.class, "menuId", "parentId", "children");
        List<RouterVo> routers = new LinkedList<RouterVo>();
        for (SysMenuVo menu : tree) {
            RouterVo router = new RouterVo();
            router.setHidden(StrUtil.equals(BaseEnum.NO.getCode(), menu.getIsVisible()));
            router.setName(MenuUtil.getRouteName(menu));
            router.setPath(MenuUtil.getRouterPath(menu));
            router.setComponent(MenuUtil.getComponent(menu));
            router.setQuery(menu.getQuery());
            router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StrUtil.equals(BaseEnum.NO.getCode(), menu.getIsCache()), menu.getPath()));
            List<SysMenuVo> cMenus = menu.getChildren();
            if (CollUtil.isNotEmpty(cMenus) && MenuConstant.TYPE_DIR.equals(menu.getMenuType())) {
                router.setAlwaysShow(true);
                router.setRedirect(MenuConstant.NO_REDIRECT);
                router.setChildren(menusToRouters(cMenus));
            } else if (MenuUtil.isMenuFrame(menu)) {
                router.setMeta(null);
                List<RouterVo> childrenList = new ArrayList<RouterVo>();
                RouterVo children = new RouterVo();
                children.setPath(menu.getPath());
                children.setComponent(menu.getComponent());
                children.setName(StrUtil.upperFirst(menu.getPath()));
                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StrUtil.equals(BaseEnum.NO.getCode(), menu.getIsCache()), menu.getPath()));
                children.setQuery(menu.getQuery());
                childrenList.add(children);
                router.setChildren(childrenList);
            } else if (BaseConstant.DEFAULT_PARENT_ID_VALUE.equals(menu.getParentId()) && MenuUtil.isInnerLink(menu.getIsFrame(), menu.getPath())) {
                router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
                router.setPath("/");
                List<RouterVo> childrenList = new ArrayList<RouterVo>();
                RouterVo children = new RouterVo();
                String routerPath = MenuUtil.innerLinkReplaceEach(menu.getPath());
                children.setPath(routerPath);
                children.setComponent(MenuConstant.INNER_LINK);
                children.setName(StrUtil.upperFirst(routerPath));
                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));
                childrenList.add(children);
                router.setChildren(childrenList);
            }
            routers.add(router);
        }
        return routers;
    }

    /**
     * 获取路由名称
     *
     * @param menuVo 菜单信息
     * @return 路由名称
     */
    private static String getRouteName(SysMenuVo menuVo) {
        // 首字母大写
        String routerName = StrUtil.upperFirst(menuVo.getPath());
        // 非外链并且是一级目录（类型为目录）
        return isMenuFrame(menuVo) ? StrUtil.EMPTY : routerName;
    }

    /**
     * 是否为菜单内部跳转
     *
     * @param menuVo 菜单信息
     * @return 结果
     */
    private static boolean isMenuFrame(SysMenuVo menuVo) {
        return BaseConstant.DEFAULT_PARENT_ID_VALUE.equals(menuVo.getParentId()) && MenuConstant.TYPE_MENU.equals(menuVo.getMenuType())
                && menuVo.getIsFrame().equals(MenuConstant.NO_FRAME);
    }

    /**
     * 获取路由地址
     *
     * @param menuVo 菜单信息
     * @return 路由地址
     */
    private static String getRouterPath(SysMenuVo menuVo) {
        String routerPath = menuVo.getPath();
        // 内链打开外网方式
        if (!BaseConstant.DEFAULT_PARENT_ID_VALUE.equals(menuVo.getParentId()) && isInnerLink(menuVo.getIsFrame(), menuVo.getPath())) {
            routerPath = innerLinkReplaceEach(routerPath);
        }
        // 非外链并且是一级目录（类型为目录）
        if (BaseConstant.DEFAULT_PARENT_ID_VALUE.equals(menuVo.getParentId()) && MenuConstant.TYPE_DIR.equals(menuVo.getMenuType())
                && MenuConstant.NO_FRAME.equals(menuVo.getIsFrame())) {
            routerPath = "/" + menuVo.getPath();
        }
        // 非外链并且是一级目录（类型为菜单）
        else if (isMenuFrame(menuVo)) {
            routerPath = "/";
        }
        return routerPath;
    }

    /**
     * 获取组件信息
     *
     * @param menuVo 菜单信息
     * @return 组件信息
     */
    private static String getComponent(SysMenuVo menuVo) {
        String component = MenuConstant.LAYOUT;
        if (StrUtil.isNotEmpty(menuVo.getComponent()) && !isMenuFrame(menuVo)) {
            component = menuVo.getComponent();
        } else if (StrUtil.isEmpty(menuVo.getComponent()) && !BaseConstant.DEFAULT_PARENT_ID_VALUE.equals(menuVo.getParentId()) && isInnerLink(menuVo.getIsFrame(), menuVo.getPath())) {
            component = MenuConstant.INNER_LINK;
        } else if (StrUtil.isEmpty(menuVo.getComponent()) && isParentView(menuVo.getParentId(), menuVo.getMenuType())) {
            component = MenuConstant.PARENT_VIEW;
        }
        return component;
    }

    /**
     * 是否为内链组件
     *
     * @param isFrame isFrame
     * @param path    path
     * @return 结果
     */
    private static boolean isInnerLink(String isFrame, String path) {
        return MenuConstant.NO_FRAME.equals(isFrame) && (HttpUtil.isHttp(path) || HttpUtil.isHttps(path));
    }

    /**
     * 内链域名特殊字符替换
     */
    private static String innerLinkReplaceEach(String path) {
        return path.replaceAll(BaseConstant.HTTP, "").replaceAll(BaseConstant.HTTPS, "");
    }

    /**
     * 是否为parent_view组件
     *
     * @param parentId parentId
     * @param menuType menuType
     * @return 结果
     */
    private static boolean isParentView(String parentId, String menuType) {
        return !BaseConstant.DEFAULT_PARENT_ID_VALUE.equals(parentId) && MenuConstant.TYPE_DIR.equals(menuType);
    }

}
