package com.qmth.teachcloud.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.teachcloud.common.base.BaseEntity;
import com.qmth.teachcloud.common.contant.SystemConstant;
import com.qmth.teachcloud.common.entity.*;
import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
import com.qmth.teachcloud.common.enums.FieldUniqueEnum;
import com.qmth.teachcloud.common.enums.userPush.SpecialPrivilegeEnum;
import com.qmth.teachcloud.common.enums.userPush.SyncStatusEnum;
import com.qmth.teachcloud.common.enums.userPush.UserPushTrackEnum;
import com.qmth.teachcloud.common.mapper.SysRoleMapper;
import com.qmth.teachcloud.common.service.*;
import com.qmth.teachcloud.common.util.ResultUtil;
import com.qmth.teachcloud.common.util.ServletUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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);

    @Autowired
    private SysUserRoleService sysUserRoleService;

    @Autowired
    private SysRolePrivilegeService sysRolePrivilegeService;

    @Autowired
    private CommonCacheService commonCacheService;

    @Resource
    SysRoleService sysRoleService;

    @Resource
    TeachcloudCommonService commonService;

    @Resource
    SysPrivilegeService sysPrivilegeService;

    @Resource
    SysUserService sysUserService;

    @Resource
    PushUserTrackService pushUserTrackService;

    @Resource
    SysRoleGroupMemberService sysRoleGroupMemberService;

    @Override
    public IPage<SysRole> list(String name, Boolean enable, Integer pageNumber, Integer pageSize) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        return this.baseMapper.listPage(new Page<>(pageNumber, pageSize), schoolId, SystemConstant.translateSpecificSign(name), enable);
    }

    @Transactional
    @Override
    @Deprecated
    public boolean saveRole(SysRole role) {
        Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
        role.setSchoolId(schoolId);
        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();

        QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SysRole::getSchoolId, role.getSchoolId()).eq(SysRole::getName, role.getName());
        SysRole sysRole = this.getOne(queryWrapper);
        boolean isSuccess;
        // 新增
        if (Objects.isNull(role.getId())) {
            if (sysRole != null) {
                throw ExceptionResultEnum.ERROR.exception("角色已存在");
            }
            role.setId(SystemConstant.getDbUuid());
            role.setCreateId(sysUser.getId());
            role.setCreateTime(System.currentTimeMillis());
            isSuccess = this.save(role);
        }
        // 修改
        else {
            if (sysRole != null && sysRole.getId().longValue() != role.getId().longValue()) {
                throw ExceptionResultEnum.ERROR.exception("角色已存在");
            }

            role.setUpdateId(sysUser.getId());
            role.setUpdateTime(System.currentTimeMillis());

//            if (RoleTypeEnum.CUSTOM.equals(role.getType())) {
            //删除权限
            sysRolePrivilegeService.removeByRoleId(role.getId());
//            }
            isSuccess = this.updateById(role);

        }

//        if (RoleTypeEnum.CUSTOM.equals(role.getType())) {
        // 新增权限
        sysRolePrivilegeService.saveBatch(role);
//        }

        // 更新sys_user_role
        sysUserRoleService.rebindPrivileges(role.getId());

        // 清除缓存
        commonCacheService.removeUserAuthCache(sysUser.getId());
        commonCacheService.removeRolePrivilegeCache(role.getId());

        return isSuccess;
    }

    /**
     * 新增角色
     *
     * @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);
            }
            if (Objects.nonNull(role.getId())) {//编辑
                List<SysRolePrivilege> sysRolePrivilegeList = commonCacheService.rolePrivilegeCache(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()) {
                    // 删除权限前先更新涉及特殊权限用户 -> 需要重新同步
                    List<SysRolePrivilege> dbRolePriList = commonCacheService.rolePrivilegeCache(role.getId());
                    this.updateUserPushStats(dbRolePriList.stream().map(SysRolePrivilege::getPrivilegeId).distinct().collect(Collectors.toList()),
                            Arrays.asList(role.getPrivilegeIds()),
                            role.getId(),
                            schoolId);
                    sysRolePrivilegeService.removeByRoleId(role.getId());
                    sysRolePrivilegeService.saveBatch(role);//角色权限
                    commonCacheService.updateRolePrivilegeCache(role.getId());
                    //绑定该角色的用户都需要清除鉴权缓存
                    List<SysUserRole> sysUserRoleList = sysUserRoleService.listByRoleId(role.getId());
                    commonService.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;
    }

    @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);
            }
            if (Objects.nonNull(role.getId())) {//编辑
                List<SysRolePrivilege> sysRolePrivilegeList = commonCacheService.rolePrivilegeCache(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());
                    commonService.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);

        commonCacheService.updateRoleCache(role.getId());
        //如果状态为禁用，需要踢下线重新登录
        if (!role.getEnable()) {
            List<SysUserRole> sysUserRoleList = sysUserRoleService.listByRoleId(role.getId());
            for (SysUserRole s : sysUserRoleList) {
                commonService.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);

        commonCacheService.updateRoleCache(role.getId());
        //如果状态为禁用，需要踢下线重新登录
        if (!role.getEnable()) {
            List<SysUserRole> sysUserRoleList = sysUserRoleService.listByRoleId(role.getId());
            for (SysUserRole s : sysUserRoleList) {
                commonService.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);

        commonCacheService.removeRoleCache(id);
        commonCacheService.removeRolePrivilegeCache(id);
        return true;
    }

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

        commonCacheService.removeRoleCache(id);
        commonCacheService.removeRolePrivilegeCache(id);
        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();
//        QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();
//        queryWrapper.lambda().eq(SysRole::getEnable, true);
//        if (Objects.isNull(object)) {
//            queryWrapper.lambda().isNull(SysRole::getSchoolId);
//        } else {
//            Long schoolId = Long.valueOf(object.toString());
//            queryWrapper.lambda().eq(SysRole::getSchoolId, schoolId);
//        }
        return this.baseMapper.listRolesBySchoolId(Objects.nonNull(schoolId) ? Long.valueOf(schoolId) : null);
    }

    /**
     * 更新用户状态为重新推送
     *
     * @param dbPrivilege 角色旧权限
     * @param upPrivilege 角色新权限
     * @param roleId      角色id
     * @param schoolId    学校id
     */
    @Transactional
    public void updateUserPushStats(List<Long> dbPrivilege, List<Long> upPrivilege, Long roleId, Long schoolId) {
        SysUser requestUser = (SysUser) ServletUtil.getRequestUser();
        // 评卷员权限
        SysPrivilege marker = sysPrivilegeService.list(new QueryWrapper<SysPrivilege>().lambda()
                .eq(SysPrivilege::getUrl, SpecialPrivilegeEnum.MARKER.getId())).get(0);
        Long markerId = marker.getId();

        // 科组长权限
        SysPrivilege subjectHeader = sysPrivilegeService.list(new QueryWrapper<SysPrivilege>().lambda()
                .eq(SysPrivilege::getUrl, SpecialPrivilegeEnum.SUBJECT_HEADER.getId())).get(0);
        Long subjectHeaderId = subjectHeader.getId();
        if ((dbPrivilege.contains(markerId) || upPrivilege.contains(markerId)) || (dbPrivilege.contains(subjectHeaderId) || upPrivilege.contains(subjectHeaderId))) {
            List<SysUserRole> sysUserRoleList = sysUserRoleService.list(new QueryWrapper<SysUserRole>().lambda().eq(SysUserRole::getRoleId, roleId));
            Set<Long> userIdSet = sysUserRoleList.stream().map(SysUserRole::getUserId).collect(Collectors.toSet());
            if (userIdSet.size() > 0) {
                List<SysUser> sysUserList = sysUserService.listByIds(userIdSet);
                for (SysUser sysUser : sysUserList) {
                    boolean enable = sysUser.getEnable();
                    sysUser.setSyncStatus(SyncStatusEnum.NEED_PUSH_AGAIN);
                    sysUserService.updateById(sysUser);
                    Set<Long> roleIdSet = sysUserRoleService.listRoleByUserId(sysUser.getId()).stream().map(BaseEntity::getId).collect(Collectors.toSet());
                    roleIdSet.remove(roleId);

                    // 该用户除掉正要更改的角色所属的权限外其他角色所属权限的特殊权限枚举
                    SpecialPrivilegeEnum otherRoleSpecialPrivilegeEnum = sysUserService.findUserSpecialPrivilegeByRoleIdSet(roleIdSet);

                    PushUserTrack markerTrack = new PushUserTrack();
                    PushUserTrack headerTrack = new PushUserTrack();
                    List<PushUserTrack> specialUserTrack = pushUserTrackService.list(new QueryWrapper<PushUserTrack>().lambda().eq(PushUserTrack::getUserId, sysUser.getId()));
                    if (specialUserTrack.size() > 0) {
                        List<PushUserTrack> markerTrackList = specialUserTrack.stream().filter(e -> SpecialPrivilegeEnum.MARKER.equals(e.getIdentify())).sorted(Comparator.comparing(PushUserTrack::getCreateTime).reversed()).limit(1).collect(Collectors.toList());
                        List<PushUserTrack> headerTrackList = specialUserTrack.stream().filter(e -> SpecialPrivilegeEnum.SUBJECT_HEADER.equals(e.getIdentify())).sorted(Comparator.comparing(PushUserTrack::getCreateTime).reversed()).limit(1).collect(Collectors.toList());
                        if (markerTrackList.size() == 1) {
                            markerTrack = markerTrackList.get(0);
                        }
                        if (headerTrackList.size() == 1) {
                            headerTrack = headerTrackList.get(0);
                        }
                    }

                    // 更新轨迹数据
                    // 评卷员身份轨迹记录
                    if (SystemConstant.longNotNull(markerTrack.getId())) {
                        // 更新
                        markerTrack.updateInfo(requestUser.getId());
                    } else {
                        // 新增
                        markerTrack.insertInfo(requestUser.getId());
                    }
                    markerTrack.setUserId(sysUser.getId());
                    markerTrack.setSchoolId(sysUser.getSchoolId());
                    markerTrack.setIdentify(SpecialPrivilegeEnum.MARKER);

                    // 科组长身份轨迹记录
                    if (SystemConstant.longNotNull(markerTrack.getId())) {
                        // 更新
                        headerTrack.updateInfo(requestUser.getId());
                    } else {
                        // 新增
                        headerTrack.insertInfo(requestUser.getId());
                    }
                    headerTrack.setUserId(sysUser.getId());
                    headerTrack.setSchoolId(sysUser.getSchoolId());
                    headerTrack.setIdentify(SpecialPrivilegeEnum.SUBJECT_HEADER);

                    // 评卷员判断
                    if (dbPrivilege.contains(markerId) && !upPrivilege.contains(markerId)) {
                        // 该角色更新没收了评卷员权限
                        if (!SpecialPrivilegeEnum.MARKER.equals(otherRoleSpecialPrivilegeEnum) && !SpecialPrivilegeEnum.COMPOSITE.equals(otherRoleSpecialPrivilegeEnum)) {
                            // 该用户其他的角色也不包含评卷员权限 -> 评卷员角色解绑
                            markerTrack.setOperate(UserPushTrackEnum.UNBIND);
                            pushUserTrackService.saveOrUpdate(markerTrack);
                        }
                    } else if (!dbPrivilege.contains(markerId) && upPrivilege.contains(markerId)) {
                        // 更新新增了评卷员权限
                        if (enable) {
                            markerTrack.setOperate(UserPushTrackEnum.BIND);
                            pushUserTrackService.saveOrUpdate(markerTrack);
                        }
                    }
                    // 科组长判断
                    if (dbPrivilege.contains(subjectHeaderId) && !upPrivilege.contains(subjectHeaderId)) {
                        // 该角色更新没收了科组长权限
                        if (!SpecialPrivilegeEnum.SUBJECT_HEADER.equals(otherRoleSpecialPrivilegeEnum) && !SpecialPrivilegeEnum.COMPOSITE.equals(otherRoleSpecialPrivilegeEnum)) {
                            // 该用户其他的角色也不包含科组长权限 -> 科组长角色解绑
                            headerTrack.setOperate(UserPushTrackEnum.UNBIND);
                            pushUserTrackService.saveOrUpdate(headerTrack);
                        }
                    } else if (!dbPrivilege.contains(subjectHeaderId) && upPrivilege.contains(subjectHeaderId)) {
                        // 更新新增了科组长权限
                        if (enable) {
                            headerTrack.setOperate(UserPushTrackEnum.BIND);
                            pushUserTrackService.saveOrUpdate(headerTrack);
                        }
                    }
                }
            }
        }
    }
}
