package com.ho.user.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ho.business.entity.Station;
import com.ho.common.tools.constant.CommonConstant;
import com.ho.common.tools.constant.EnvConstant;
import com.ho.common.tools.constant.RedisKeyConstant;
import com.ho.common.tools.constant.SymbolConstant;
import com.ho.common.tools.entity.*;
import com.ho.common.tools.exception.BaseResponseCode;
import com.ho.common.tools.exception.BusinessException;
import com.ho.common.tools.exception.DataResult;
import com.ho.common.tools.service.RedisService;
import com.ho.common.tools.util.PageResult;
import com.ho.common.tools.util.PageUtils;
import com.ho.common.tools.util.PageUtilsOld;
import com.ho.common.tools.vo.req.PositionVo;
import com.ho.flow.entity.SendSmsConfig;
import com.ho.user.api.entity.SysDept;
import com.ho.user.api.entity.SysSubDict;
import com.ho.user.api.entity.SysUser;
import com.ho.user.api.vo.req.OrderUserSelectReqVo;
import com.ho.user.api.vo.req.QueryDeptReqVO;
import com.ho.user.api.vo.req.SysSubDictVO;
import com.ho.user.entity.SysPosition;
import com.ho.user.entity.SysTheme;
import com.ho.user.feignclient.BusinessFeignClient;
import com.ho.user.feignclient.FlowFeignClient;
import com.ho.user.mapper.SysDeptMapper;
import com.ho.user.mapper.SysPermissionMapper;
import com.ho.user.mapper.SysUserMapper;
import com.ho.user.service.*;
import com.ho.user.vo.req.*;
import com.ho.user.vo.resp.SysUserThemeRespVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author fancl
 * @desc: 用户实现类
 * @date 2022/8/10
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    @Lazy
    DeptService deptService;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private RedisUpdateService redisUpdateService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private PermissionService permissionService;

    @Autowired
    private UserRoleService userRoleService;

    @Autowired
    private SysDeptMapper sysDeptMapper;

    @Autowired
    private UserPostService userPostService;

    @Autowired
    BusinessFeignClient businessFeignClient;

    @Autowired
    RolePermissionService rolePermissionService;

    @Autowired
    SysPermissionMapper sysPermissionMapper;

    @Autowired
    FlowFeignClient flowFeignClient;

    @Autowired
    Snowflake snowflake;

    @Autowired
    DictService dictService;

    @Value("${default.pwd}")
    private String defaultPwd;

    @Value("${spring.profiles.active}")
    private String env;

    @Override
    public UserDetailRespVO yourSelfInfo(UserDetailRespVO user, boolean platSuper,String lang) {
        if (user.getRoleIds() == null) {
            //该用户无有效角色
            throw new BusinessException(BaseResponseCode.USER_DOES_NOT_VALID_ROLE);
        }
        //根据RoleIds在sys_role_permission关联表中拿到 permission_id,在根据permission_id拿到菜单
        List<SysPermission> result = permissionService.getPermissionByRoleIds(user.getRoleIds(),lang);
        //将其组成树结构返回
        //全量的菜单集合
        List<SysPermission> permissions = new ArrayList<>();
        List<SysPermission> menuListTree = new ArrayList<>();
        //超管,只查询 系统管理下 的菜单
        if (platSuper) {
            SysPermission sysManageMenu = permissionService.findSysManageMenu();
            if (sysManageMenu != null) {
                List<SysPermission> menuList = new ArrayList<>();
                menuList.add(sysManageMenu);
                List<Integer> queryIds = new ArrayList<>();
                queryIds.add(sysManageMenu.getId());
                permissions = permissionService.getSysMangeMenus(menuList, queryIds);

                //排序
                List<SysPermission> permissionsCollect = permissions.stream().sorted(Comparator.comparing(SysPermission::getOrderNum)).collect(Collectors.toList());

                menuListTree = getMenuListTree(platSuper, permissionsCollect, user.getLoginChannel());
            }
        }
        //非超管,查询角色该有的
        else {
            //若是组态，直接过滤组态菜单
            if(CommonConstant.MenuShowType.CONFIG.equals(user.getConfigType())){
                result = result.stream().filter(s -> CommonConstant.ONE.equals(s.getIsConfig())).collect(Collectors.toList());
            }else{
                //否则将组态菜单过滤掉
                result = result.stream().filter(s -> !CommonConstant.ONE.equals(s.getIsConfig())).collect(Collectors.toList());
            }
            menuListTree = getMenuListTree(platSuper, result, user.getLoginChannel());
        }

        //组成返回对象
        user.setMenuList(menuListTree);
        return user;
    }

    @Override
    public UserDetailRespVO login(LoginReqVO loginReqVO, SysUser sysUser) {
        //查用户是否存在
        if (sysUser == null) {
            //手机号登陆的
            if (RedisKeyConstant.User.LOGIN_TYPE_PHONE.equals(loginReqVO.getLoginType())) {
                sysUser = sysUserMapper.getUserInfoByPhone(loginReqVO.getUsername());
            }
            //账号登陆的
            else if (RedisKeyConstant.User.LOGIN_TYPE_ACCOUNT.equals(loginReqVO.getLoginType())) {
                sysUser = sysUserMapper.getUserInfoByName(loginReqVO.getUsername());
            }
            if (sysUser == null) {
                throw new BusinessException(BaseResponseCode.NOT_ACCOUNT);
            }
            if (sysUser.getStatus().equals(2)) {
                throw new BusinessException(BaseResponseCode.USER_LOCK);
            }
            //数据库中存的Bcrypt加密后的, 所以使用BCrypt来根据明文经过算法与库中密文对比
            if (!BCrypt.checkpw(loginReqVO.getPassword(), sysUser.getPassword())) {
                throw new BusinessException(BaseResponseCode.PASSWORD_ERROR);
            }
        }
        //获取用户信息
        UserDetailRespVO userDetail = getUserDetail(sysUser.getId(), loginReqVO.getType());
        //赋值 登陆渠道 登陆方式
        userDetail.setLoginChannel(loginReqVO.getType());
        userDetail.setLoginType(loginReqVO.getLoginType());
        String token = IdUtil.simpleUUID();
        userDetail.setAccessToken(token);
        userDetail.setConfigType(loginReqVO.getConfigType());
        log.info("user:{} ,token:{}", sysUser.getUsername(), token);
        //生成SimpleUser对象
        SimpleUser simpleUser = generateSimpleUser(sysUser, userDetail.getDeptId(), token, loginReqVO);

        log.info("simpleUser:" + simpleUser);
        //设置缓存键值对
        redisService.set(RedisKeyConstant.User.TOKEN + token, userDetail, 2, TimeUnit.HOURS);
        redisService.set(RedisKeyConstant.User.USER_NAME + loginReqVO.getType() + ":" + sysUser.getUsername(), simpleUser, 2, TimeUnit.HOURS);
        return userDetail;
    }


    @Override
    public SimpleUser generateSimpleUser(SysUser sysUser, Integer deptId, String token, LoginReqVO loginReqVO) {
        SimpleUser simpleUser = new SimpleUser();
        List<Integer> depts = new ArrayList<>();
        //电站列表
        List<Integer> stationIds = new ArrayList<>();
        //根据部门id查询到relation_code
        //非超管再查部门
        if (!CommonConstant.TOP_PARENT_ID.equals(sysUser.getGroupId())) {
            SysDept sysDept = deptService.selectByPrimaryKey(deptId);
            //再根据relation_code获取到dept的集合
            List<SysDept> sysDepts = new ArrayList<>();
            sysDepts.add(sysDept);
            List<SysDept> deptList = deptService.getSubsidiaryDepts(sysDepts, CommonConstant.DEPT_KEY);
            depts = deptList.stream().map(s -> {
                return s.getId();
            }).collect(Collectors.toList());
            //查多个电站
            QueryDeptReqVO queryDeptReqVO = new QueryDeptReqVO();
            queryDeptReqVO.setDeptIds(depts);
            if (!depts.isEmpty()) {
                try {
                    DataResult<List<Station>> listDataResult = null;
                    //OPEN环境只找自己的电站
                    log.info("当前环境：{}",env);
//                    if (EnvConstant.DEV.equals(env) || EnvConstant.OPEN.equals(env)) {
                        //DEV和OPEN环境只找用户所属机构下站点
                        listDataResult = businessFeignClient.selectByDeptIds(queryDeptReqVO);
//
//                    } else {
//                        //通合环境查全部电站
//                        listDataResult = businessFeignClient.selectByGroupId(sysUser.getGroupId());
//                    }

//                    if (listDataResult.isSuccess() && listDataResult.getData() != null) {
//                        List<Station> stationDataList = listDataResult.getData();
//                        if (stationDataList != null && !stationDataList.isEmpty()) {
//                            stationDataList.stream().forEach(s -> stationIds.add(s.getId()));
//                            //缓存放入SimpleUser对象
//                            simpleUser.setStationIds(stationIds);
//                        }
//                    }

                    if (listDataResult.isSuccess() && listDataResult.getData() != null) {
                        List<Station> stationDataList = listDataResult.getData();
                        if (stationDataList != null && !stationDataList.isEmpty()) {
                            List<String> typeList = new ArrayList<>();
                            typeList.add(CommonConstant.OPERATIONS_PERSON);//运维人员
                            typeList.add(CommonConstant.DEBUGGING_PERSONNEL);//调试人员
                            typeList.add(CommonConstant.DEMO_USER);//演示用戶
                            List<SysSubDict> sysSubDictList = dictService.selectSubDictByTypeList(typeList);
                            Map<String, String> operationsPersonMap = new HashMap<>();
                            Map<String, String> debuggingPersonnelMap = new HashMap<>();
                            Map<String, String> demoUserMap = new HashMap<>();
                            Map<String, String> allMap = new HashMap<>();
                            for (SysSubDict sysSub:sysSubDictList) {
                                allMap.put(sysSub.getLabel(),sysSub.getValue());
                                if(CommonConstant.OPERATIONS_PERSON.equals(sysSub.getType())){
                                    operationsPersonMap.put(sysSub.getLabel(),sysSub.getValue());
                                }else if(CommonConstant.DEBUGGING_PERSONNEL.equals(sysSub.getType())){
                                    debuggingPersonnelMap.put(sysSub.getLabel(),sysSub.getValue());
                                }else if(CommonConstant.DEMO_USER.equals(sysSub.getType())){
                                    demoUserMap.put(sysSub.getLabel(),sysSub.getValue());
                                }
                            }
                            if(null == allMap.get(sysUser.getUsername())){
                                stationDataList.stream().forEach(s -> stationIds.add(s.getId()));
                            }else{
                                if(null != operationsPersonMap.get(sysUser.getUsername())){
                                    //若用户是设定的运维人员，则只能看到公司在投的电站
                                    String station = operationsPersonMap.get(sysUser.getUsername());
                                    Map<String, String> stationMap = getStringMap(station);
                                    stationDataList.stream().filter(i->CommonConstant.ONE.equals(i.getStatus()) && stationMap.get(String.valueOf(i.getId()))!=null).forEach(s -> stationIds.add(s.getId()));
                                }else if(null != debuggingPersonnelMap.get(sysUser.getUsername())){
                                    stationDataList.stream().filter(i->!CommonConstant.ONE.equals(i.getStatus())).forEach(s -> stationIds.add(s.getId()));
                                }else if(null != demoUserMap.get(sysUser.getUsername())){
                                    String station = demoUserMap.get(sysUser.getUsername());
                                    Map<String, String> stationMap = getStringMap(station);
                                    stationDataList.stream().filter(i->stationMap.get(String.valueOf(i.getId()))!=null).forEach(s -> stationIds.add(s.getId()));
                                }
                            }
//                            //运维人员
//                            Map<String, String> map = getSysSubDict(CommonConstant.OPERATIONS_PERSON);
//                            //调试人员
//                            Map<String, String> sysSubDict = getSysSubDict(CommonConstant.DEBUGGING_PERSONNEL);
//                            if(null == map.get(sysUser.getUsername()) && null == sysSubDict.get(sysUser.getUsername())){
//                                stationDataList.stream().forEach(s -> stationIds.add(s.getId()));
//                            }else{
//                                //若用户是设定的运维人员，则只能看到公司在投的电站
//                                if(null != map.get(sysUser.getUsername())){
//                                    //stationDataList.stream().filter(i->CommonConstant.ONE.equals(i.getStatus())).forEach(s -> stationIds.add(s.getId()));
//                                    stationDataList.stream().filter(i->CommonConstant.ONE.equals(i.getStatus()) && specialStation.contains(String.valueOf(i.getId()))).forEach(s -> stationIds.add(s.getId()));
//                                }else if(null != sysSubDict.get(sysUser.getUsername())){
//                                    stationDataList.stream().filter(i->!CommonConstant.ONE.equals(i.getStatus())).forEach(s -> stationIds.add(s.getId()));
//                                }
//                            }
                            //缓存放入SimpleUser对象
                            simpleUser.setStationIds(stationIds);
                        }
                    }
                } catch (Exception e) {
                    log.error("查询部门下电站时feign出错:" + e.getMessage());
                }
            }
        }
        String userId = sysUser.getId();
        simpleUser.setUserId(userId);
        simpleUser.setGroupId(sysUser.getGroupId());
        simpleUser.setDeptId(sysUser.getDeptId());
        simpleUser.setToken(token);
        simpleUser.setAesKey(loginReqVO.getAesKey());
        simpleUser.setIv(loginReqVO.getIv());
        simpleUser.setUserLevel(sysUser.getUserLevel());
        //如果groupId是0,那么是平台超管,否则不是
        if (CommonConstant.TOP_PARENT_ID.equals(sysUser.getGroupId())) {
            simpleUser.setPlatSuper(true);
            simpleUser.setDepts(new ArrayList<>());
        } else {
            simpleUser.setPlatSuper(false);
            simpleUser.setDepts(depts);
        }
        return simpleUser;
    }

    /**
     * 将字符串分割成
     * @param station
     * @return
     */
    @NotNull
    private Map<String, String> getStringMap(String station) {
        String[] stationSplit = station.split(SymbolConstant.COMMA);
        Map<String,String> stationMap = new HashMap<>();
        for (String s:stationSplit) {
            stationMap.put(s,s);
        }
        return stationMap;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addUser(UserAddReqVO vo) {
        //判断用户名不能重复
        SysUser userInfoByName = sysUserMapper.getUserInfoByName(vo.getUsername());
        if (userInfoByName != null) {
            throw new BusinessException(BaseResponseCode.USER_NAME_ALREADY_EXISTS);
        }
        //判断手机号不能重复
        SysUser userInfoByPhone = sysUserMapper.getUserInfoByPhone(vo.getPhone());
        if (userInfoByPhone != null) {
            throw new BusinessException(BaseResponseCode.PHONE_IS_USED_BY_OTHER_PERSON);
        }
        //账号手机号不能相同
        if (vo.getUsername().equals(vo.getPhone())) {
            throw new BusinessException(BaseResponseCode.USER_NAME_PHONE_CANNOT_BE_SAME);
        }
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(vo, sysUser);
        //默认密码
        String encode = BCrypt.hashpw(defaultPwd);
        sysUser.setPassword(encode);
        sysUser.setId(snowflake.nextIdStr());
        sysUser.setCreateTime(new Date());
        //用户所属group_id, 用于区分顶级集团
        SysDept topDept = deptService.getTopDept(vo.getDeptId());
        if (topDept != null) {
            sysUser.setGroupId(topDept.getId());
        }
        int i = sysUserMapper.insertSelective(sysUser);
        if (i != 1) {
            throw new BusinessException(BaseResponseCode.OPERATION_ERRO);
        }
        //增加角色关联
        if (vo.getRoleIds() != null && !vo.getRoleIds().isEmpty()) {
            UserRoleOperationReqVO reqVO = new UserRoleOperationReqVO();
            reqVO.setUserId(sysUser.getId());
            reqVO.setRoleIds(sysUser.getRoleIds());
            userRoleService.addUserRoleInfo(reqVO);
        }
        //增加岗位关联
        if (vo.getPositionIds() != null && !vo.getPositionIds().isEmpty()) {
            UserPostOperationReqVO reqVO = new UserPostOperationReqVO();
            reqVO.setUserId(sysUser.getId());
            reqVO.setPostIds(vo.getPositionIds());
            userPostService.addUserPostInfo(reqVO);
        }
    }


    @Override
    public String register(RegisterReqVO vo) {
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(vo, sysUser);
        String encode = BCrypt.hashpw(defaultPwd);
        //sysUser.setSalt(PasswordUtils.getSalt());
        //String encode = PasswordUtils.encode(vo.getPassword(), sysUser.getSalt());
        sysUser.setPassword(encode);
        sysUser.setId(snowflake.nextIdStr());
        sysUser.setCreateTime(new Date());
        int i = sysUserMapper.insertSelective(sysUser);
        if (i != 1) {
            throw new BusinessException(BaseResponseCode.OPERATION_ERRO);
        }
        return sysUser.getId();
    }


    private List<String> getRolesByUserId(String userId) {
        return roleService.getRoleNames(userId);
    }

    private Set<String> getPermissionsByUserId(String userId) {
        return permissionService.getPermissionsByUserId(userId);
    }


    @Override
    public void updateUserInfo(UserUpdateReqVO vo, String operationId, String token) {
        //注意 ，这个token是操作者的token,而不是被修改人的token
        SysUser sysUser = sysUserMapper.selectByPrimaryKey(vo.getId());
        if (null == sysUser) {
            log.error("传入 的 id:{}不合法", vo.getId());
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
        //如果是超管, 不改修改
        if (CommonConstant.TOP_PARENT_ID.equals(sysUser.getGroupId())) {
            throw new BusinessException(BaseResponseCode.SUPER_ROLE_CANNOT_MODIFY);
        }
        //判断是否修改了集团 ,修改的话同步更新大屏
        Integer groupIdOld = sysUser.getGroupId();

        SysUser user = new SysUser();
        BeanUtils.copyProperties(vo, user);
        //修改groupId
        if (!vo.getDeptId().equals(sysUser.getDeptId())) {
            //查询所更改的部门的groupId，将groupId更新
            SysDept sysDept = deptService.selectByPrimaryKey(vo.getDeptId());
            if (sysDept != null) {
                user.setGroupId(sysDept.getGroupId());
                //新集团和原有集团不一样,修改大屏token中的集团属性
                Integer groupIdNew = sysDept.getGroupId();
                if (!groupIdOld.equals(groupIdNew)) {
                    modifyLargeScreenToken(sysUser.getUsername(), groupIdNew);
                }
            }
        }
        //username不能改
        user.setUsername(null);
        //密码不改
        user.setPassword(null);
        user.setUpdateTime(new Date());
        //groupId和deptId都不能改
        //user.setGroupId(sysUser.getGroupId());
        //user.setDeptId(sysUser.getDeptId());
        user.setUpdateId(operationId);
        int count = sysUserMapper.updateByPrimaryKeySelective(user);
        if (count != 1) {
            throw new BusinessException(BaseResponseCode.OPERATION_ERRO);
        }
        updateSendSmsUserInfo(vo, sysUser);
        //当角色有值更新角色  --角色并不需要做null判断，因为角色为必传项
        if (vo.getRoleIds() != null && vo.getRoleIds().size() != 0) {
            setUserOwnRole(sysUser.getId(), vo.getRoleIds());
        }
        //有岗位时更新岗位
        if (vo.getPositionIds() != null && vo.getPositionIds().size() != 0) {
            setUserOwnPosition(sysUser.getId(), vo.getPositionIds());
        } else {
            //当等于null时，将光连表数据清空
            //根据人ID将其删除
            List<String> userIds = new ArrayList<>();
            userIds.add(vo.getId());
            userPostService.removeByUserIds(userIds);
        }
        //用户如果锁定,就把用户缓存删掉
        if (sysUser.getStatus() == 2) {
            //todo 要把用户的三个缓存都删掉
            //redisService.set(RedisKeyConstant.User.ACCOUNT_LOCK_KEY + sysUser.getId(), sysUser.getId());
        } else {
            //有登陆,判断登陆方式 是 手机号还是账号
            String pcKey = RedisKeyConstant.User.USER_NAME + RedisKeyConstant.User.LOGIN_CHANNEL_PC + ":" + sysUser.getUsername();
            String appKey = RedisKeyConstant.User.USER_NAME + RedisKeyConstant.User.LOGIN_CHANNEL_APP + ":" + sysUser.getUsername();
            if (!redisService.hasKey(pcKey)
                    && !redisService.hasKey(appKey)) {
                return;
            }
            //有登陆缓存,判断登陆方式
            String tokenKey = null;
            if (redisService.hasKey(pcKey)) {
                SimpleUser simpleUser = (SimpleUser) redisService.get(pcKey);
                //被修改人token
                String userToken = simpleUser.getToken();
                tokenKey = RedisKeyConstant.User.TOKEN + userToken;
            } else if (redisService.hasKey(appKey)) {
                SimpleUser simpleUser = (SimpleUser) redisService.get(appKey);
                //被修改人token
                String userToken = simpleUser.getToken();
                tokenKey = RedisKeyConstant.User.TOKEN + userToken;
            }
            //共同执行的代码
            if (redisService.hasKey(tokenKey)) {
                log.info("更新用户缓存:" + tokenKey);
                UserDetailRespVO userDetail = (UserDetailRespVO) redisService.get(tokenKey);

                String loginChannel = userDetail.getLoginChannel();
                //这个被更更新人登陆了,需要查信息再缓存
                UserDetailRespVO newUserDetail = getUserDetail(sysUser.getId(), loginChannel);
                //需要把权限信息放入缓存对象中
                userDetail.setRoles(newUserDetail.getRoles());
                userDetail.setRoleNames(newUserDetail.getRoleNames());
                userDetail.setPowerList(newUserDetail.getPowerList());
                //userDetail.setMenuList(newUserDetail.getMenuList());

                log.info("重新查询的数据,并缓存起来: {}", userDetail);
                //userDetail.setAccessToken(userToken);

                redisUpdateService.updateRedis(userDetail, user);
            }


        }
    }

    /**
     * 手动修改用户信息,同步更新告警短信中用户信息
     * @param vo
     * @param sysUser
     */
    private void updateSendSmsUserInfo(UserUpdateReqVO vo, SysUser sysUser) {
        SendSmsConfig smsConfig = new SendSmsConfig();
        smsConfig.setUserId(vo.getId());
        smsConfig.setPhone(vo.getPhone());
        smsConfig.setRealName(vo.getRealName());
        smsConfig.setEmail(vo.getEmail());
        smsConfig.setUpdateTime(new Date());
        smsConfig.setUpdateId(sysUser.getId());
        flowFeignClient.updateSendSmsUserInfo(smsConfig);
    }

    //修改用户大屏token
    void modifyLargeScreenToken(String userName, Integer groupIdNew) {
        String userNameKey = RedisKeyConstant.User.USER_NAME_LARGE_SCREEN + "pc:" + userName;
        log.info("userLargeTokenKey:" + userNameKey);
        if (redisService.hasKey(userNameKey)) {
            log.info("用户所属集团发生变化 ,大屏信息进行了更新: userName:{}, groupIdNew: {}", userName, groupIdNew);
            //修改用户集团
            SimpleUser simpleUser = (SimpleUser) redisService.get(userNameKey);
            simpleUser.setGroupId(groupIdNew);
            redisService.set(userNameKey, simpleUser, 365, TimeUnit.DAYS);
        }
    }

    @Override
    public PageVO<SysUser> pageInfo(UserPageReqVO vo) {
        PageHelper.startPage(vo.getPageNum(), vo.getPageSize());
        List<SysUser> sysUsers = sysUserMapper.selectAll(vo);
        if (!sysUsers.isEmpty()) {
            for (SysUser sysUser : sysUsers) {
                SysDept sysDept = deptService.detailInfo(sysUser.getDeptId());
                if (sysDept != null) {
                    sysUser.setDeptName(sysDept.getName());
                }
            }
        }
        return PageUtilsOld.getPageVO(sysUsers);
    }

    @Override
    public SysUser detailInfo(String userId) {
        SysUser sysUser = sysUserMapper.selectByPrimaryKey(userId);
        //查部门名称
        SysDept sysDept = deptService.detailInfo(sysUser.getDeptId());
        sysUser.setDeptName(sysDept.getName());
        //查用户权限
        List<Integer> roleIds = userRoleService.getRoleIdsByUserId(sysUser.getId());
        sysUser.setRoleIds(roleIds);
        //用户岗位 2022-12-06 add
        List<Integer> postIdsByUserId = userPostService.getPostIdsByUserId(userId);
        sysUser.setPositionIds(postIdsByUserId);
        return sysUser;
    }

    @Override
    public SysUser getUserByName(String userName) {
        SysUser sysUser = sysUserMapper.getUserInfoByName(userName);
        return sysUser;
    }

    @Override
    public List<SysUser> getUserListByNameConcat(String userName, Integer groupId) {
        List<SysUser> userInfoListByName = sysUserMapper.getUserInfoListByName(userName, groupId);
        return userInfoListByName;
    }

    @Override
    public SysUser getUserByPhone(String phone) {
        SysUser sysUser = sysUserMapper.getUserInfoByPhone(phone);
        return sysUser;
    }

    @Override
    public PageResult<SysUser> selectUserInfoByDeptIds(int pageNum, int pageSize, List<SysDept> depts, UserPageUserByDeptReqVO vo) {
        //将deptId抽取出来
        List<Integer> deptIds = new ArrayList<>();
        for (SysDept dept : depts) {
            deptIds.add(dept.getId());
        }
        PageHelper.startPage(pageNum, pageSize);
        List<SysUser> list = sysUserMapper.selectUserInfoByDeptIds(deptIds, vo, null);

        //将用户的deptName赋值
        list.stream().forEach(sysUser -> {
            String deptAppendName = fillDeptName(depts, sysUser.getDeptId());
            sysUser.setDeptName(deptAppendName);
        });
        //找用户的角色
        return PageUtils.getPageResult(new PageInfo<>(list));
        //return PageUtilsOld.getPageVO(list);
    }

    //递归给部门赋值
    private String fillDeptName(List<SysDept> depts, Integer currentDeptId) {
        //找deptId的pid是0的时候就退出
        Map<Integer, SysDept> map = new HashMap();
        for (SysDept dept : depts) {
            //先找到那条部门数据
            if (dept.getId().equals(currentDeptId)) {
                String topDept = findTopDept(dept.getPid(), dept.getName(), map);
                return topDept;

            }
        }
        return "";
    }

    //查顶级部门的递归
    private String findTopDept(Integer pid, String name, Map<Integer, SysDept> map) {
        //如果是顶级部门，则直接返回pid的名称
        if (CommonConstant.TOP_PARENT_ID.equals(pid)) {
            return name + "/";
        }
        SysDept sysDept = null;
        //判断map集合中是否包含
        if (!map.containsKey(pid)) {
            sysDept = sysDeptMapper.selectByPrimaryKey(pid);
            map.put(pid, sysDept);
        }
        //map中有，直接拿出来用
        else {
            sysDept = map.get(pid);
        }
        return findTopDept(sysDept.getPid(), sysDept.getName() + "/" + name, map);
    }


    @Override
    public void logout(String accessToken) {
        //if (StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(refreshToken)) {
        if (StringUtils.isEmpty(accessToken)) {
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
        Subject subject = SecurityUtils.getSubject();
        log.info("subject.getPrincipals()={}", subject.getPrincipals());
        if (subject.isAuthenticated()) {
            subject.logout();
        }
        String userTokenKey = RedisKeyConstant.User.TOKEN + accessToken;
        UserDetailRespVO userDetail = (UserDetailRespVO) redisService.get(userTokenKey);
        Map<String, String> map = checkSpecialUser();
        //特殊用户修改密码接口会直接删除redis相关缓存，后续的退出接口无须再调用
        if(null != userDetail && null == map.get(userDetail.getUsername())){
            redisService.delete(RedisKeyConstant.User.IDENTIFY_CACHE_KEY + userDetail.getUserId());
            redisService.delete(RedisKeyConstant.User.TOKEN + userDetail.getAccessToken());
            String userNameKey = redisService.getUserNameKey(userDetail, userDetail.getUsername());
            redisService.delete(userNameKey);
        }
    }

    @Override
    public void updatePwd(UpdatePasswordReqVO vo, String userId, String accessToken) {
        SysUser sysUser = sysUserMapper.selectByPrimaryKey(userId);
        if (sysUser == null) {
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
        if (!BCrypt.checkpw(vo.getOldPwd(), sysUser.getPassword())) {
            throw new BusinessException(BaseResponseCode.OLD_PASSWORD_ERROR);
        }
        sysUser.setUpdateTime(new Date());
        sysUser.setPassword(BCrypt.hashpw(vo.getNewPwd()));
        int i = sysUserMapper.updateByPrimaryKeySelective(sysUser);
        if (i != 1) {
            throw new BusinessException(BaseResponseCode.OPERATION_ERRO);
        }
        //优化可多点登录的特殊用户退出效果，由于退出接口无法识别正常退出还是修改密码后的退出，故直接在修改密码时清除特殊用户的redis缓存 禅道bug-1977
        String userTokenKey = RedisKeyConstant.User.TOKEN + accessToken;
        UserDetailRespVO userDetail = (UserDetailRespVO) redisService.get(userTokenKey);
        Map<String, String> map = checkSpecialUser();
        if(null != map.get(userDetail.getUsername())){
            redisService.delete(RedisKeyConstant.User.IDENTIFY_CACHE_KEY + userDetail.getUserId());
            redisService.delete(RedisKeyConstant.User.TOKEN + userDetail.getAccessToken());
            String userNameKey = redisService.getUserNameKey(userDetail, userDetail.getUsername());
            redisService.delete(userNameKey);
        }

    }


    @Override
    public void resetPwd(ResetPasswordReqVO vo) {
        SysUser sysUser = sysUserMapper.selectByPrimaryKey(vo.getUserId());
        //如果是超管, 不改修改
        if (CommonConstant.TOP_PARENT_ID.equals(sysUser.getGroupId())) {
            throw new BusinessException(BaseResponseCode.SUPER_ROLE_CANNOT_MODIFY);
        }
        //重置密码 ,只是给这个用户的密码重置
        sysUser = new SysUser();
        sysUser.setId(vo.getUserId());
        String encode = BCrypt.hashpw(defaultPwd);
        sysUser.setPassword(encode);
        sysUserMapper.updateByPrimaryKeySelective(sysUser);
    }


    @Override
    public List<SysUser> getUserListByDeptIds(List<Integer> deptIds) {
        return sysUserMapper.selectUserInfoByDeptIds(deptIds, new UserPageUserByDeptReqVO(), null);
    }

    @Override
    public List<SysUser> getUserListByDeptIdsAndUserIds(List<Integer> deptIds, UserPageUserByDeptReqVO userQuery, Integer groupId) {
        return sysUserMapper.selectUserInfoByDeptIds(deptIds, userQuery, groupId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deletedUsers(List<String> userIds, String operationId) {
        //判断所删除的状态是否未启用状态，如果未启用状态则不能删除
        for (String userId : userIds) {
            SysUser sysUser = sysUserMapper.selectByPrimaryKey(userId);
            if (sysUser.getStatus().equals(CommonConstant.ONE)) {
                throw new BusinessException(BaseResponseCode.USER_CANNOT_NOT_STATE_DELETE);
            }
        }
        SysUser sysUser = new SysUser();
        sysUser.setUpdateId(operationId);
        sysUser.setUpdateTime(new Date());
        int i = sysUserMapper.deletedUsers(sysUser, userIds);
        if (i == 0) {
            throw new BusinessException(BaseResponseCode.OPERATION_ERRO);
        }
        //添加一个删除用户和岗位的关联表
        int userPostDelete = userPostService.removeByUserIds(userIds);

        //添加一个删除用户和角色的关联表
        int deleteUserId = userRoleService.removeByUserIds(userIds);

        //判断是否有超级管理员
        for (String userId : userIds) {
            SysUser user = sysUserMapper.selectByPrimaryKey(userId);
            //如果是超管, 不改修改
            if (CommonConstant.TOP_PARENT_ID.equals(user.getGroupId())) {
                throw new BusinessException(BaseResponseCode.SUPER_ROLE_CANNOT_MODIFY);
            }
            String pcKey = RedisKeyConstant.User.USER_NAME + RedisKeyConstant.User.LOGIN_CHANNEL_PC + ":" + user.getUsername();
            String appKey = RedisKeyConstant.User.USER_NAME + RedisKeyConstant.User.LOGIN_CHANNEL_APP + ":" + user.getUsername();
            if (redisService.hasKey(pcKey)) {
                redisService.delete(RedisKeyConstant.User.IDENTIFY_CACHE_KEY + user.getId());
                SimpleUser simpleUser = (SimpleUser) redisService.get(pcKey);
                redisService.delete(pcKey);
                redisService.delete(RedisKeyConstant.User.TOKEN + simpleUser.getToken());
            } else if (redisService.hasKey(appKey)) {
                redisService.delete(RedisKeyConstant.User.IDENTIFY_CACHE_KEY + user.getId());
                SimpleUser simpleUser = (SimpleUser) redisService.get(appKey);
                redisService.delete(appKey);
                redisService.delete(RedisKeyConstant.User.TOKEN + simpleUser.getToken());
            }
        }

    }

    @Override
    public void setUserOwnRole(String userId, List<Integer> roleIds) {
        userRoleService.removeByUserId(userId);
        if (roleIds != null && !roleIds.isEmpty()) {

            UserRoleOperationReqVO reqVO = new UserRoleOperationReqVO();
            reqVO.setUserId(userId);
            reqVO.setRoleIds(roleIds);
            userRoleService.addUserRoleInfo(reqVO);
        }
        //redisService.delete(RedisKeyConstant.User.IDENTIFY_CACHE_KEY + userId);
    }

    @Override
    public void setUserOwnPosition(String userId, List<Integer> positionIds) {
        //userPostService.removeByUserId(userId);
        if (positionIds != null && !positionIds.isEmpty()) {
            UserPostOperationReqVO reqVO = new UserPostOperationReqVO();
            reqVO.setUserId(userId);
            reqVO.setPostIds(positionIds);
            userPostService.addUserPostInfo(reqVO);
        }

    }

    /**
     * 包含用户角色/菜单/权限列表
     *
     * @param userId
     * @param loginChannel 登陆渠道 手机 或 PC
     * @return
     */
    @Override
    public UserDetailRespVO getUserDetail(String userId, String loginChannel) {
        UserDetailRespVO userDetail = new UserDetailRespVO();
        //查用户信息
        SysUser sysUser = sysUserMapper.selectByPrimaryKey(userId);
        if (sysUser == null) {
            return userDetail;
        }
        userDetail.setUserId(userId);
        userDetail.setUsername(sysUser.getUsername());
        userDetail.setDeptId(sysUser.getDeptId());
        userDetail.setPhone(sysUser.getPhone());
        SysDept sysDept = deptService.detailInfo(sysUser.getDeptId());
        if (sysDept == null) {
            userDetail.setDeptName("平台超级部门");
        } else {
            userDetail.setDeptName(sysDept.getName());
        }
        Integer userLevel = sysUser.getUserLevel();
        if(userLevel!=null){
            userDetail.setUserLevel(userLevel);
        }
        //查角色ids
        List<SysRole> roleInfoByUserId = roleService.getRoleInfoByUserId(userId);
        List<Integer> roleIds = roleInfoByUserId.stream().map(s -> {
            return s.getId();
        }).collect(Collectors.toList());
        if (roleIds.isEmpty()) {
            return userDetail;
        }
        userDetail.setRoleIds(roleIds);
        //查询角色列表
        List<SysRole> roleList = roleService.getRoleInfoByRoleIds(roleIds);
        List<String> roleCodes = getRoleCodes(roleList);
        if (roleList.isEmpty()) {
            return userDetail;
        }
        userDetail.setRoles(roleCodes);
        //角色名称列表
        List<String> roleNames = roleService.getRoleNames(userId);
        userDetail.setRoleNames(roleNames);
        //岗位列表
        List<SysPosition> postListByUserId = userPostService.getPostListByUserId(userId);
        List<PositionVo> positionList = new ArrayList<>();
        List<String> postCodes = new ArrayList<>();
        postListByUserId.stream().forEach(p -> postCodes.add(p.getPostCode()));
        userDetail.setPositions(postCodes);
        if (!postListByUserId.isEmpty()) {
            for (SysPosition sysPosition : postListByUserId) {
                PositionVo vo = new PositionVo();
                vo.setId(sysPosition.getId());
                vo.setName(sysPosition.getName());
                vo.setPostCode(sysPosition.getPostCode());
                positionList.add(vo);
            }
        }
        userDetail.setPositionList(positionList);
        //根据roles查询菜单列表
        //是否是超管
        boolean superFlag = CommonConstant.TOP_PARENT_ID.equals(sysUser.getGroupId());
        //全量的菜单集合
        List<SysPermission> permissions = new ArrayList<>();
        //超管,只查询 系统管理下 的菜单
        if (superFlag) {
            SysPermission sysManageMenu = permissionService.findSysManageMenu();
            if (sysManageMenu != null) {
                List<SysPermission> menuList = new ArrayList<>();
                menuList.add(sysManageMenu);
                List<Integer> queryIds = new ArrayList<>();
                queryIds.add(sysManageMenu.getId());
                permissions = permissionService.getSysMangeMenus(menuList, queryIds);
            }
        }
        //非超管,查询角色该有的
        else {
            permissions = permissionService.getPermissionByRoleIds(roleIds,null);
        }
        if (permissions.isEmpty()) {
            userDetail.setMenuList(new ArrayList<>());
            userDetail.setPowerList(new ArrayList<>());
            return userDetail;
        }

        //把菜单标签加工成列表
        userDetail.setPowerList(dealPowerTag(permissions));
        return userDetail;
    }


    /**
     * 判断是否为超管
     * 根据 roleIds
     *
     * @return
     */
    private List<SysPermission> getMenuListTree(boolean superFlag, List<SysPermission> permissions, String loginChannel) {
        //根据roles查询菜单列表

        List<SysPermission> topMenus = new ArrayList<>();
        //超管,只查询 系统管理下 的菜单
        if (superFlag) {
            SysPermission sysManageMenu = permissionService.findSysManageMenu();
            if (sysManageMenu != null) {
                sysManageMenu.setChildren(getPermTree(sysManageMenu.getId(), permissions));
                //将菜单放入userDetail对象
                List<SysPermission> menus = new ArrayList<>();
                menus.add(sysManageMenu);
                return menus;
            }
        }
        //非超管,查询角色该有的
        else {
            topMenus = filterTopMenus(permissions, loginChannel);
            // userDetail.setMenuList(topMenus);
            //递归找每个菜单的子菜单
            //此时permList只有一级菜单,需要递归找到它的所有子集
            for (SysPermission sysPermission : topMenus) {
                sysPermission.setChildren(getPermTree(sysPermission.getId(), permissions));
            }
            return topMenus;
        }
        return null;
    }


    //获取到一级菜单,并且按照order_num排序
    private List<SysPermission> filterTopMenus(List<SysPermission> permissions, String loginChannel) {
        if (permissions == null) {
            return new ArrayList<>();
        }
        List<SysPermission> parentList = new ArrayList<>();
        //登陆渠道是app
        if (RedisKeyConstant.User.LOGIN_CHANNEL_APP.equals(loginChannel)) {
            //只找顶级菜单 show 类型是all或是app的
            for (SysPermission permission : permissions) {
                //顶级菜单,并且
                if (CommonConstant.TOP_PARENT_ID.equals(permission.getPid()) &&
                        //和下面的条件要同时成立
                        (CommonConstant.MenuShowType.ALL.equals(permission.getShow())
                                //all或app的
                                || CommonConstant.MenuShowType.APP.equals(permission.getShow())
                        )) {
                    parentList.add(permission);
                }
            }
        }
        //登陆渠道是pc的
        else if (RedisKeyConstant.User.LOGIN_CHANNEL_PC.equals(loginChannel)) {
            //只找顶级菜单 show 类型是all或是app的
            for (SysPermission permission : permissions) {
                //顶级菜单,并且
                if (CommonConstant.TOP_PARENT_ID.equals(permission.getPid()) &&
                        //和下面的条件要同时成立
                        (CommonConstant.MenuShowType.ALL.equals(permission.getShow())
                                //all或pc的
                                || CommonConstant.MenuShowType.PC.equals(permission.getShow())
                        )) {
                    parentList.add(permission);
                }
            }
        }
        //getPermList用不到了暂时不用这个方法了,因为前端递归时顺序会发生改变
        //得到全部合规菜单, 开始时就跟节点放入targetList，所以targetList传入 parentList
        //List<SysPermission> permList = getPermList(parentList, permissions, parentList);
        //对parentList进行排序

        List<SysPermission> permList = parentList.stream().sorted(Comparator.comparing(SysPermission::getOrderNum)).collect(Collectors.toList());
        return permList;
    }

    /**
     * @param id          根据这个id找它的子集
     * @param permissions 全量菜单集合
     * @return
     */
    private List<SysPermission> getPermTree(Integer id, List<SysPermission> permissions) {
        List<SysPermission> list = new ArrayList<>();
        for (SysPermission permission : permissions) {
            if (permission.getPid().equals(id) && CommonConstant.MENU_FLAG.equals(permission.getType())) {
                permission.setChildren(getPermTree(permission.getId(), permissions));
                list.add(permission);
            }
        }
        return list;
    }


    //那个递归方法 2022-11-16暂时不用了,改用新的递归方法
    //targetList 目标数组,从顶层开始不断增加
    //srcList 原始数组,从顶层开始不断增加
    //parentList父级菜单
    @Deprecated
    private List<SysPermission> getPermList(List<SysPermission> targetList, List<SysPermission> srcList, List<SysPermission> parentList) {
        if (parentList.isEmpty()) {
            return targetList;
        }
        List<SysPermission> parentNewList = new ArrayList<>();

        //从srcList找 pid是parentList的数据放到 targetList
        for (int i = 0; i < parentList.size(); i++) {
            for (int j = 0; j < srcList.size(); j++) {
                if (srcList.get(j).getPid().equals(parentList.get(i).getId())) {
                    if (!targetList.contains(srcList.get(j))) {
                        targetList.add(srcList.get(j));
                    }
                    //这个数据作为下一次数组的父对象
                    parentNewList.add(srcList.get(j));
                }
            }
        }
        //递归调用
        return getPermList(targetList, srcList, parentNewList);
    }


    //抽取roleCode
    private List<String> getRoleCodes(List<SysRole> roleList) {
        List<String> roles = new ArrayList<>();
        if (roleList != null) {
            for (SysRole sysRole : roleList) {
                roles.add(sysRole.getCode());
            }
        }
        return roles;
    }

    /**
     * 从菜单列表中提取权限标签
     *
     * @param permissions 菜单列表
     * @return
     */
    private List<String> dealPowerTag(List<SysPermission> permissions) {
        final List<String> powerList = new ArrayList<>();
        permissions.stream().filter(p -> !StrUtil.isBlank(p.getPerms())).forEach(p -> {
            powerList.add(p.getPerms());
        });
        return powerList;
    }


    @Override
    public List<SysUser> selectIds(List<String> userIds) {
        List<SysUser> sysUsers = sysUserMapper.selectByIds(userIds, new OrderUserSelectReqVo());
        return sysUsers;
    }

    //清除用户的登陆缓存
    @Override
    public void removeUserCache(String username, String loginChannel) {
        String userNameKey = RedisKeyConstant.User.USER_NAME + loginChannel + ":" + username;
        //如果已经登陆,失效原有token信息
        if (redisService.hasKey(userNameKey)) {
            //清除原有登陆信息
            SimpleUser simpleUser = (SimpleUser) redisService.get(userNameKey);
            if (simpleUser != null) {
                String token = simpleUser.getToken();
                String userTokenKey = RedisKeyConstant.User.TOKEN + token;
                if (redisService.hasKey(userTokenKey)) {
                    redisService.delete(userTokenKey);
                }
                if (redisService.hasKey(userNameKey)) {
                    redisService.delete(userNameKey);
                }
                //权限shiro缓存
                String shiroKey = RedisKeyConstant.User.IDENTIFY_CACHE_KEY + simpleUser.getUserId();
                if (redisService.hasKey(shiroKey)) {
                    redisService.delete(shiroKey);
                }
            }
        }
    }

    @Override
    public List<SysUser> selectByIds(List<String> userIdsByPostIds, OrderUserSelectReqVo vo) {
        List<SysUser> sysUsers = sysUserMapper.selectByIds(userIdsByPostIds, vo);
        return sysUsers;
    }

    @Override
    public SysUser selectById(String userId) {
        SysUser user = sysUserMapper.selectByPrimaryKey(userId);
        return user;
    }

    @Override
    public List<SysUser> selectByDeptId(Integer deptId) {
        return sysUserMapper.getUserListByDeptId(deptId);
    }

    @Override
    public List<SysUser> selectByDeptIds(List<Integer> deptIds) {
        UserPageUserByDeptReqVO user = new UserPageUserByDeptReqVO();
        user.setStatus(CommonConstant.STATUS_FLAG);
        return sysUserMapper.selectUserInfoByDeptIds(deptIds, user, null);
    }

    @Override
    public Map<String, String> checkSpecialUser() {
        Map<String,String> userMap = new HashMap<>();
        List<SysSubDict> sysSubDictList = dictService.selectSubDictByType(CommonConstant.SPECIAL_USER,null);
        for (SysSubDict sysSub:sysSubDictList) {
            userMap.put(sysSub.getValue(),sysSub.getValue());
        }
        return userMap;
    }

    @Override
    public Map<String, String> getSysSubDict(SysSubDictVO vo) {
        Map<String,String> userMap = new HashMap<>();
        List<SysSubDict> sysSubDictList = dictService.selectSubDictByType(vo.getType(),null);
        for (SysSubDict sysSub:sysSubDictList) {
            if(CommonConstant.ONE.equals(vo.getKeyVal())){
                userMap.put(sysSub.getLabel(),sysSub.getValue());
            }else{
                userMap.put(sysSub.getValue(),sysSub.getLabel());
            }
        }
        return userMap;
    }

    @Override
    public List<SysUser> selectPostUserIds(List<String> userIds, List<Integer> postIds) {

        return sysUserMapper.selectPostUserIds(userIds,postIds);

    }

    @Override
    public SysUserThemeRespVo getUserTheme(String userId) {
        SysUserThemeRespVo theme = sysUserMapper.getUserTheme(userId);
        return theme;
    }

    @Override
    public List<SysTheme> getSysTheme() {
        List<SysTheme> sysThemeList = sysUserMapper.getSysTheme();
        return sysThemeList;
    }

    @Override
    public void addUserTheme(SysUserThemeReqVo sysUserThemeReqVo) {
        //首先删除原有用户id主题数据
        sysUserMapper.deletedUserTheme(sysUserThemeReqVo.getUserId());
        //新增本次用户主题数据
        sysUserMapper.addUserTheme(sysUserThemeReqVo);

    }


}
