package com.qmth.paper.library.common.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.boot.api.exception.ApiException;
import com.qmth.paper.library.common.contant.SystemConstant;
import com.qmth.paper.library.common.entity.*;
import com.qmth.paper.library.common.enums.ExceptionResultEnum;
import com.qmth.paper.library.common.enums.FieldUniqueEnum;
import com.qmth.paper.library.common.enums.RoleSourceEnum;
import com.qmth.paper.library.common.mapper.SysRoleMapper;
import com.qmth.paper.library.common.service.*;
import com.qmth.paper.library.common.util.ResultUtil;
import com.qmth.paper.library.common.util.ServletUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色表 服务实现类
 * </p>
 *
 * @author xf
 * @since 2021-03-23
 */
@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {
    private final static Logger log = LoggerFactory.getLogger(SysRoleServiceImpl.class);

    @Resource
    private SysUserRoleService sysUserRoleService;

    @Resource
    private SysRolePrivilegeService sysRolePrivilegeService;

    @Resource
    LibraryCommonService libraryCommonService;

    @Resource
    SysRoleService sysRoleService;

    @Resource
    CommonCacheService commonCacheService;

    @Resource
    SysPrivilegeService sysPrivilegeService;

    @Resource
    SysRoleGroupMemberService sysRoleGroupMemberService;

    @Override
    public IPage<SysRole> list(String name, Boolean enable, Integer pageNumber, Integer pageSize) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        IPage<SysRole> sysRoleIPage = this.baseMapper.listPage(new Page<>(pageNumber, pageSize), schoolId, SystemConstant.translateSpecificSign(name), enable);
        for (SysRole record : sysRoleIPage.getRecords()) {
            int count = baseMapper.countUserByRole(schoolId, record.getId());
            record.setUserCount(count);
        }
        return sysRoleIPage;
    }

    /**
     * 新增角色
     *
     * @param role
     * @return
     */
    @Transactional
    @Override
    public boolean saveRoleNew(SysRole role) {
        try {
            SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
            Long schoolId = Objects.nonNull(ServletUtil.getRequestHeaderSchoolIdByNotVaild()) ? Long.valueOf(ServletUtil.getRequestHeaderSchoolIdByNotVaild().toString()) : null;
            if (Objects.isNull(schoolId) && Objects.isNull(role.getSchoolId())) {
                role.setSchoolId(sysUser.getSchoolId());
            } else if (Objects.nonNull(schoolId)) {
                role.setSchoolId(schoolId);
            }
            // 系统默认内置角色（不允许和系统默认角色重名）
            List<String> defaultRoleNames = this.list(new QueryWrapper<SysRole>().lambda()
                            .eq(SysRole::getDefaultRole, true)
                            .eq(SysRole::getEnable, true))
                    .stream()
                    .map(SysRole::getName)
                    .distinct()
                    .collect(Collectors.toList());
            String roleName = role.getName();
            if (defaultRoleNames.contains(roleName)) {
                throw ExceptionResultEnum.ERROR.exception("自定义角色名称不能和系统默认角色【" + roleName + "】同名");
            }
            if (Objects.nonNull(role.getId())) {//编辑
                List<SysRolePrivilege> sysRolePrivilegeList = libraryCommonService.getRolePrivilege(role.getId());
                QueryWrapper<SysPrivilege> sysPrivilegeQueryWrapper = new QueryWrapper<>();
                sysPrivilegeQueryWrapper.lambda().in(SysPrivilege::getId, role.getPrivilegeIds());
                List<SysPrivilege> sysPrivilegeList = sysPrivilegeService.list(sysPrivilegeQueryWrapper);
                Set<String> relatedSet = sysPrivilegeList.stream().filter(s -> Objects.nonNull(s.getRelated())).map(s -> s.getRelated()).collect(Collectors.toSet());
                Set<Long> finalRelatedSet = new HashSet<>(Arrays.asList(role.getPrivilegeIds()));
                for (String s : relatedSet) {
                    if (s.contains(",")) {
                        String[] arrays = s.split(",");
                        for (int i = 0; i < arrays.length; i++) {
                            finalRelatedSet.add(Long.parseLong(arrays[i].trim()));
                        }
                    } else {
                        finalRelatedSet.add(Long.parseLong(s));
                    }
                }
                List<Long> relatedList = new ArrayList<>(finalRelatedSet);
                int count = (int) sysRolePrivilegeList.stream().filter(s -> relatedList.contains(s.getPrivilegeId())).count();
                role.updateInfo(sysUser.getId());
                sysRoleService.updateById(role);
                commonCacheService.updateRoleCache(role.getId());

                if (count != sysRolePrivilegeList.size() || count != finalRelatedSet.size()) {
                    sysRolePrivilegeService.removeByRoleId(role.getId());
                    sysRolePrivilegeService.saveBatch(role);//角色权限

                    commonCacheService.updateRolePrivilegeCache(role.getId());
                    //绑定该角色的用户都需要清除鉴权缓存
                    List<SysUserRole> sysUserRoleList = sysUserRoleService.listByRoleId(role.getId());
                    libraryCommonService.removeUserInfoBatch(sysUserRoleList.stream().map(SysUserRole::getUserId).collect(Collectors.toList()), true);
                }
            } else {
                role.insertInfo(sysUser.getId());
                sysRoleService.save(role);
                sysRolePrivilegeService.saveBatch(role);//角色权限
            }
        } catch (Exception e) {
            if (e instanceof DuplicateKeyException) {
                String errorColumn = e.getCause().toString();
                String columnStr = errorColumn.substring(errorColumn.lastIndexOf("key") + 3, errorColumn.length()).replaceAll("'", "");
                throw ExceptionResultEnum.SQL_ERROR.exception("[" + FieldUniqueEnum.convertToTitle(columnStr) + "]数据不允许重复插入");
            } else if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return true;
    }

    @Transactional
    @Override
    public boolean saveRoleReportNew(SysRole role) {
        try {
            SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
            Long schoolId = Objects.nonNull(ServletUtil.getRequestHeaderSchoolIdByNotVaild()) ? Long.valueOf(ServletUtil.getRequestHeaderSchoolIdByNotVaild().toString()) : null;
            if (Objects.isNull(schoolId) && Objects.isNull(role.getSchoolId())) {
                role.setSchoolId(sysUser.getSchoolId());
            } else if (Objects.nonNull(schoolId)) {
                role.setSchoolId(schoolId);
            }
            // 系统默认内置角色（不允许和系统默认角色重名）
            List<String> defaultRoleNames = this.list(new QueryWrapper<SysRole>().lambda()
                            .eq(SysRole::getDefaultRole, true)
                            .eq(SysRole::getEnable, true))
                    .stream()
                    .map(SysRole::getName)
                    .distinct()
                    .collect(Collectors.toList());
            String roleName = role.getName();
            if (defaultRoleNames.contains(roleName)) {
                throw ExceptionResultEnum.ERROR.exception("自定义角色名称不能和系统默认角色【" + roleName + "】同名");
            }
            if (Objects.nonNull(role.getId())) {//编辑
                List<SysRolePrivilege> sysRolePrivilegeList = libraryCommonService.getRolePrivilege(role.getId());
                QueryWrapper<SysPrivilege> sysPrivilegeQueryWrapper = new QueryWrapper<>();
                sysPrivilegeQueryWrapper.lambda().in(SysPrivilege::getId, role.getPrivilegeIds());
                List<SysPrivilege> sysPrivilegeList = sysPrivilegeService.list(sysPrivilegeQueryWrapper);
                Set<String> relatedSet = sysPrivilegeList.stream().filter(s -> Objects.nonNull(s.getRelated())).map(s -> s.getRelated()).collect(Collectors.toSet());
                Set<Long> finalRelatedSet = new HashSet<>(Arrays.asList(role.getPrivilegeIds()));
                for (String s : relatedSet) {
                    if (s.contains(",")) {
                        String[] arrays = s.split(",");
                        for (int i = 0; i < arrays.length; i++) {
                            finalRelatedSet.add(Long.parseLong(arrays[i].trim()));
                        }
                    } else {
                        finalRelatedSet.add(Long.parseLong(s));
                    }
                }
                List<Long> relatedList = new ArrayList<>(finalRelatedSet);
                int count = (int) sysRolePrivilegeList.stream().filter(s -> relatedList.contains(s.getPrivilegeId())).count();
                role.updateInfo(sysUser.getId());
                sysRoleService.updateById(role);
                if (count != sysRolePrivilegeList.size() || count != finalRelatedSet.size()) {
                    // 删除权限前先更新涉及特殊权限用户 -> 需要重新同步
                    sysRolePrivilegeService.removeByRoleId(role.getId());
                    sysRolePrivilegeService.saveBatch(role);//角色权限
                    //绑定该角色的用户都需要清除鉴权缓存
                    List<SysUserRole> sysUserRoleList = sysUserRoleService.listByRoleId(role.getId());
                    libraryCommonService.removeUserInfoBatch(sysUserRoleList.stream().map(s -> s.getUserId()).collect(Collectors.toList()), true);
                }
            } else {
                role.insertInfo(sysUser.getId());
                sysRoleService.save(role);
                sysRolePrivilegeService.saveBatch(role);//角色权限
            }
        } catch (Exception e) {
            if (e instanceof DuplicateKeyException) {
                String errorColumn = e.getCause().toString();
                String columnStr = errorColumn.substring(errorColumn.lastIndexOf("key") + 3, errorColumn.length()).replaceAll("'", "");
                throw ExceptionResultEnum.SQL_ERROR.exception("[" + FieldUniqueEnum.convertToTitle(columnStr) + "]数据不允许重复插入");
            } else if (e instanceof ApiException) {
                ResultUtil.error((ApiException) e, e.getMessage());
            } else {
                ResultUtil.error(e.getMessage());
            }
        }
        return true;
    }

    @Override
    public boolean enable(SysRole role) throws NoSuchAlgorithmException {
        UpdateWrapper<SysRole> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().set(SysRole::getEnable, role.getEnable()).eq(SysRole::getId, role.getId());
        this.update(updateWrapper);

        UpdateWrapper<SysRoleGroupMember> sysRoleGroupMemberUpdateWrapper = new UpdateWrapper<>();
        sysRoleGroupMemberUpdateWrapper.lambda().eq(SysRoleGroupMember::getRoleId, role.getId())
                .set(SysRoleGroupMember::getEnable, role.getEnable());
        sysRoleGroupMemberService.update(sysRoleGroupMemberUpdateWrapper);

        //如果状态为禁用，需要踢下线重新登录
        if (!role.getEnable()) {
            List<SysUserRole> sysUserRoleList = sysUserRoleService.listByRoleId(role.getId());
            for (SysUserRole s : sysUserRoleList) {
                libraryCommonService.removeUserInfo(s.getUserId(), true);
            }
        }
        return true;
    }

    @Override
    public boolean enableReport(SysRole role) throws NoSuchAlgorithmException {
        UpdateWrapper<SysRole> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().set(SysRole::getEnable, role.getEnable()).eq(SysRole::getId, role.getId());
        this.update(updateWrapper);

        //如果状态为禁用，需要踢下线重新登录
        if (!role.getEnable()) {
            List<SysUserRole> sysUserRoleList = sysUserRoleService.listByRoleId(role.getId());
            for (SysUserRole s : sysUserRoleList) {
                libraryCommonService.removeUserInfo(s.getUserId(), true);
            }
        }
        return true;
    }

    @Transactional
    @Override
    public boolean remove(Long id) {
        // 判断绑定用户
        List<SysUserRole> userRoleList = sysUserRoleService.listByRoleId(id);
        if (userRoleList != null && userRoleList.size() > 0) {
            throw ExceptionResultEnum.ERROR.exception("用户绑定，不能删除");
        }
        //删除权限
        sysRolePrivilegeService.removeByRoleId(id);
        this.removeById(id);

        QueryWrapper<SysRoleGroupMember> sysRoleGroupMemberQueryWrapper = new QueryWrapper<>();
        sysRoleGroupMemberQueryWrapper.lambda().eq(SysRoleGroupMember::getRoleId, id);
        sysRoleGroupMemberService.remove(sysRoleGroupMemberQueryWrapper);
        return true;
    }

    @Transactional
    @Override
    public boolean removeReport(String ids) {
        String[] idsArray = ids.split(",");
        for (String id : idsArray) {
            Long idLong = Long.valueOf(id);
            //删除权限
            sysRolePrivilegeService.removeByRoleId(idLong);
            this.removeById(idLong);

            // 删除用户角色
            sysUserRoleService.removeByRoleId(idLong);
        }
        return true;
    }

    @Override
    public List<Long> getUserRoles(Long userId) {
        QueryWrapper<SysUserRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SysUserRole::getUserId, userId);
        List<SysUserRole> sysUserRoles = sysUserRoleService.list(queryWrapper);
        List<Long> list = new ArrayList<>();
        if (sysUserRoles != null && sysUserRoles.size() > 0) {
            list = sysUserRoles.stream().map(m -> m.getRoleId()).collect(Collectors.toList());
        }
        return list;
    }

    @Override
    public List<SysRole> listRolesByUserId(Long id) {
        return this.baseMapper.listRolesByUserId(id);
    }

    @Override
    public List<SysRole> list(Long[] roleIds, String name) {
        QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SysRole::getType, name).in(SysRole::getId, roleIds);
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    public List<SysRole> listToUser() {
        String schoolId = (String) ServletUtil.getRequestHeaderSchoolIdByNotVaild();
        return this.baseMapper.listRolesBySchoolId(Objects.nonNull(schoolId) ? Long.valueOf(schoolId) : null);
    }

    @Override
    public boolean builtin(Long id, boolean defaultRole) {
        SysRole sysRole = this.getById(id);
        if (defaultRole) {
            sysRole.setSource(RoleSourceEnum.SYS);
            sysRole.setInterpret(RoleSourceEnum.SYS.getDesc());
        } else {
            sysRole.setSource(null);
            sysRole.setInterpret(null);
        }
        sysRole.setDefaultRole(defaultRole);
        return this.updateById(sysRole);
    }
}
