package com.ruoyi.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.mybatisflex.solon.service.impl.ServiceImpl;
import com.ruoyi.common.enums.DictEnum;
import com.ruoyi.common.utils.SecurityUtil;
import com.ruoyi.common.web.domain.entity.SysRole;
import com.ruoyi.common.web.exception.ServiceException;
import com.ruoyi.system.domain.SysRoleDept;
import com.ruoyi.system.domain.SysRoleMenu;
import com.ruoyi.system.domain.SysUserRole;
import com.ruoyi.system.mapper.SysRoleDeptMapper;
import com.ruoyi.system.mapper.SysRoleMapper;
import com.ruoyi.system.mapper.SysRoleMenuMapper;
import com.ruoyi.system.mapper.SysUserRoleMapper;
import com.ruoyi.system.service.ISysRoleService;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;

import java.util.*;

/**
 * 系统角色 服务层实现
 * @author ruoyi
 */
@Component
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements ISysRoleService {

    @Inject
    SysRoleMapper sysRoleMapper;

    @Inject
    SysRoleMenuMapper sysRoleMenuMapper;

    @Inject
    SysRoleDeptMapper sysRoleDeptMapper;

    @Inject
    SysUserRoleMapper sysUserRoleMapper;

    /**
     * 查询角色列表
     * @param sysRole
     * @return
     */
    @Override
    public List<SysRole> selectRoleList(SysRole sysRole) {
        return sysRoleMapper.selectRoleList(sysRole, DictEnum.DEL_FLAG.OK.getValue());
    }

    /**
     * 根据用户ID查询角色权限
     * @param userId
     * @return
     */
    @Override
    public Set<String> getRolePermission(long userId) {
        Set<String> roles = new HashSet<>();
        // 管理员拥有所有权限
        if (SecurityUtil.isAdmin(userId)) {
            roles.add("admin");
        } else {
            List<SysRole> perms = sysRoleMapper.selectRolePermissionByUserId(userId, DictEnum.DEL_FLAG.OK.getValue());
            Set<String> permsSet = new HashSet<>();
            for (SysRole sysRole : perms) {
                if (ObjectUtil.isNotNull(sysRole)) {
                    permsSet.addAll(Arrays.asList(sysRole.getRoleKey().trim().split(",")));
                }
            }
            roles.addAll(permsSet);
        }
        return roles;
    }

    /**
     * 根据用户ID查询角色
     * @param userId 用户ID
     * @param sysRole
     * @return
     */
    @Override
    public List<SysRole> selectRolesByUserId(Long userId, SysRole sysRole) {
        List<SysRole> userRoles = sysRoleMapper.selectRolePermissionByUserId(userId, DictEnum.DEL_FLAG.OK.getValue());
        List<SysRole> roles = selectRoleList(sysRole);
        for (SysRole role : roles) {
            for (SysRole userRole : userRoles) {
                if (role.getRoleId().longValue() == userRole.getRoleId().longValue()) {
                    role.setFlag(true);
                    break;
                }
            }
        }
        return roles;
    }

    /**
     * 根据用户名查询角色
     * @param userName 用户名
     * @return
     */
    @Override
    public List<SysRole> selectRolesByUserName(String userName) {
        return sysRoleMapper.selectRolesByUserName(userName, DictEnum.DEL_FLAG.OK.getValue());
    }

    /**
     * 通过角色ID查询角色
     * @param roleId 角色ID
     * @return
     */
    @Override
    public SysRole selectRoleById(Long roleId) {
        return sysRoleMapper.selectRoleById(roleId, DictEnum.DEL_FLAG.OK.getValue());
    }

    /**
     * 查询角色详情
     * @param roleId
     * @param sysRole
     * @return
     */
    @Override
    public SysRole info(Long roleId, SysRole sysRole) {
        sysRole.setRoleId(roleId);
        checkRoleDataScope(sysRole);
        return selectRoleById(roleId);
    }

    /**
     * 新增角色
     * @param sysRole
     * @return
     */
    @Override
    public boolean add(SysRole sysRole) {
        if (!checkRoleNameUnique(sysRole)) {
            throw new ServiceException("角色名称已存在");
        } else if (!checkRoleKeyUnique(sysRole)) {
            throw new ServiceException("角色权限已存在");
        }
        int row = sysRoleMapper.insert(sysRole);
        int r = insertRoleMenu(sysRole);
        return row > 0 && r > 0;
    }

    /**
     * 修改角色
     * @param sysRole
     * @return
     */
    @Override
    public boolean edit(SysRole sysRole) {
        if (!checkRoleNameUnique(sysRole)) {
            throw new ServiceException("角色名称已存在");
        } else if (!checkRoleKeyUnique(sysRole)) {
            throw new ServiceException("角色权限已存在");
        }
        int row = sysRoleMapper.update(sysRole);
        // 删除角色与菜单关联
        sysRoleMenuMapper.deleteRoleMenuByRoleId(sysRole.getRoleId());
        int r = insertRoleMenu(sysRole);
        return row > 0 && r > 0;
    }

    /**
     * 修改保存数据权限
     * @param sysRole
     */
    @Override
    public boolean dataScope(SysRole sysRole) {
        checkRoleAllowed(sysRole);
        checkRoleDataScope(sysRole);
        int row = sysRoleMapper.update(sysRole);
        // 删除角色与部门关联
        sysRoleDeptMapper.deleteRoleDeptByRoleId(sysRole.getRoleId());
        int r = insertRoleDept(sysRole);
        return row > 0 && r > 0;
    }

    /**
     * 状态修改
     * @param sysRole
     * @return
     */
    @Override
    public int changeStatus(SysRole sysRole) {
        checkRoleAllowed(sysRole);
        checkRoleDataScope(sysRole);
        return sysRoleMapper.update(sysRole);
    }

    /**
     * 删除角色
     * @param roleIds
     * @param sysRole
     */
    @Override
    public int delete(Long[] roleIds, SysRole sysRole) {
        for (Long roleId : roleIds) {
            sysRole.setRoleId(roleId);
            checkRoleAllowed(sysRole);
            checkRoleDataScope(sysRole);
            if (sysUserRoleMapper.countUserRoleByRoleId(roleId) > 0) {
                throw new ServiceException("角色已分配，不能删除");
            }
        }
        // 删除角色与菜单关联
        sysRoleMenuMapper.deleteRoleMenu(roleIds);
        // 删除角色与部门关联
        sysRoleDeptMapper.deleteRoleDept(roleIds);
        return sysRoleMapper.deleteBatchByIds(Arrays.asList(roleIds));
    }

    /**
     * 取消授权用户
     * @param sysUserRole
     * @return
     */
    @Override
    public int cancelAuthUser(SysUserRole sysUserRole) {
        return sysUserRoleMapper.deleteUserRoleInfo(sysUserRole);
    }

    /**
     * 批量取消授权用户
     * @param roleId
     * @param userIds
     * @return
     */
    @Override
    public int cancelAuthUsers(Long roleId, Long[] userIds) {
        return sysUserRoleMapper.deleteUserRoleInfos(roleId, userIds);
    }

    /**
     * 批量选择用户授权
     * @param roleId
     * @param userIds
     * @param sysRole
     * @return
     */
    @Override
    public int insertAuthUsers(Long roleId, Long[] userIds, SysRole sysRole) {
        sysRole.setRoleId(roleId);
        checkRoleDataScope(sysRole);
        // 新增用户与角色管理
        List<SysUserRole> list = new ArrayList<>();
        for (Long userId : userIds) {
            SysUserRole ur = new SysUserRole();
            ur.setUserId(userId);
            ur.setRoleId(roleId);
            list.add(ur);
        }
        return sysUserRoleMapper.insertBatch(list);
    }

    /**
     * 校验角色是否允许操作
     * @param sysRole 角色信息
     */
    private void checkRoleAllowed(SysRole sysRole) {
        if (sysRole.getRoleId() != null && sysRole.isAdmin()) {
            throw new ServiceException("不允许操作超级管理员角色");
        }
    }

    /**
     * 校验角色是否有数据权限
     * @param sysRole
     */
    private void checkRoleDataScope(SysRole sysRole) {
        if (!SecurityUtil.isAdmin(SecurityUtil.getUserId())) {
            List<SysRole> roles = selectRoleList(sysRole);
            if (CollectionUtil.isEmpty(roles)) {
                throw new ServiceException("没有权限访问角色数据！");
            }
        }
    }

    /**
     * 校验角色名称是否唯一
     * @param sysRole 角色信息
     * @return
     */
    private boolean checkRoleNameUnique(SysRole sysRole) {
        long roleId = sysRole.getRoleId() == null ? -1L : sysRole.getRoleId();
        SysRole info = sysRoleMapper.checkRoleNameUnique(sysRole.getRoleName(), DictEnum.DEL_FLAG.OK.getValue());
        return ObjectUtil.isNull(info) || info.getRoleId() == roleId;
    }

    /**
     * 校验角色权限是否唯一
     * @param sysRole 角色信息
     * @return
     */
    private boolean checkRoleKeyUnique(SysRole sysRole) {
        long roleId = sysRole.getRoleId() == null ? -1L : sysRole.getRoleId();
        SysRole info = sysRoleMapper.checkRoleKeyUnique(sysRole.getRoleKey(), DictEnum.DEL_FLAG.OK.getValue());
        return ObjectUtil.isNull(info) || info.getRoleId() == roleId;
    }

    /**
     * 新增角色菜单信息
     * @param sysRole 角色对象
     */
    public int insertRoleMenu(SysRole sysRole) {
        int rows = 1;
        // 新增用户与角色管理
        List<SysRoleMenu> list = new ArrayList<>();
        for (Long menuId : sysRole.getMenuIds()) {
            SysRoleMenu rm = new SysRoleMenu();
            rm.setRoleId(sysRole.getRoleId());
            rm.setMenuId(menuId);
            list.add(rm);
        }
        if (list.size() > 0) {
            rows = sysRoleMenuMapper.insertBatch(list);
        }
        return rows;
    }

    /**
     * 新增角色部门信息(数据权限)
     * @param role 角色对象
     */
    public int insertRoleDept(SysRole role) {
        int rows = 1;
        // 新增角色与部门（数据权限）管理
        List<SysRoleDept> list = new ArrayList<>();
        for (Long deptId : role.getDeptIds()) {
            SysRoleDept rd = new SysRoleDept();
            rd.setRoleId(role.getRoleId());
            rd.setDeptId(deptId);
            list.add(rd);
        }
        if (list.size() > 0) {
            rows = sysRoleDeptMapper.insertBatch(list);
        }
        return rows;
    }

}
