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.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.mapper.SysRoleMapper;
import com.qmth.teachcloud.common.service.*;
import com.qmth.teachcloud.common.util.ResultUtil;
import com.qmth.teachcloud.common.util.ServletUtil;
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 {

    @Autowired
    private SysUserRoleService sysUserRoleService;

    @Autowired
    private SysRolePrivilegeService sysRolePrivilegeService;

    @Autowired
    private CommonCacheService commonCacheService;

    @Resource
    SysRoleService sysRoleService;

    @Resource
    TeachcloudCommonService commonService;

    @Resource
    SysPrivilegeService sysPrivilegeService;

    @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()) {
                    sysRolePrivilegeService.removeByRoleId(role.getId());
                    sysRolePrivilegeService.saveBatch(role);//角色权限
                    commonCacheService.updateRolePrivilegeCache(role.getId());
                    //绑定该角色的用户都需要清除鉴权缓存
                    List<SysUserRole> sysUserRoleList = sysUserRoleService.listByRoleId(role.getId());
                    for (SysUserRole s : sysUserRoleList) {
                        commonService.removeUserInfo(s.getUserId(), 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);
        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);
        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 = null;
        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() {
        Object object = 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.list(queryWrapper);
    }
}
