package com.system.oauth.system.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.system.framework.core.constant.CacheConstant;
import com.system.framework.core.exception.StarBosException;
import com.system.framework.core.utils.oConvertUtils;
import com.system.oauth.constant.enums.PermissionTypeEnum;
import com.system.oauth.system.entity.SysPermission;
import com.system.oauth.system.entity.SysRole;
import com.system.oauth.system.entity.SysRolePermission;
import com.system.oauth.system.mapper.SysPermissionMapper;
import com.system.oauth.system.service.ISysPermissionService;
import com.system.oauth.system.service.ISysRolePermissionService;
import com.system.oauth.system.service.ISysRoleService;
import com.system.oauth.system.vo.MenuPage;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class SysPermissionServiceImpl extends ServiceImpl<SysPermissionMapper, SysPermission> implements ISysPermissionService {

    @Autowired
    ISysRolePermissionService rolePermissionService;
    @Autowired
    ISysRoleService roleService;


    public List<MenuPage> getUserMenu(Integer userId) {
//        查用户所有角色
        List<SysRole> roles = roleService.selectByUserId(userId);
//        List<Integer> roleIds = roleService.selectRoleIdByUserId(userId);//用了这个时间反而更长了，数据多了或许还有用
        List<String> roleIds = new ArrayList<>();
        roles.forEach((r -> {
            roleIds.add(r.getId());
        }));
        List<SysPermission> permissionBase = this.findMenuByUserId(userId);//
//        List<Permission> permissionLNotBase = this.selectAllNotBase(userId);//查询用户除了一级菜单以外的菜单
        List<String> parmIds = new ArrayList<>();
        permissionBase.forEach((r -> {
            parmIds.add(r.getId());
        }));

        List<SysRolePermission> rolePermissions = rolePermissionService.selectInUser(roleIds, parmIds);//

//        List<Permission> menus = iterateTreeList(permissionBase, null);

//        List<MenuPage> menuBase = iterateMenus(menus, rolePermissions, roles);//
        List<MenuPage> menuBase = MenuTreeList(permissionBase, null, rolePermissions, roles);
//        System.out.println(rolePermissions);
        return menuBase;
    }

    public List<MenuPage> iterateMenus(List<SysPermission> permission, List<SysRolePermission> rolePermissions, List<SysRole> roles) {
        List<MenuPage> menuBase = new ArrayList<>();//
        permission.forEach((p -> {
            List<String> MetaRoles = metaRolesSetUp(rolePermissions, p, roles);//获取对应角色
            MenuPage menuPage = new MenuPage(p, MetaRoles);
            if (p.getChildren() != null && p.getChildren().size() >= 1) {
                List<MenuPage> menuPages = iterateMenus(p.getChildren(), rolePermissions, roles);
                menuPage.setChildren(menuPages);
            }
            menuBase.add(menuPage);
        }));
        return menuBase;
    }

    private List<String> metaRolesSetUp(List<SysRolePermission> rolePermissions, SysPermission p, List<SysRole> roles) {
        List<SysRolePermission> removePool = new ArrayList<>();
        List<String> MetaRoles = new ArrayList<>();
        for (int i = rolePermissions.size() - 1; i >= 0; i--) {
            SysRolePermission rp = rolePermissions.get(i);
            if (p.getId().equals(rp.getPermId())) {
                roles.forEach((role -> {
                    if (rp.getRoleId().equals(role.getId())) {
                        MetaRoles.add("sys:" + role.getRoleCode());
                        removePool.add(rp);//删除已配对的对应关系
                    }
                }));
            }
        }
        rolePermissions.removeAll(removePool);
        return MetaRoles;
    }

    /**
     * 多级菜单查询方法
     *
     * @param menuVoList 不包含最高层次菜单的菜单集合
     * @param pid        父类id
     * @return
     */
    public List<SysPermission> iterateTreeList(List<SysPermission> menuVoList, String pid) {
        List<SysPermission> result = new ArrayList<SysPermission>();
        if (pid == null) {
            for (SysPermission menu : menuVoList) {
                if (menu.getParentId().equals("0")) {
                    List<SysPermission> menus = iterateTreeList(menuVoList, menu.getId().toString());
                    menu.setChildren(menus);
                    result.add(menu);
                }
            }
        } else if (pid != null) {
            for (SysPermission menu : menuVoList) {
                //获取菜单的id
                String menuid = menu.getId().toString();
                //获取菜单的父id
                String parentid = menu.getParentId().toString();
                if (StringUtils.isNotBlank(parentid)) {
                    if (parentid.equals(pid)) {
                        //递归查询当前子菜单的子菜单
                        List<SysPermission> iterateMenu = iterateTreeList(menuVoList, menuid);
                        menu.setChildren(iterateMenu);
                        result.add(menu);
                    }
                }
            }
        }

        return result;
    }

    public List<MenuPage> MenuTreeList(List<SysPermission> menuVoList, String pid, List<SysRolePermission> rolePermissions, List<SysRole> roles) {
        List<MenuPage> result = new ArrayList<MenuPage>();
        if (pid == null) {
            for (SysPermission menu : menuVoList) {
                if (menu.getParentId().equals("0")) {
                    List<String> MetaRoles = metaRolesSetUp(rolePermissions, menu, roles);//获取对应角色

                    MenuPage menuPage = new MenuPage(menu, MetaRoles);

                    List<MenuPage> menus = MenuTreeList(menuVoList, menu.getId().toString(), rolePermissions, roles);
                    menuPage.setChildren(menus);
                    result.add(menuPage);
                }
            }
        } else if (pid != null) {
            for (SysPermission menu : menuVoList) {
                //获取菜单的id
                String menuid = menu.getId().toString();
                //获取菜单的父id
                String parentid = menu.getParentId().toString();
                if (StringUtils.isNotBlank(parentid)) {
                    if (parentid.equals(pid)) {
                        List<String> MetaRoles = metaRolesSetUp(rolePermissions, menu, roles);//获取对应角色
                        MenuPage menuPage = new MenuPage(menu, MetaRoles);
                        //递归查询当前子菜单的子菜单
                        List<MenuPage> iterateMenu = MenuTreeList(menuVoList, menuid, rolePermissions, roles);
                        menuPage.setChildren(iterateMenu);
                        result.add(menuPage);
                    }
                }
            }
        }

        return result;
    }


    @Override
    @CacheEvict(value = CacheConstant.SYS_DATA_PERMISSIONS_CACHE, allEntries = true)
    public void addPermission(SysPermission sysPermission) {
        //----------------------------------------------------------------------
        //判断是否是一级菜单，是的话清空父菜单
        if (PermissionTypeEnum.FIRST_LEVEL_MENU.getKey().equals(sysPermission.getType())) {
            sysPermission.setParentId("0");
        } else {
            //判断二级菜单，按钮所属父菜单
            String pid = sysPermission.getParentId().toString();
            if (oConvertUtils.isNotEmpty(pid) && !pid.equals("0")) {
                //设置父节点不为叶子节点
                this.baseMapper.setMenuLeaf(pid, 0);
            }
        }
//        String pid = sysPermission.getParentId().toString();
//        if (oConvertUtils.isNotEmpty(pid)) {
//            //设置父节点不为叶子节点
//            this.baseMapper.setMenuLeaf(pid, 0);
//        }
        //设置为叶子节点
        sysPermission.setHasChildren(true);
        this.save(sysPermission);
    }

    @Override
    @CacheEvict(value = CacheConstant.SYS_DATA_PERMISSIONS_CACHE, allEntries = true)
    public void editPermission(SysPermission sysPermission) throws StarBosException {
        SysPermission p = this.getById(sysPermission.getId());
        //TODO 该节点判断是否还有子节点
        if (p == null) {
            throw new StarBosException("未找到菜单信息");
        } else {
            sysPermission.setFmodifyDate(new Date());
            //----------------------------------------------------------------------
            //Step1.判断是否是一级菜单，是的话清空父菜单ID
            if (PermissionTypeEnum.FIRST_LEVEL_MENU.getKey().equals(sysPermission.getType())) {
                sysPermission.setParentId("0");
            }
            //Step2.判断菜单下级是否有菜单，无则设置为叶子节点
            int count = this.count(new QueryWrapper<SysPermission>().lambda().eq(SysPermission::getParentId, sysPermission.getId()));
            if (count == 0) {
                sysPermission.setHasChildren(true);
            }
            //----------------------------------------------------------------------
            this.updateById(sysPermission);

            //如果当前菜单的父菜单变了，则需要修改新父菜单和老父菜单的，叶子节点状态
            String pid = sysPermission.getParentId().toString();
            if ((oConvertUtils.isNotEmpty(pid) && !pid.equals(p.getParentId())) || oConvertUtils.isEmpty(pid) && oConvertUtils.isNotEmpty(p.getParentId())) {
                //a.设置新的父菜单不为叶子节点
                this.baseMapper.setMenuLeaf(pid, 0);
                //b.判断老的菜单下是否还有其他子菜单，没有的话则设置为叶子节点
                int cc = this.count(new QueryWrapper<SysPermission>().lambda().eq(SysPermission::getParentId, p.getParentId()));
                if (cc == 0) {
                    if (oConvertUtils.isNotEmpty(p.getParentId())) {
                        this.baseMapper.setMenuLeaf(p.getParentId().toString(), 1);
                    }
                }

            }
        }

    }

    @Override
    @Transactional
    @CacheEvict(value = CacheConstant.SYS_DATA_PERMISSIONS_CACHE, allEntries = true)
    public void deletePermission(String id) {
        SysPermission sysPermission = this.getById(id);
        if (sysPermission == null) {
            throw new StarBosException("未找到菜单信息");
        }
        String pid = sysPermission.getParentId().toString();
        if (oConvertUtils.isNotEmpty(pid)) {
            int count = this.count(new QueryWrapper<SysPermission>().lambda().eq(SysPermission::getParentId, pid));
            if (count == 1) {
                //若父节点无其他子节点，则该父节点是叶子节点
                this.getBaseMapper().setMenuLeaf(pid, 1);
            }
        }
        Map map = new HashMap<>();
        map.put("perm_id", id);

        // 该节点可能是子节点但也可能是其它节点的父节点,所以需要级联删除
        this.removeChildrenBy(sysPermission.getId().toString());
        //删除角色授权表
        rolePermissionService.getBaseMapper().deleteByMap(map);

        this.baseMapper.deleteById(id);


    }

    /**
     * 根据父id删除其关联的子节点数据
     *
     * @return
     */
    public void removeChildrenBy(String parentId) {
        LambdaQueryWrapper<SysPermission> query = new LambdaQueryWrapper<>();
        // 封装查询条件parentId为主键,
        query.eq(SysPermission::getParentId, parentId);
        // 查出该主键下的所有子级
        List<SysPermission> permissionList = this.list(query);
        if (permissionList != null && permissionList.size() > 0) {
            String id = ""; // id
            int num = 0; // 查出的子级数量


            // 再遍历刚才查出的集合, 根据每个对象,查找其是否仍有子级
            for (int i = 0, len = permissionList.size(); i < len; i++) {
                id = permissionList.get(i).getId().toString();
                Map map = new HashMap<>();
                map.put("perm_id", id);
                //删除角色授权表
                rolePermissionService.getBaseMapper().deleteByMap(map);
                this.baseMapper.deleteById(id);

                num = this.count(new LambdaQueryWrapper<SysPermission>().eq(SysPermission::getParentId, id));
                // 如果有, 则递归
                if (num > 0) {
                    this.removeChildrenBy(id);
                }
            }
            // 如果查出的集合不为空, 则先删除所有
            this.remove(query);
        }
    }

    @Override
    public List<SysPermission> findMenuByUserId(Integer userId) {
        //    获取用户所有菜单
        List<SysPermission> permissionByUserId = this.getBaseMapper().findMenuByUserId(userId);
        return permissionByUserId;
    }


    @Override
    public List<SysPermission> findPermissionByUserId(Integer userId) {
        //    获取用户所有按钮权限
        List<SysPermission> permissionByUserId = this.getBaseMapper().findPermissionByUserId(userId);
        return permissionByUserId;
    }

    @Override
    public List<String> getPermissionList(Integer userId) {
        List<SysPermission> permissionByUserId = this.findPermissionByUserId(userId);
        List<String> permissions = new ArrayList<>();
        permissionByUserId.forEach(permission -> {
            permissions.add("sys:" + permission.getPermTag());
        });
        return permissions;
    }
}
