package com.cpop.system.business.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.cpop.common.constant.Constants;
import com.cpop.common.utils.StringUtils;
import com.cpop.common.utils.bean.BeanUtils;
import com.cpop.core.base.entity.LoginUser;
import com.cpop.core.base.enums.InitRoleEnum;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.utils.SecurityUtils;
import com.cpop.system.business.bo.MenuBo;
import com.cpop.system.business.bo.MenuListBo;
import com.cpop.system.business.entity.Menu;
import com.cpop.system.business.mapper.MenuMapper;
import com.cpop.system.business.service.MenuService;
import com.cpop.system.business.vo.MenuRouteVo;
import com.cpop.system.business.vo.MenuVo;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static com.cpop.system.business.entity.table.MenuTableDef.MENU;
import static com.cpop.system.business.entity.table.RoleMenuTableDef.ROLE_MENU;
import static com.cpop.system.business.entity.table.RoleTableDef.ROLE;

/**
 * 系统菜单表 服务层实现。
 *
 * @author DB
 * @since 2023-10-19
 */
@Service("menuService")
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    /**
     * @descriptions 获取系统菜单树列表
     * @author DB
     * @date 2023/10/19 14:39
     * @return: java.util.List<com.cpop.system.business.vo.MenuRouteVo>
     */
    @Override
    public List<MenuRouteVo> getSysMenuList() {
        //获取用户信息
        LoginUser user = SecurityUtils.getInstance().getLoginUser();
        //获取申请员工信息
        JSONObject loginStaffInfo = SecurityUtils.getInstance().getLoginUserInfo();
        //超级管理员
        if (Constants.SUPER_ADMIN.equals(user.getUsername())) {
            //获取菜单
            List<MenuRouteVo> list = this.listAs(QueryWrapper.create()
                            .where(MENU.TYPE.in(0, 1))
                            //构建公共菜单与特有菜单
                            .and(MENU.USER_TYPE.eq(user.getUserType()))
                            .orderBy(MENU.ORDER_NO.asc()),
                    MenuRouteVo.class);
            return buildMenuRouteTree(list);
        } else {
            //一般管理员
            if (StringUtils.equals(loginStaffInfo.getString("roleId"), InitRoleEnum.SUPER_MALL_ROLE.getId())) {
                return buildMenuRouteTree(this.listAs(QueryWrapper.create()
                                .where(MENU.TYPE.in(0, 1))
                                //构建公共菜单与特有菜单
                                .and(MENU.USER_TYPE.eq(user.getUserType()))
                                .where(MENU.STATUS.eq(1))
                                .and(MENU.NAME.notIn(Constants.HIDE_MENU.split(",")))
                                .orderBy(MENU.ORDER_NO.asc()),
                        MenuRouteVo.class));
            }else {
                return buildMenuRouteTree(this.listAs(QueryWrapper.create()
                                .select(MENU.ALL_COLUMNS)
                                .leftJoin(ROLE_MENU).on(ROLE_MENU.MENU_ID.eq(MENU.ID))
                                .leftJoin(ROLE).on(ROLE.ID.eq(ROLE_MENU.ROLE_ID))
                                .where(MENU.STATUS.eq(1))
                                .and(MENU.TYPE.in(0, 1))
                                .and(MENU.NAME.notIn(Constants.HIDE_MENU.split(",")))
                                .and(ROLE_MENU.ROLE_ID.eq(loginStaffInfo.getString("roleId")))
                                //构建公共菜单与特有菜单
                                .and(MENU.USER_TYPE.eq(user.getUserType()))
                                .orderBy(MENU.ORDER_NO.asc()),
                        MenuRouteVo.class));
            }
        }
    }

    @Override
    public List<MenuVo> getSysMenuTreeList(MenuListBo bo) {
        //获取用户信息
        LoginUser user = SecurityUtils.getInstance().getLoginUser();
        return buildMenuTree(this.listAs(QueryWrapper.create()
                //状态不为空
                .and(MENU.STATUS.eq(bo.getStatus()))
                //标题不为空
                .and(MENU.TITLE.like(bo.getTitle()))
                //构建公共菜单与特有菜单
                .and(MENU.USER_TYPE.eq(user.getUserType()))
                .and(MENU.NAME.notIn(Constants.HIDE_MENU.split(",")))
                .orderBy(MENU.ORDER_NO.asc()), MenuVo.class));
    }

    @Override
    public List<MenuVo> getDirectoryAndMenuTreeList() {
        //只读取启用的菜单
        return buildMenuTree(this.listAs(QueryWrapper.create()
                        .where(MENU.TYPE.in(0, 1))
                        .orderBy(MENU.ORDER_NO.asc())
                , MenuVo.class));
    }

    /**
     * @descriptions 构建菜单树
     * @author DB
     * @date 2023/09/07 16:36
     * @param menus 菜单集合
     * @return java.util.List<com.jambox.OAMtem.business.vo.OAMMenuVo>
     */
    private List<MenuVo> buildMenuTree(List<MenuVo> menus) {
        List<MenuVo> returnList = new ArrayList<MenuVo>();
        if (menus.isEmpty()) {
            return menus;
        }
        //构建根节点
        List<MenuVo> tempList = menus.stream()
                .filter(s -> StringUtils.isBlank(s.getParentMenu())).collect(Collectors.toList());
        for (MenuVo menu : tempList) {
            MenuVo menuVo = recursionFn(menus, menu);
            returnList.add(menuVo);
        }
        return returnList;
    }

    /**
     * @descriptions 递归列表
     * @author DB
     * @date 2023/09/07 16:36
     * @param list 递归集合
     * @param menu 菜单
     * @return com.jambox.OAMtem.business.vo.OAMMenuVo
     */
    private MenuVo recursionFn(List<MenuVo> list, MenuVo menu) {
        // 得到子节点列表
        List<MenuVo> childList = new ArrayList<MenuVo>();
        for (MenuVo menuNode : list) {
            if (null != menuNode.getParentMenu() && menuNode.getParentMenu().equals(menu.getId())) {
                childList.add(recursionFn(list, menuNode));
            }
        }
        if (!childList.isEmpty()){
            menu.setChildren(childList);
        }
        return menu;
    }

    @Override
    public void insertSysMenu(MenuBo bo) {
        Menu entity = new Menu();
        BeanUtils.copyBeanProp(entity, bo);
        //设置菜单名
        if (StringUtils.isNotBlank(bo.getPath())){
            String[] split = bo.getPath().split("/");
            String name = StringUtils.getMethodName(split[split.length - 1].replace("/", ""));
            LoginUser loginUser = SecurityUtils.getInstance().getLoginUser();
            //名字不能重复
            long count = this.count(QueryWrapper.create().where(MENU.NAME.eq(name)).and(MENU.USER_TYPE.eq(loginUser.getUserType().toString())));
            if (count > 0) {
                throw new ServiceException("命名失败,请调整路径");
            }
            entity.setName(name);
        } else {
            entity.setName(null);
        }
        //设置组件
        if (StringUtils.isBlank(bo.getComponent())){
            entity.setComponent("LAYOUT");
        }
        //获取当前用户
        entity.setUserType(SecurityUtils.getInstance().getLoginUser().getUserType().toString());
        this.save(entity);
    }

    @Override
    public void updateSysMenu(MenuBo bo) {
        Menu entity = new Menu();
        BeanUtils.copyBeanProp(entity, bo);
        //设置菜单名
        if (StringUtils.isNotBlank(bo.getPath())){
            String[] split = bo.getPath().split("/");
            String toUpperCaseString = split[split.length - 1];
            if (toUpperCaseString.contains(":")) {
                toUpperCaseString = split[split.length - 2];
            }
            String name = StringUtils.getMethodName(toUpperCaseString.replace("/", ""));
            LoginUser loginUser = SecurityUtils.getInstance().getLoginUser();
            //名字不能重复
            long count = this.count(QueryWrapper.create().where(MENU.NAME.eq(name)).and(MENU.USER_TYPE.eq(loginUser.getUserType().toString())));
            if (count > 1) {
                throw new ServiceException("命名失败,请调整路径");
            }
            entity.setName(name);
        }
        //设置组件
        if (StringUtils.isBlank(bo.getComponent())){
            entity.setComponent("LAYOUT");
        }
        this.updateById(entity);
    }

    @Override
    public void removeSysMenu(String id) {
        //查询所有
        List<Menu> list = this.list();
        //递归获取当前菜单及其下属子菜单
        List<String> removeIds = new ArrayList<>();
        recursionRemove(list, id, removeIds);
        removeIds.add(id);
        this.removeByIds(removeIds);
    }

    /**
     * @Description: 递归要删除的菜单集合
     * @param list 菜单集合
     * @param id id
     * @param removeIds 删除id集合
     * @Author: DB
     * @Date: 2023/5/10 15:27
     **/
    private void recursionRemove(List<Menu> list, String id, List<String> removeIds) {
        //过滤出删除根菜单
        List<Menu> sonMenu = list.stream().filter(s -> null != s.getParentMenu()&& s.getParentMenu().equals(id)).collect(Collectors.toList());
        if (!sonMenu.isEmpty()) {
            sonMenu.forEach(item -> {
                recursionRemove(list, item.getId(), removeIds);
                removeIds.add(item.getId());
            });
        }
    }

    /**
     * @Description: 构建菜单路由树
     * @param menus 菜单集合
     * @return: List<MenuRouteVo>
     * @Author: DB
     * @Date: 2023/5/11 9:21
     **/
    private List<MenuRouteVo> buildMenuRouteTree(List<MenuRouteVo> menus) {
        if (menus.isEmpty()){
            return menus;
        }
        //构建内部类
        menus.forEach(item->{
            MenuRouteVo.Meta meta = item.new Meta();
            meta.setIcon(item.getIcon());
            meta.setOrderNo(item.getOrderNo());
            meta.setTitle(item.getTitle());
            meta.setHideMenu(item.getHideMenu());
            meta.setIgnoreKeepAlive(item.getIgnoreKeepAlive());
            item.setMeta(meta);
        });
        //构建根节点
        List<MenuRouteVo> tempList = menus.stream()
                .filter(s -> StringUtils.isBlank(s.getParentMenu())).collect(Collectors.toList());
        List<MenuRouteVo> menuRoutes = new ArrayList<>();
        for (MenuRouteVo menu : tempList) {
            MenuRouteVo menuVo = recursionMenuRoute(menus, menu);
            //设置是否需要隐藏子内部菜单
            menuVo.getMeta().setHideChildrenInMenu(null != menuVo.getChildren() && menuVo.getChildren().size() == 1 && menuVo.getChildren().get(0).getHideMenu());
            menuRoutes.add(menuVo);
        }
        return BeanUtils.mapToList(menuRoutes, MenuRouteVo.class);
    }

    /**
     * @Description: 递归列表
     * @param list 菜单集合
     * @param menu 菜单
     * @return: MenuRouteVo
     * @Author: DB
     * @Date: 2023/5/11 9:22
     **/
    private MenuRouteVo recursionMenuRoute(List<MenuRouteVo> list, MenuRouteVo menu) {
        // 得到子节点列表
        List<MenuRouteVo> childList = new ArrayList<MenuRouteVo>();
        for (MenuRouteVo menuNode : list) {
            if (StringUtils.isNotBlank(menuNode.getParentMenu()) && menuNode.getParentMenu().equals(menu.getId())) {
                childList.add(recursionMenuRoute(list, menuNode));
            }
        }
        menu.setChildren(childList);
        return menu;
    }
}
