package com.webchat.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.webchat.common.bean.APIPageResponseBean;
import com.webchat.common.constants.CookieConstants;
import com.webchat.common.constants.WebConstant;
import com.webchat.common.enums.APIErrorCommonEnum;
import com.webchat.common.enums.RedisKeyEnum;
import com.webchat.common.enums.RoleCodeEnum;
import com.webchat.common.enums.UserStatusEnum;
import com.webchat.common.exception.BusinessException;
import com.webchat.common.helper.SessionHelper;
import com.webchat.common.util.*;
import com.webchat.domain.convert.UserEntryConvert;
import com.webchat.domain.vo.request.CreateGroupRequestVO;
import com.webchat.domain.vo.request.CreatePublicAccountRequestVO;
import com.webchat.domain.vo.request.CreateRobotRequestVO;
import com.webchat.domain.vo.request.UpdateUserInfoRequestVO;
import com.webchat.domain.vo.response.GroupResponseInfoVO;
import com.webchat.domain.vo.response.UserBaseResponseInfoVO;
import com.webchat.domain.vo.response.UserSafeResponseInfoVO;
import com.webchat.domain.vo.response.publicaccount.PublicAccountVO;
import com.webchat.repository.dao.IGroupUserDAO;
import com.webchat.repository.dao.IUserDAO;
import com.webchat.repository.entity.GroupUserEntity;
import com.webchat.repository.entity.UserEntity;
import com.webchat.service.publicaccount.PublicAccountService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class UserService {

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private HttpServletResponse response;

    @Autowired
    private IUserDAO userDAO;

    @Autowired
    private RedisService redisService;

    @Autowired
    private IGroupUserDAO groupUserDAO;

    @Autowired
    private PublicAccountService publicAccountService;

    /***
     * USER ID 前缀
     */
    private static final String USER_ID_PREFIX = "U";
    private static final String ROBOT_ID_PREFIX = "R";
    private static final String GROUP_ID_PREFIX = "G";
    private static final String PUBLIC_ACCOUNT_ID_PREFIX = "P";

    /**
     * 用户登录 - 登录成功返回用户基本信息
     * @param mobile
     * @param password
     * @return
     */
    public UserBaseResponseInfoVO login(String mobile, String password) {
        if (!hasUserInfo(mobile)) {
            throw new BusinessException(APIErrorCommonEnum.USER_NOT_FOUND);
        }
        UserEntity userEntity = userDAO.findByMobileAndPassword(mobile, md5Pwd(password));
        if (userEntity == null) {
            throw new BusinessException("密码验证失败");
        }
        if (userEntity.getRoleCode().equals(RoleCodeEnum.BLACK.getCode())) {
            throw new BusinessException("账号异常！联系管理员解封");
        }
        UserBaseResponseInfoVO user = userLogin(userEntity);
        return user;
    }

    private UserBaseResponseInfoVO userLogin(UserEntity userEntity) {
        // 创建用户登录会话数据
        this.createLoginSession(userEntity.getUserId());
        UserBaseResponseInfoVO user = UserEntryConvert.convertBaseVo(userEntity);
        return user;
    }

    /**
     * 用户注册 - 注册成功自动登录
     * @param photo
     * @param userName
     * @param mobile
     * @param password
     * @return
     */
    // 这里其实不需要事务，因为想分享事务管理器的用法和场景，刻意添加了事务注解
    @Transactional
    public boolean registry(String photo, String userName, String mobile, String password) {
        // 参数校验
        this.validateRegistryParam(userName, mobile);
        // 注册信息入库
        String uid = this.registryUser2DB(userName, photo, mobile, password);
        // 注册成功，事务结束后刷新用户缓存信息
        TransactionSyncManagerUtil.registerSynchronization(() -> {
            // 刷新用户缓存
            this.refreshAndGetUserEntityFromCache(uid);
        });
        return true;
    }

    private void validateRegistryParam(String userName, String mobile) {
        if (hasUserInfo(mobile)) {
            throw new BusinessException("用户已存在");
        }
        if (!Pattern.matches("^[0-9a-zA-Z_]{1,}$", mobile)) {
            throw new BusinessException("账号格式不合法");
        }
        if (StringUtils.isBlank(userName) || userName.length() < 2 || userName.length() > 12) {
            throw new BusinessException("用户名不合法：2~12位字符");
        }
        if (userNameIsExist(userName)) {
            throw new BusinessException("用户名已经被占用，换一个吧");
        }
    }

    public UserBaseResponseInfoVO queryByMobile(String mobile) {
        UserEntity userEntity = userDAO.findByMobile(mobile);
        return UserEntryConvert.convertBaseVo(userEntity);
    }

    public APIPageResponseBean<List<UserSafeResponseInfoVO>> getUserList(Integer roleCode, int pageNo, int pageSize) {
        Pageable pageable = PageRequest.of(pageNo - 1, pageSize, Sort.by(Sort.Direction.DESC, "id"));
        Page<UserEntity> userEntities;
        if (roleCode == null) {
            userEntities = userDAO.findAll(pageable);
        } else {
            userEntities = userDAO.findAllByRoleCode(roleCode, pageable);
        }
        List<UserSafeResponseInfoVO> userSafeResponseInfoVOS = new ArrayList<>();
        if (userEntities != null && CollectionUtils.isNotEmpty(userEntities.getContent())) {
            userEntities.getContent().stream().forEach(u -> {
                UserSafeResponseInfoVO userSafeResponseInfoVO = UserEntryConvert.convertSafeVo(u);
                userSafeResponseInfoVOS.add(userSafeResponseInfoVO);
            });
        }
        return APIPageResponseBean.success(pageNo, pageSize, userEntities.getTotalElements(), userSafeResponseInfoVOS);
    }

    /**
     * 创建机器人
     *
     * 复用用户信息表，账号角色为 ROBOT
     */
    @Transactional
    public void createRobot(CreateRobotRequestVO requestPram) {
        String robotNumber = requestPram.getRobotNumber();
        String robotName = requestPram.getRobotName();
        String robotRole = requestPram.getRobotRole();
        String createUserId = requestPram.getCreateUserId();
        String robotPhoto = requestPram.getRobotPhoto();
        UserEntity userEntity = userDAO.findByMobile(robotName);
        Assert.isTrue(userEntity == null, "机器人账号已存在！");
        /**
         * 防快速点击
         */
        String key = RedisKeyEnum.CREATE_ROBOT_LIMIT.getKey(createUserId);
        boolean lockResult = redisService.installDistributedLock(key, WebConstant.CACHE_NONE, RedisKeyEnum.CREATE_ROBOT_LIMIT.getExpireTime());
        Assert.isTrue(lockResult, "创建中请稍等！请勿频繁点击");
        /**
         * 创建机器人
         */
        robotRole = StringUtils.isBlank(robotRole) ? "全能助手" : robotRole;
        this.registryRobot2DB(requestPram.getId(), robotNumber, robotName, robotRole, robotPhoto, createUserId);
    }

    /**
     * 创建公众号
     *
     * 复用用户信息表，账号角色为 PUBLIC_ACCOUNT
     */
    @Transactional
    public void createPublicAccount(CreatePublicAccountRequestVO requestVO) {
        String account = requestVO.getAccount();
        String accountName = requestVO.getAccountName();
        String signature = requestVO.getSignature();
        String photo = requestVO.getAccountPhoto();
        String createUserId = requestVO.getCreateUserId();
        /**
         * 防快速点击
         */
        String key = RedisKeyEnum.CREATE_PUBLIC_ACCOUNT_LIMIT.getKey();
        boolean lockResult = redisService.installDistributedLock(key, WebConstant.CACHE_NONE, RedisKeyEnum.CREATE_ROBOT_LIMIT.getExpireTime());
        Assert.isTrue(lockResult, "创建中请稍等！请勿频繁点击");
        // 创建机器人
        this.registryPublicAccount2DB(account, accountName, photo, signature, createUserId);
    }

    /**
     * 创建聊天群组
     *
     * 群组复用用户信息表，账号角色为 GROUP
     */
    @Transactional
    public void createChatGroup(CreateGroupRequestVO requestPram) {
        String groupName = requestPram.getGroupName();
        String createUserId = requestPram.getCreateUserId();
        Set<String> groupUserIdSet = requestPram.getUserIds();
        Assert.isTrue(CollectionUtils.isNotEmpty(groupUserIdSet) && groupUserIdSet.size() >= 2, "至少需要添加3名成员");
        // 群组默认添加创建人，群聊的创建人默认为群聊管理员
        groupUserIdSet.add(createUserId);
        /**
         * 创建群组
         */
        String groupId = this.registryGroup2DB(groupName, createUserId);
        /**
         * 保存群组成员
         */
        this.addUsers2Group(groupId, groupUserIdSet, createUserId);
        /**
         * 用户刷新群组缓存
         */
        removeGroupUserIdsFromCacheByUserId(groupUserIdSet);
        /**
         * 刷新群组中的用户列表缓存
         * 事务提交成功后，刷新群组中用户列表缓存
         */
        TransactionSyncManagerUtil.registerSynchronization(() -> refreshGroupUserIdListCache(groupId));
    }

    /**
     * 查询用户加入的所有群聊
     *
     * @param userId
     * @return
     */
    public List<GroupResponseInfoVO> listUserAttendGroupsFromCache(String userId) {
        if (StringUtils.isBlank(userId)) {
            return Collections.emptyList();
        }
        List<String> groupIds = this.getGroupUserIdsFromCacheByUserId(userId);
        if (CollectionUtils.isEmpty(groupIds)) {
            return Collections.emptyList();
        }
        List<UserBaseResponseInfoVO> groups = this.batchGetUserListInfoFromCache(groupIds);
        return groups.stream().map(g -> {
            GroupResponseInfoVO groupResponseInfoVO = new GroupResponseInfoVO();
            groupResponseInfoVO.setId(g.getId());
            groupResponseInfoVO.setGroupId(g.getUserId());
            groupResponseInfoVO.setGroupName(g.getUserName());
            // 这里性能可能存在问题，最好不要在遍历中查询，当前为了省事，先这么干了
            groupResponseInfoVO.setUserCount(getGroupUserIdsFromCache(g.getUserId()).size());
            return groupResponseInfoVO;
        }).collect(Collectors.toList());
    }

    /**
     * 查询群组下所有用户信息列表
     *
     * @param groupId
     * @return
     */
    public List<UserBaseResponseInfoVO> getGroupUsersFromCache(String groupId, String userId) {
        List<String> groupIds = getGroupUserIdsFromCache(groupId);
        if (CollectionUtils.isEmpty(groupIds)) {
            return Collections.emptyList();
        }
        Assert.isTrue(groupIds.contains(userId), "无群组查看权限！");
        // 缓存中批量查询用户信息
        return this.batchGetUserListInfoFromCache(groupIds);
    }

    /**
     * 查询群组下所有用户ID列表
     *
     * @param groupId
     * @return
     */
    public List<String> getGroupUserIdsFromCache(String groupId) {
        String key = RedisKeyEnum.GROUP_USER_ID_LIST_CACHE.getKey(groupId);
        // redis中取群组下所有用户ID列表
        Set<String> userIds = redisService.zreverseRange(key, 0, Integer.MAX_VALUE);
        if (CollectionUtils.isEmpty(userIds)) {
            userIds = refreshGroupUserIdListCache(groupId);
        }
        return new ArrayList<>(userIds);
    }

    /**
     * 查询用户加入的所有群组
     *
     *
     * @param userId
     * @return
     */
    public List<String> getGroupUserIdsFromCacheByUserId(String userId) {
        String key = RedisKeyEnum.USER_ATTEND_GROUP_ID_LIST_CACHE.getKey(userId);
        // redis中取群组下所有用户ID列表
        String cache = redisService.get(key);
        if (StringUtils.isNotBlank(cache)) {
            return JsonUtil.fromJson(cache, new TypeReference<List<String>>() {});
        }
        return this.refreshUserAttendGroupIdListCache(userId);
    }

    /**
     * 删除用加入的群组列表缓存
     *
     * @param userIds
     */
    private void removeGroupUserIdsFromCacheByUserId(Set<String> userIds) {
        for (String userId : userIds) {
            String key = RedisKeyEnum.USER_ATTEND_GROUP_ID_LIST_CACHE.getKey(userId);
            redisService.remove(key);
        }
    }

    private List<String> refreshUserAttendGroupIdListCache(String userId) {
        String key = RedisKeyEnum.USER_ATTEND_GROUP_ID_LIST_CACHE.getKey(userId);
        List<GroupUserEntity> groupUserEntities = groupUserDAO.findAllByUserIdAndStatusOrderByIdDesc(userId, UserStatusEnum.ENABLE.getStatus());
        List<String> groupIds = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(groupUserEntities)) {
            groupIds = groupUserEntities.stream().map(GroupUserEntity::getGroupId).collect(Collectors.toList());
        }
        redisService.set(key, JsonUtil.toJsonString(groupIds), RedisKeyEnum.USER_ATTEND_GROUP_ID_LIST_CACHE.getExpireTime());
        return groupIds;
    }

    /**
     * 刷新群组下用户列表缓存
     */
    private Set<String> refreshGroupUserIdListCache(String groupId) {
        String key = RedisKeyEnum.GROUP_USER_ID_LIST_CACHE.getKey(groupId);
        List<GroupUserEntity> groupUserEntities =
                groupUserDAO.findAllByGroupIdAndStatusOrderByIdDesc(groupId, UserStatusEnum.ENABLE.getStatus());
        // 先清空
        redisService.remove(key);
        if (CollectionUtils.isEmpty(groupUserEntities)) {
            return Collections.emptySet();
        }
        Set<ZSetOperations.TypedTuple<String>> typedTupleSet = new HashSet<>();
        for (GroupUserEntity groupUser : groupUserEntities) {
            String value = groupUser.getUserId().toString();
            double score = groupUser.getId();
            ZSetOperations.TypedTuple<String> tuple = new DefaultTypedTuple<>(value, score);
            typedTupleSet.add(tuple);
        }
        redisService.zadd(key, typedTupleSet, RedisKeyEnum.GROUP_USER_ID_LIST_CACHE.getExpireTime());
        return groupUserEntities.stream().map(GroupUserEntity::getUserId).collect(Collectors.toSet());
    }

    /**
     * 添加用户到群组
     *
     * @param groupId
     * @param userIdSet
     * @param createUserId
     */
    private void addUsers2Group(String groupId, Set<String> userIdSet, String createUserId) {
        if (CollectionUtils.isEmpty(userIdSet)) {
            return;
        }
        Date now = new Date();
        List<GroupUserEntity> groupUserEntities = userIdSet.stream().map(
                uid -> {
                    GroupUserEntity groupUserEntity = new GroupUserEntity();
                    groupUserEntity.setGroupId(groupId);
                    groupUserEntity.setUserId(uid);
                    groupUserEntity.setStatus(UserStatusEnum.ENABLE.getStatus());
                    groupUserEntity.setCreateBy(createUserId);
                    groupUserEntity.setCreateDate(now);
                    return groupUserEntity;
                }
        ).collect(Collectors.toList());
        // 批量添加用户到群组
        groupUserDAO.saveAll(groupUserEntities);
    }

    /**
     * 退出登录
     */
    public void logout() {
        String userId = getLoginCurrentUserId();
        // 清理登录Session
        Cookie[] cookies = request.getCookies();
        for(Cookie cookie : cookies) {
            if (CookieConstants.C_U_USER_COOKIE_KEY.equals(cookie.getName())) {
                cookie.setValue(null);
                cookie.setMaxAge(0);
                cookie.setPath("/");
                response.addCookie(cookie);
            }
        }
        // 清理缓存
        if (StringUtils.isNotBlank(userId)) {
            String sessionKey = RedisKeyEnum.USER_SESSION_PREFIX.getKey(MD5Utils.md5(userId));
            redisService.remove(sessionKey);
        }
    }

    /**
     * 注册用户到数据库
     *
     * @param userName
     * @param photo
     * @param mobile
     * @param password
     */
    private String registryUser2DB(String userName, String photo, String mobile, String password) {
        UserEntity userEntity = new UserEntity();
        String userId = IDGenerateUtil.createId(USER_ID_PREFIX);
        userEntity.setUserId(userId);
        userEntity.setUserName(StringUtil.handleSpecialHtmlTag(userName));
        userEntity.setPhoto(photo);
        userEntity.setMobile(mobile);
        userEntity.setStatus(UserStatusEnum.ENABLE.getStatus());
        userEntity.setPassword(md5Pwd(password));
        userEntity.setRoleCode(RoleCodeEnum.USER.getCode());
        userEntity.setCreateBy(userId);
        // 注册用户
        return userDAO.save(userEntity).getUserId();
    }

    /**
     * 创建群组到数据库
     *
     * @param groupName
     * @param createUserId
     */
    private String registryGroup2DB(String groupName, String createUserId) {
        UserEntity userEntity = new UserEntity();
        String groupId = IDGenerateUtil.createId(GROUP_ID_PREFIX);
        userEntity.setUserId(groupId);
        userEntity.setUserName(StringUtil.handleSpecialHtmlTag(groupName));
        userEntity.setPhoto("https://coderutil.oss-cn-beijing.aliyuncs.com/bbs-image/file_6b2a447e4a1f4df8870f8a51e2874618.png");
        userEntity.setMobile("-");
        userEntity.setStatus(UserStatusEnum.ENABLE.getStatus());
        // 密码设置为用户ID, 本身也不支持登录
        userEntity.setPassword(md5Pwd(groupId));
        userEntity.setRoleCode(RoleCodeEnum.GROUP.getCode());
        userEntity.setCreateBy(createUserId);
        // 注册用户
        userDAO.save(userEntity);
        // 注册成功，事务结束后刷新用户缓存信息
        TransactionSyncManagerUtil.registerSynchronization(() -> {
            // 刷新用户缓存
            this.refreshAndGetUserEntityFromCache(groupId);
        });
        return groupId;
    }

    /**
     * 创建机器人到数据库
     *
     * @param robotName
     * @param createUserId
     */
    private String registryRobot2DB(Long id, String robotNumber, String robotName, String role, String robotPhoto, String createUserId) {
        UserEntity userEntity;

        if (id != null) {
            userEntity = userDAO.findById(id).orElse(null);
        } else {
            userEntity = new UserEntity();
            String robotId = IDGenerateUtil.createId(ROBOT_ID_PREFIX);
            userEntity.setUserId(robotId);
            // 密码设置为用户ID, 本身也不支持登录
            userEntity.setPassword(md5Pwd(robotId));
            userEntity.setStatus(UserStatusEnum.ENABLE.getStatus());
            userEntity.setRoleCode(RoleCodeEnum.ROBOT.getCode());
            userEntity.setCreateBy(createUserId);
        }
        userEntity.setUserName(robotName);
        userEntity.setPhoto(robotPhoto);
        userEntity.setMobile(robotNumber);
        userEntity.setSignature(role);
        // 注册用户
        userEntity = userDAO.save(userEntity);
        String robotId = userEntity.getUserId();
        // 注册成功，事务结束后刷新用户缓存信息
        TransactionSyncManagerUtil.registerSynchronization(() -> {
            // 刷新用户缓存
            this.refreshAndGetUserEntityFromCache(robotId);
        });
        return robotId;
    }

    /**
     * 创建公众号
     * @return
     */
    private String registryPublicAccount2DB(String account, String accountName, String accountPhoto,
                                            String accountSignature, String createUserId) {

        UserEntity userEntity = userDAO.findByMobile(account);
        Assert.isTrue(userEntity == null, "公众号已经存在");

        userEntity = new UserEntity();
        String userId = IDGenerateUtil.createId(PUBLIC_ACCOUNT_ID_PREFIX);
        userEntity.setUserId(userId);
        userEntity.setUserName(StringUtil.handleSpecialHtmlTag(accountName));
        userEntity.setPhoto(accountPhoto);
        userEntity.setMobile(account);
        userEntity.setSignature(accountSignature);
        userEntity.setStatus(UserStatusEnum.ENABLE.getStatus());
        // 密码设置为用户ID, 本身也不支持登录
        userEntity.setPassword(md5Pwd(account));
        userEntity.setRoleCode(RoleCodeEnum.PUBLIC_ACCOUNT.getCode());
        userEntity.setCreateBy(createUserId);
        // 注册用户
        userDAO.save(userEntity);
        // 注册成功，事务结束后刷新用户缓存信息
        TransactionSyncManagerUtil.registerSynchronization(() -> {
            // 刷新用户缓存
            this.refreshAndGetUserEntityFromCache(account);
            // 刷新公众号文章列表
            publicAccountService.refreshPublicAccountListCache();
        });
        return userId;
    }

    /**
     * 判断用户是否存在
     * @param mobile
     * @return
     */
    private boolean hasUserInfo(String mobile) {
        return userDAO.findByMobile(mobile) != null;
    }

    private boolean userNameIsExist(String userName) {
        return userDAO.findByUserName(userName) != null;
    }

    /**
     * 获取当前登录用户信息
     * @return
     */
    public UserBaseResponseInfoVO getCurrentUserInfo() {

        return getLoginUserBaseInfoFromCache();
    }

    public UserBaseResponseInfoVO getLoginUserBaseInfoFromCache() {
        String userId = this.getLoginCurrentUserId();
        return getUserBaseInfoByUserIdFromCache(userId);
    }

    public UserBaseResponseInfoVO getUserInfoByUserId(String userId) {
        return getUserBaseInfoByUserId(userId);
    }

    /**
     * 用户信息编辑
     *
     * @param updateUserInfoRequest
     * @return
     */
    public boolean updateUserInfo(UpdateUserInfoRequestVO updateUserInfoRequest) {
        // 更新数据库
        UserEntity userEntity = userDAO.findByUserId(updateUserInfoRequest.getUserId());
        Assert.notNull(userEntity, "用户信息更新失败: 用户不存在！");
        // 支持单独修改头像或者昵称
        if (StringUtils.isNotBlank(updateUserInfoRequest.getUserName())) {
            userEntity.setUserName(updateUserInfoRequest.getUserName());
        }
        if (StringUtils.isNotBlank(updateUserInfoRequest.getPhoto())) {
            userEntity.setPhoto(updateUserInfoRequest.getPhoto());
        }
        userDAO.save(userEntity);
        // 刷新用户信息缓存
        this.refreshUserDetailCache(userEntity);
        return true;
    }

    public UserBaseResponseInfoVO getUserBaseInfoByUserId(String userId) {
        if (StringUtils.isBlank(userId)) {
            return null;
        }
        return getUserBaseInfoByUserIdFromCache(userId);
    }

    private UserBaseResponseInfoVO getUserBaseInfoByUserIdFromCache(String userId) {
        if (userId == null) {
            return null;
        }
        UserEntity entity = this.refreshAndGetUserEntityFromCache(userId);
        UserBaseResponseInfoVO userBaseResponseInfoVO = UserEntryConvert.convertBaseVo(entity);
        if (userBaseResponseInfoVO == null) {
            return null;
        }
        return userBaseResponseInfoVO;
    }

    /**
     * 强制刷新用户信息缓存
     * @param userId
     */
    private void refreshUserDetailCache(String userId) {
        this.refreshAndGetUserEntityFromCache(userId, true);
    }

    private UserEntity refreshAndGetUserEntityFromCache(String userId, boolean ... refreshCache) {
        String key = RedisKeyEnum.USER_INFO_CACHE.getKey(userId);
        String val = redisService.get(key);
        boolean refresh = refreshCache != null && refreshCache.length > 0 && refreshCache[0];
        if (!refresh && StringUtils.isNotBlank(val)) {
            return JsonUtil.fromJson(val, UserEntity.class);
        }
        UserEntity userEntity = userDAO.findByUserId(userId);
        if (userEntity != null) {
            this.refreshUserDetailCache(userEntity);
        }
        return userEntity;
    }

    /**
     * 刷新用户详情redis缓存
     *
     * @param userEntity
     */
    private void refreshUserDetailCache(UserEntity userEntity) {
        if (userEntity == null) {
            return;
        }
        String key = RedisKeyEnum.USER_INFO_CACHE.getKey(userEntity.getUserId());
        redisService.set(key, JsonUtil.toJsonString(userEntity),  RedisKeyEnum.USER_INFO_CACHE.getExpireTime());
    }

    /***
     * 取当前用户ID，且未登录时直接抛出未登录异常
     * @return
     */
    public String getLoginCurrentUserIdOrElseThrowUnLoginExp() {
        String userId = getLoginCurrentUserId();
        if (StringUtils.isNotBlank(userId)) {
            return userId;
        }
        throw new BusinessException(APIErrorCommonEnum.USER_UN_LOGIN);
    }

    /***
     * 更新用户角色
     * @param userId
     * @param roleCode
     */
    public void updateUserRole(String userId, Integer roleCode) {
        UserEntity userEntity = userDAO.findByUserId(userId);
        Assert.isTrue(userEntity != null, "更新失败，用户不存在!");
        userEntity.setRoleCode(roleCode);
        userDAO.save(userEntity);
        /***
         * 刷新用户信息缓存
         */
        this.refreshUserDetailCache(userId);
    }

    /**
     * 获取当前登录的用户ID
     * @return
     */
    public String getLoginCurrentUserId() {
        return SessionHelper.getCurrentUserId();
    }

    private String md5Pwd(String password) {
        return MD5Utils.md5(password.concat(WebConstant.MD5_SALT));
    }

    /**
     * 创建用户登录会话数据
     * @param userId
     */
    private void createLoginSession(String userId) {
        String sessionId = MD5Utils.md5(userId);
        // sessionId：UserId缓存，用的String数据结构存储，有效期3天
        String sessionKey = RedisKeyEnum.USER_SESSION_PREFIX.getKey(sessionId);
        redisService.set(sessionKey, userId, RedisKeyEnum.USER_SESSION_PREFIX.getExpireTime());
        // 种浏览器Cookie
        Cookie cookie = new Cookie(CookieConstants.C_U_USER_COOKIE_KEY, sessionId);
        cookie.setPath("/");
        cookie.setMaxAge(CookieConstants.COOKIE_OUT_TIME);
        response.addCookie(cookie);
    }

    public String getUserIdBySessionId(String sessionId) {
        String sessionKey = RedisKeyEnum.USER_SESSION_PREFIX.getKey(sessionId);
        return redisService.get(sessionKey);
    }

    /**
     * 批量查询用户缓存
     *
     * @param userIdList
     * @return
     */
    public Map<String, UserBaseResponseInfoVO> batchGetUserInfoFromCache(List<String> userIdList) {
        Map<String, UserBaseResponseInfoVO> userBaseResponseInfoVOMap = new HashMap<>();
        if (CollectionUtils.isEmpty(userIdList)) {
            return userBaseResponseInfoVOMap;
        }
        List<String> cacheKeys = userIdList.stream().map(k ->
                RedisKeyEnum.USER_INFO_CACHE.getKey(String.valueOf(k))).collect(Collectors.toList());
        Map<String, String> multiResultMap = redisService.mgetAndParseMap(cacheKeys);
        for (int i = 0; i < userIdList.size(); i++) {
            String userId = userIdList.get(i);
            String cacheKey = cacheKeys.get(i);
            String cache = multiResultMap.get(cacheKey);
            UserBaseResponseInfoVO userBaseResponseInfoVO;
            if (StringUtils.isNotBlank(cache)) {
                userBaseResponseInfoVO = JsonUtil.fromJson(cache, UserBaseResponseInfoVO.class);
            } else {
                userBaseResponseInfoVO = getUserBaseInfoByUserId(userId);
            }
            userBaseResponseInfoVOMap.put(userId, userBaseResponseInfoVO);
        }
        return userBaseResponseInfoVOMap;
    }

    public List<UserBaseResponseInfoVO> batchGetUserListInfoFromCache(List<String> userIdList) {
        if (CollectionUtils.isEmpty(userIdList)) {
            return Collections.emptyList();
        }
        List<String> cacheKeys = userIdList.stream().map(k ->
                RedisKeyEnum.USER_INFO_CACHE.getKey(String.valueOf(k))).collect(Collectors.toList());
        Map<String, String> multiResultMap = redisService.mgetAndParseMap(cacheKeys);
        List<UserBaseResponseInfoVO> userBaseResponseInfoVOList = new ArrayList<>();
        for (int i = 0; i < userIdList.size(); i++) {
            String userId = userIdList.get(i);
            String cacheKey = cacheKeys.get(i);
            String cache = multiResultMap.get(cacheKey);
            UserBaseResponseInfoVO userBaseResponseInfoVO;
            if (StringUtils.isNotBlank(cache)) {
                userBaseResponseInfoVO = JsonUtil.fromJson(cache, UserBaseResponseInfoVO.class);
            } else {
                userBaseResponseInfoVO = getUserBaseInfoByUserId(userId);
            }
            userBaseResponseInfoVOList.add(userBaseResponseInfoVO);
        }
        return userBaseResponseInfoVOList;
    }

    /**
     * 创建系统账号
     * @return
     */
    public UserBaseResponseInfoVO getSystemUserInfo() {
        UserBaseResponseInfoVO userBaseResponseInfoVO = new UserBaseResponseInfoVO();
        userBaseResponseInfoVO.setUserId(WebConstant.SYSTEM_USER_ID);
        userBaseResponseInfoVO.setUserName("系统");
        userBaseResponseInfoVO.setPhoto("");
        return userBaseResponseInfoVO;
    }

    public String getUserLoginCookie(String userId) {
        String sessionId = MD5Utils.md5(userId);
        return CookieConstants.C_U_USER_COOKIE_KEY.concat("=").concat(sessionId);
    }
}
