package ink.wgink.service.user.service.impl;

import com.alibaba.excel.EasyExcel;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.exceptions.FileException;
import ink.wgink.exceptions.ParamsException;
import ink.wgink.exceptions.SearchException;
import ink.wgink.exceptions.UpdateException;
import ink.wgink.exceptions.base.SystemException;
import ink.wgink.interfaces.app.IAppSignBaseService;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.interfaces.manager.ISystemConfigManager;
import ink.wgink.interfaces.user.IUserSaveAfterHandler;
import ink.wgink.interfaces.user.IUserUpdateAfterHandler;
import ink.wgink.interfaces.user.mongo.IMongoLoginUserService;
import ink.wgink.interfaces.user.wechat.miniapp.IMiniappUserBaseService;
import ink.wgink.interfaces.user.wechat.official.account.IOfficialAccountBaseService;
import ink.wgink.module.file.excel.error.AbstractErrorExcelHandler;
import ink.wgink.module.file.service.IFileService;
import ink.wgink.pojo.ListPage;
import ink.wgink.pojo.app.AppTokenUser;
import ink.wgink.pojo.dtos.user.UserDTO;
import ink.wgink.pojo.result.SuccessResultData;
import ink.wgink.pojo.result.SuccessResultList;
import ink.wgink.pojo.result.UploadExcelResultDTO;
import ink.wgink.pojo.vos.UpdatePasswordVO;
import ink.wgink.service.user.dao.IUserDao;
import ink.wgink.service.user.enums.UserStateEnum;
import ink.wgink.service.user.enums.UserTypeEnum;
import ink.wgink.service.user.enums.UserUpdateTypeEnum;
import ink.wgink.service.user.excel.UserExcel;
import ink.wgink.service.user.excel.UserExcelError;
import ink.wgink.service.user.excel.UserExcelListener;
import ink.wgink.service.user.pojo.bos.UserAdjustmentBO;
import ink.wgink.service.user.pojo.dtos.AppUserDTO;
import ink.wgink.service.user.pojo.pos.UserPO;
import ink.wgink.service.user.pojo.vos.*;
import ink.wgink.service.user.service.IUserAdjustmentService;
import ink.wgink.service.user.service.IUserService;
import ink.wgink.util.ArrayListUtil;
import ink.wgink.util.ReflectUtil;
import ink.wgink.util.ResourceUtil;
import ink.wgink.util.UUIDUtil;
import ink.wgink.util.date.DateUtil;
import ink.wgink.util.map.HashMapUtil;
import ink.wgink.util.thread.CachedThreadPoolUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.*;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: UserServiceImpl
 * @Description: 用户
 * @Author: WangGeng
 * @Date: 2021/1/24 20:25
 * @Version: 1.0
 **/
@Service
public class UserServiceImpl extends DefaultBaseService implements IUserService {

    @Autowired
    private IUserDao userDao;
    @Autowired
    private IUserAdjustmentService userAdjustmentService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Value("${user.default-password:" + ISystemConstant.DEFAULT_PASSWORD + "}")
    private String defaultPassword;
    @Autowired
    private IFileService fileService;
    @Autowired(required = false)
    private IAppSignBaseService appSignBaseService;
    @Autowired(required = false)
    private IMiniappUserBaseService miniappUserBaseService;
    @Autowired(required = false)
    private IOfficialAccountBaseService officialAccountBaseService;
    @Autowired(required = false)
    private IUserSaveAfterHandler userSaveAfterHandler;
    @Autowired(required = false)
    private IUserUpdateAfterHandler userUpdateAfterHandler;
    @Autowired(required = false)
    private IMongoLoginUserService mongoLoginUserService;

    @Override
    public void save(UserVO userVO) {
        saveAndReturnId(userVO, false);
    }

    @Override
    public void register(UserVO userVO) {
        saveAndReturnId(userVO, true);
    }

    /**
     * 保存用户
     *
     * @param userVO
     * @param isRegister 是否注册
     */
    @Override
    public String saveAndReturnId(UserVO userVO, boolean isRegister) {
        UserDTO userDTO = getByUsername(userVO.getUserUsername());
        if (userDTO != null) {
            throw new SearchException("用户已经存在");
        }
        String password;
        if (StringUtils.isBlank(userVO.getUserPassword())) {
            password = defaultPassword;
        } else {
            password = userVO.getUserPassword();
        }
        userVO.setUserPassword(passwordEncoder.encode(DigestUtils.md5Hex(DigestUtils.md5Hex(DigestUtils.md5Hex(password)))));
        String userId = UUIDUtil.getUUID();
        Map<String, Object> params = HashMapUtil.beanToMap(userVO);
        params.put("userId", userId);
        if (isRegister) {
            setSaveInfoByUserId(params, userId);
        } else {
            setSaveInfo(params);
        }
        userDao.save(params);

        updateMongoLoginUser(userId);
        if (userSaveAfterHandler != null) {
            userSaveAfterHandler.handle(userId, userVO.getUserUsername(), userVO.getUserName());
        }
        return userId;
    }

    @Override
    public void remove(List<String> ids) {
        Map<String, Object> params = getHashMap(2);
        params.put("userIds", ids);
        setUpdateInfo(params);
        userDao.remove(params);
        // 删除关联用户
        deleteRelationUser(ids);
        updateMongoLoginUser(ids);
    }

    @Override
    public void delete(List<String> ids) {
        Map<String, Object> params = getHashMap(2);
        params.put("userIds", ids);
        userDao.delete(params);
        // 删除关联用户
        deleteRelationUser(ids);
        updateMongoLoginUser(ids);
    }

    @Override
    public void deleteByToken(String token) {
        String userId = getAppTokenUser(token).getId();
        delete(Arrays.asList(userId));
    }

    @Override
    public void update(String userId, UserVO userVO) {
        if (!StringUtils.isBlank(userVO.getUserPassword())) {
            userVO.setUserPassword(passwordEncoder.encode(DigestUtils.md5Hex(DigestUtils.md5Hex(DigestUtils.md5Hex(userVO.getUserPassword())))));
        }
        Map<String, Object> params = HashMapUtil.beanToMap(userVO);
        setUpdateInfo(params);
        params.put("userId", userId);
        userDao.update(params);
        updateMongoLoginUser(userId);
        if (userUpdateAfterHandler != null) {
            userUpdateAfterHandler.handle(userId);
        }
    }

    @Override
    public String updateInfo(String token, UpdateUserVO updateUserVO) throws Exception {
        if (appSignBaseService == null) {
            throw new SystemException("未引入APP登录模块");
        }
        String userId = securityComponent.getAppTokenUser(token).getId();
        Map<String, Object> params = getHashMap(8);
        params.put("userAvatar", updateUserVO.getAvatar());
        params.put("userEmail", updateUserVO.getEmail());
        params.put("userPhone", updateUserVO.getPhone());
        params.put("userName", updateUserVO.getName());
        params.put("userId", userId);
        setAppUpdateInfo(token, params);
        userDao.update(params);
        updateMongoLoginUser(userId);
        if (userUpdateAfterHandler != null) {
            userUpdateAfterHandler.handle(userId);
        }
        return appSignBaseService.userIdSign(userId);
    }

    @Override
    public void resetPassword(String userId, RestPasswordVO restPasswordVO) {
        UserDTO userDTO = get(userId);
        if (userDTO == null) {
            throw new SearchException("修改用户不存在");
        }
        Map<String, Object> params = getHashMap(4);
        params.put("userId", userId);
        params.put("userPassword", passwordEncoder.encode(DigestUtils.md5Hex(DigestUtils.md5Hex(DigestUtils.md5Hex(defaultPassword)))));
        userDao.updatePassword(params);

        updateMongoLoginUser(userId);

        // 记录日志
        UserAdjustmentBO userAdjustmentBO = new UserAdjustmentBO();
        userAdjustmentBO.setUserId(userId);
        userAdjustmentBO.setUserName(userDTO.getUserName());
        userAdjustmentBO.setUpdateType(UserUpdateTypeEnum.REST_PASSWORD.getValue());
        userAdjustmentBO.setCreator(securityComponent.getCurrentUser().getUserId());
        userAdjustmentBO.setCreatorName(securityComponent.getCurrentUsername());
        userAdjustmentBO.setNewValue(defaultPassword);
        userAdjustmentBO.setGmtCreate(DateUtil.getTime());
        userAdjustmentBO.setUpdateReason(restPasswordVO.getUpdateReason());
        userAdjustmentService.save(userAdjustmentBO);
    }

    @Override
    public void updateUsername(String userId, UpdateUsernameVO updateUsernameVO) {
        updateUsername(userId, updateUsernameVO, true);
    }

    @Override
    public void updateUsername(String userId, UpdateUsernameVO updateUsernameVO, boolean updateAdjustment) {
        UserDTO oldUserDTO = get(userId);
        if (oldUserDTO == null) {
            throw new SearchException("用户不存在");
        }
        Map<String, Object> params = getHashMap(2);
        params.put("userUsername", updateUsernameVO.getUsername());
        UserDTO userDTO = userDao.get(params);
        if (userDTO != null && !StringUtils.equals(userId, userDTO.getUserId())) {
            throw new SearchException("用户名已经存在");
        }
        params.put("userId", userId);
        userDao.updateUsername(params);

        updateMongoLoginUser(userId);

        if (updateAdjustment) {
            updateUsernameAdjustment(userId, oldUserDTO.getUserUsername(), updateUsernameVO);
        }
        if (userUpdateAfterHandler != null) {
            userUpdateAfterHandler.handle(userId);
        }
    }

    @Override
    public void updatePassword(UpdatePasswordVO updatePasswordVO) {
        updatePasswordByUserId(securityComponent.getCurrentUser().getUserId(), updatePasswordVO);
    }

    @Override
    public void updatePassword(String token, UpdatePasswordVO updatePasswordVO) throws ReflectUtil.ReflectException {
        AppTokenUser appTokenUser = securityComponent.getAppTokenUser(token);
        updatePasswordByUserId(appTokenUser.getId(), updatePasswordVO, true);
    }

    @Override
    public void updatePasswordByUserId(String userId, UpdatePasswordVO updatePasswordVO) {
        updatePasswordByUserId(userId, updatePasswordVO, false);
    }

    @Override
    public void updatePasswordByUserId(String userId, UpdatePasswordVO updatePasswordVO, boolean isPasswordMd5) {
        String oldPassword;
        String newPassword;
        if (isPasswordMd5) {
            oldPassword = updatePasswordVO.getOldPassword();
            newPassword = updatePasswordVO.getNewPassword();
        } else {
            oldPassword = DigestUtils.md5Hex(DigestUtils.md5Hex(DigestUtils.md5Hex(updatePasswordVO.getOldPassword())));
            newPassword = DigestUtils.md5Hex(DigestUtils.md5Hex(DigestUtils.md5Hex(updatePasswordVO.getNewPassword())));
        }
        UserPO userPO = getPO(userId);
        if (!passwordEncoder.matches(oldPassword, userPO.getUserPassword())) {
            throw new UpdateException("旧密码错误");
        }
        updatePasswordByUserPOAndNewPassword(userPO, newPassword);
    }

    @Override
    public void updatePasswordByUsername(String username, String newPassword) {
        UserPO userPO = getPOByUsername(username);
        if (userPO == null) {
            throw new SearchException("用户不存在");
        }
        updatePasswordByUserPOAndNewPassword(userPO, newPassword);
    }

    /**
     * 修改密码
     *
     * @param userPO
     * @param newPassword
     */
    private void updatePasswordByUserPOAndNewPassword(UserPO userPO, String newPassword) {
        Map<String, Object> params = getHashMap(4);
        params.put("userPassword", passwordEncoder.encode(newPassword));
        params.put("gmtPasswordModified", DateUtil.getTime());
        params.put("userId", userPO.getUserId());
        userDao.updatePassword(params);

        updateMongoLoginUser(userPO.getUserId());

        // 日志
        UserAdjustmentBO userAdjustmentBO = new UserAdjustmentBO();
        userAdjustmentBO.setUserId(userPO.getUserId());
        userAdjustmentBO.setUserName(userPO.getUserName());
        userAdjustmentBO.setUpdateType(UserUpdateTypeEnum.PASSWORD.getValue());
        userAdjustmentBO.setUpdateReason("修改密码");
        userAdjustmentBO.setCreator(userPO.getUserId());
        userAdjustmentBO.setCreatorName(userPO.getUserName());
        userAdjustmentBO.setGmtCreate(DateUtil.getTime());
        userAdjustmentService.save(userAdjustmentBO);
    }

    @Override
    public void updateExpiredDate(String userId, UpdateExpiredDateVO updateExpiredDateVO) {
        UserDTO oldUserDTO = get(userId);
        if (oldUserDTO == null) {
            throw new SearchException("用户不存在");
        }
        Map<String, Object> params = new HashMap<>(4);
        params.put("userId", userId);
        params.put("userExpiredDate", updateExpiredDateVO.getExpiredDate());
        userDao.updateExpiredDate(params);

        updateMongoLoginUser(userId);
    }

    @Override
    public void updateUserStatePass(String userId) {
        Map<String, Object> params = getHashMap(4);
        params.put("userId", userId);
        params.put("userState", UserStateEnum.NORMAL.getValue());
        setUpdateInfo(params);
        userDao.updateUserState(params);

        updateMongoLoginUser(userId);
    }

    @Override
    public void updateUserStatePass(List<String> userIds) {
        Map<String, Object> params = getHashMap(4);
        params.put("userIds", userIds);
        params.put("userState", UserStateEnum.NORMAL.getValue());
        setUpdateInfo(params);
        userDao.updateUserState(params);

        updateMongoLoginUser(userIds);
    }

    @Override
    public void updateUserStateUnPass(String userId) {
        Map<String, Object> params = getHashMap(4);
        params.put("userId", userId);
        params.put("userState", UserStateEnum.UN_PASS.getValue());
        setUpdateInfo(params);
        userDao.updateUserState(params);

        updateMongoLoginUser(userId);
    }

    @Override
    public void updateUserStateUnPass(List<String> userIds) {
        Map<String, Object> params = getHashMap(4);
        params.put("userId", userIds);
        params.put("userState", UserStateEnum.UN_PASS.getValue());
        setUpdateInfo(params);
        userDao.updateUserState(params);

        updateMongoLoginUser(userIds);
    }

    @Override
    public UploadExcelResultDTO importExcel(MultipartFile excel) throws IOException {
        Map<String, Object> params = getHashMap(16);
        // 错误列表
        List<UserExcelError> userExcelErrors = new ArrayList<>();
        long startTime = System.currentTimeMillis();
        LOG.debug("读取Excel");
        EasyExcel.read(excel.getInputStream(), UserExcel.class, new UserExcelListener() {
            @Override
            public void listUserExcel(List<UserExcel> userExcels) throws Exception {
                for (UserExcel userExcel : userExcels) {
                    // 判断昵称存在
                    String userUsername = userExcel.getUserUsername();
                    String userName = userExcel.getUserName();
                    if (StringUtils.isBlank(userUsername) || StringUtils.isBlank(userName)) {
                        userExcelErrors.add(getUserExcelError(userExcel, "必填值存在空值，导入失败"));
                        continue;
                    }
                    String userPhone = userExcel.getUserPhone();
                    String userEmail = userExcel.getUserEmail();
                    try {
                        // 保存用户
                        UserVO userVO = new UserVO();
                        userVO.setUserUsername(userUsername);
                        userVO.setUserName(userName);
                        userVO.setUserPassword(defaultPassword);
                        userVO.setUserPhone(userPhone);
                        userVO.setUserEmail(userEmail);
                        userVO.setUserType(2);
                        userVO.setUserState(0);
                        saveAndReturnId(userVO, false);
                    } catch (Exception e) {
                        userExcelErrors.add(getUserExcelError(userExcel, e.getMessage()));
                    }
                }
            }
        }).headRowNumber(2).sheet().doRead();
        long endTime = System.currentTimeMillis();
        String excelFileId = null;
        if (userExcelErrors.size() > 0) {
            excelFileId = new AbstractErrorExcelHandler<UserExcelError>(fileService) {
                @Override
                public List<List<String>> excelHeaderNames() {
                    return simpleExcelHeader(new String[]{"用户名", "昵称", "手机", "邮箱", "错误原因"});
                }
            }.saveErrorExcel(userExcelErrors);
        }
        return new UploadExcelResultDTO(userExcelErrors.size(), endTime - startTime, excelFileId);
    }

    @Override
    public UserPO getPO(String userId) {
        Map<String, Object> params = getHashMap(2);
        params.put("userId", userId);
        return userDao.getPO(params);
    }

    @Override
    public UserPO getPOByUsername(String username) {
        Map<String, Object> params = getHashMap(2);
        params.put("userUsername", username);
        return userDao.getPO(params);
    }

    @Override
    public UserPO getPOByPhone(String phone) {
        Map<String, Object> params = getHashMap(2);
        params.put("userPhone", phone);
        return userDao.getPO(params);
    }

    @Override
    public List<UserPO> listPO(Map<String, Object> params) {
        params = params == null ? getHashMap(0) : params;
        return userDao.listPO(params);
    }

    @Override
    public List<UserPO> listPOByUserIds(List<String> userIds) {
        if (userIds == null || userIds.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Object> params = getHashMap(2);
        params.put("userIds", userIds);
        return listPO(params);
    }

    @Override
    public List<UserPO> listPOByUserState(UserStateEnum userState) {
        Map<String, Object> params = getHashMap(2);
        params.put("userState", userState.getValue());
        return listPO(params);
    }

    @Override
    public List<UserPO> listPOByUserType(UserTypeEnum userType) {
        Map<String, Object> params = getHashMap(2);
        params.put("userType", userType.getValue());
        return listPO(params);
    }

    @Override
    public List<UserPO> listPOByUserStateAndUserType(UserStateEnum userState, UserTypeEnum userType) {
        Map<String, Object> params = getHashMap(4);
        params.put("userState", userState.getValue());
        params.put("userType", userType.getValue());
        return listPO(params);
    }

    @Override
    public void updateLoginInfo(Map<String, Object> params) throws UpdateException {
        userDao.updateLoginInfo(params);
    }

    @Override
    public String saveDefaultUserAndReturnId(String userUsername, String username, Integer userState, Integer userType) {
        if (StringUtils.isBlank(userUsername)) {
            throw new ParamsException("用户名不能为空");
        }
        if (StringUtils.isBlank(username)) {
            throw new ParamsException("昵称不能为空");
        }
        UserVO userVO = new UserVO();
        userVO.setUserUsername(userUsername);
        userVO.setUserName(username);
        userVO.setUserState(userState == null ? 0 : userState);
        userVO.setUserType(userType == null ? 3 : userType);
        userVO.setUserPassword(defaultPassword);
        return saveAndReturnId(userVO, true);
    }

    @Override
    public UserDTO get(String userId) {
        Map<String, Object> params = getHashMap(2);
        params.put("userId", userId);
        return userDao.get(params);
    }

    @Override
    public UserDTO getByUsername(String username) {
        Map<String, Object> params = getHashMap(2);
        params.put("userUsername", username);
        return userDao.get(params);
    }

    @Override
    public List<UserDTO> listByUserIds(List<String> userIds) {
        Map<String, Object> params = getHashMap(2);
        params.put("userIds", userIds);
        return list(params);
    }

    @Override
    public List<UserDTO> listByUsernames(List<String> usernames) {
        Map<String, Object> params = getHashMap(2);
        params.put("userUsernames", usernames);
        return list(params);
    }

    @Override
    public List<UserDTO> listByUserState(Integer userState) {
        Map<String, Object> params = getHashMap(2);
        params.put("userState", userState);
        return list(params);
    }

    @Override
    public List<UserDTO> list(Map<String, Object> params) {
        return ArrayListUtil.deepClone(userDao.list(params), UserDTO.class);
    }

    @Override
    public SuccessResultList<List<UserDTO>> listPage(ListPage page) {
        PageHelper.startPage(page.getPage(), page.getRows());
        List<UserDTO> userDTOs = list(page.getParams());
        PageInfo<UserDTO> pageInfo = new PageInfo<>(userDTOs);
        return new SuccessResultList<>(userDTOs, pageInfo.getPageNum(), pageInfo.getTotal());
    }

    @Override
    public SuccessResultList<List<UserDTO>> listPageByIds(List<String> userIds, ListPage page) {
        page.getParams().put("userIds", userIds);
        return listPage(page);
    }

    @Override
    public SuccessResultList<List<UserDTO>> listPageByUserState(Integer userState, ListPage page) {
        page.getParams().put("userState", userState);
        return listPage(page);
    }

    @Override
    public List<UserDTO> listByIds(List<String> userIds, Map<String, Object> params) {
        params.put("userIds", userIds);
        return list(params);
    }

    @Override
    public SuccessResultList<List<UserDTO>> listPageByExcludeIds(List<String> excludeUserIds, ListPage page) {
        page.getParams().put("excludeUserIds", excludeUserIds);
        return listPage(page);
    }

    @Override
    public SuccessResultList<List<UserDTO>> listPageByExcludeIdsAndIncludeIds(List<String> excludeUserIds, List<String> includeUserIds, ListPage page) {
        page.getParams().put("excludeUserIds", excludeUserIds);
        page.getParams().put("userIds", includeUserIds);
        return listPage(page);
    }

    @Override
    public List<UserDTO> listByExcludeIds(List<String> excludeUserIds, Map<String, Object> params) {
        if (params == null) {
            params = getHashMap(2);
        }
        params.put("excludeUserIds", excludeUserIds);
        return list(params);
    }

    @Override
    public List<UserDTO> listByExcludeIds(List<String> excludeUserIds, List<String> includeUserIds, Map<String, Object> params) {
        if (params == null) {
            params = getHashMap(2);
        }
        params.put("excludeUserIds", excludeUserIds);
        params.put("userIds", includeUserIds);
        return list(params);
    }

    @Override
    public Integer count(Map<String, Object> params) {
        Integer count = userDao.count(params);
        return count == null ? 0 : count;
    }

    @Override
    public AppUserDTO getAppUser(String token) throws ReflectUtil.ReflectException {
        String userId = securityComponent.getAppTokenUser(token).getId();
        UserPO userPO = getPO(userId);
        if (userPO == null) {
            throw new SearchException("用户不存在");
        }
        AppUserDTO appUserDTO = new AppUserDTO();
        appUserDTO.setUserId(userPO.getUserId());
        appUserDTO.setAvatar(userPO.getUserAvatar());
        appUserDTO.setUsername(userPO.getUserUsername());
        appUserDTO.setName(userPO.getUserName());
        appUserDTO.setEmail(userPO.getUserEmail());
        appUserDTO.setPhone(userPO.getUserPhone());
        return appUserDTO;
    }

    @Override
    public void downLoadAvatar(String userId, HttpServletRequest request, HttpServletResponse response) {
        UserDTO userDTO = get(userId);
        if (userDTO == null) {
            throw new SearchException("用户不存在");
        }
        // 头像不存在，加载默认头像
        if (StringUtils.isBlank(userDTO.getUserAvatar())) {
            downloadDefaultAvatar(response);
            return;
        }
        Map<String, Object> params = getHashMap(4);
        params.put("fileId", userDTO.getUserAvatar());
        params.put("isOpen", ISystemConstant.IS_TRUE);
        fileService.downLoadFile(request, response, params);
    }

    @Override
    public void isExpiredByToken(String token) {
        AppTokenUser appTokenUser = getAppTokenUser(token);
        UserPO userPO = getPO(appTokenUser.getId());
        if (userPO == null) {
            throw new SearchException("用户不存在");
        }
        if (DateUtil.isDateExpired(userPO.getUserExpiredDate())) {
            throw new SearchException("账号已经过期");
        }
    }

    @Override
    public int countDateRange(String startDate, String endDate) {
        Map<String, Object> params = getHashMap(4);
        params.put("startDay", startDate);
        params.put("endDay", endDate);
        return count(params);
    }

    @Override
    public int count() {
        Map<String, Object> params = getHashMap(0);
        return count(params);
    }

    @Override
    public int countType(int userType) {
        Map<String, Object> params = getHashMap(2);
        params.put("userType", userType);
        return count(params);
    }

    @Override
    public int countErrorType() {
        Map<String, Object> params = getHashMap(2);
        params.put("errorLoginType", "errorLoginType");
        return count(params);
    }

    @Override
    public Integer countState(int userState) {
        Map<String, Object> params = getHashMap(2);
        params.put("userState", userState);
        return count(params);
    }

    @Override
    public SuccessResultData<String> getPasswordStatus(String userId) {
        ISystemConfigManager systemConfigManager;
        try {
            systemConfigManager = ReflectUtil.getSingleInstance("ink.wgink.login.base.manager.ConfigManager", ISystemConfigManager.class);
        } catch (ReflectUtil.ReflectException e) {
            LOG.error(e.getMessage(), e);
            throw new SystemException(e.getMessage());
        }
        if (systemConfigManager == null) {
            return new SuccessResultData<>(PASSWORD_OK);
        }
        Map<String, String> config = systemConfigManager.getConfig();
        String passwordValidity = PASSWORD_VALIDITY_CUSTOM;
        if (!StringUtils.isBlank(config.get(PASSWORD_VALIDITY))) {
            passwordValidity = config.get(PASSWORD_VALIDITY);
        }
        // 密码永不过期
        if (StringUtils.equals(PASSWORD_VALIDITY_NONE, passwordValidity)) {
            return new SuccessResultData<>(PASSWORD_OK);
        }
        String firstLoginChangePassword = FIRST_LOGIN_CHANGE_PASSWORD_CLOSE;
        if (!StringUtils.isBlank(config.get(FIRST_LOGIN_CHANGE_PASSWORD))) {
            firstLoginChangePassword = config.get(FIRST_LOGIN_CHANGE_PASSWORD);
        }
        UserPO userPO = getPO(securityComponent.getCurrentUser().getUserId());
        String gmtCreate = userPO.getGmtCreate();
        String gmtPasswordModified = userPO.getGmtPasswordModified();
        if (StringUtils.equals(FIRST_LOGIN_CHANGE_PASSWORD_OPEN, firstLoginChangePassword) && (StringUtils.isBlank(gmtPasswordModified) || StringUtils.equals(gmtCreate.substring(0, 10), gmtPasswordModified.substring(0, 10)))) {
            return new SuccessResultData<>(PASSWORD_CHANGE);
        }
        DateTime gmtPasswordModifiedDateTime = null;
        if (!StringUtils.isBlank(gmtPasswordModified)) {
            gmtPasswordModifiedDateTime = DateTime.parse(gmtPasswordModified, DateTimeFormat.forPattern(ISystemConstant.DATE_FORMATTER_YYYY_MM_DD_HH_MM_SS));
        }
        // 密码有效时间
        int passwordValidityDays = 90;
        if (StringUtils.isBlank(config.get(PASSWORD_VALIDITY_DAYS))) {
            passwordValidityDays = Integer.parseInt(config.get(PASSWORD_VALIDITY_DAYS));
        }
        if (gmtPasswordModifiedDateTime == null) {
            return new SuccessResultData<>(PASSWORD_CHANGE);
        }
        DateTime nowDate = DateTime.now();
        // 到期时间
        DateTime expireGmtPasswordModifiedDateTime = gmtPasswordModifiedDateTime.plusDays(passwordValidityDays);
        if (expireGmtPasswordModifiedDateTime.compareTo(nowDate) <= 0) {
            return new SuccessResultData<>(PASSWORD_CHANGE);
        }
        // 提醒修改密码时间
        int changePasswordNoticeDays = 14;
        if (!StringUtils.isBlank(config.get(CHANGE_PASSWORD_NOTICE_DAYS))) {
            changePasswordNoticeDays = Integer.parseInt(config.get(CHANGE_PASSWORD_NOTICE_DAYS));
        }
        if (changePasswordNoticeDays >= passwordValidityDays) {
            return new SuccessResultData<>(PASSWORD_OK);
        }
        DateTime noticeDateTime = expireGmtPasswordModifiedDateTime.minusDays(changePasswordNoticeDays);
        if (noticeDateTime.compareTo(nowDate) <= 0) {
            return new SuccessResultData<>(PASSWORD_REMIND);
        }
        return new SuccessResultData<>(PASSWORD_OK);
    }

    @Override
    public List<UserDTO> listByKeywords(String keywords) {
        Map<String, Object> params = getHashMap(2);
        params.put("keywords", keywords);
        return list(params);
    }

    @Override
    public List<String> listUserIds(List<UserDTO> userDTOs) {
        if (userDTOs.isEmpty()) {
            return new ArrayList<>();
        }
        Set<String> userIdSet = new HashSet<>();
        for (UserDTO userDTO : userDTOs) {
            userIdSet.add(userDTO.getUserId());
        }
        return new ArrayList<>(userIdSet);
    }

    @Override
    public List<UserDTO> listByUserPhones(List<String> userPhones) {
        if (userPhones.isEmpty()) {
            return new ArrayList<>();
        }
        Map<String, Object> params = getHashMap(2);
        params.put("userPhones", userPhones);
        return userDao.list(params);
    }

    /**
     * 更新mongo
     *
     * @param userId
     */
    private void updateMongoLoginUser(String userId) {
        if (mongoLoginUserService != null) {
            CachedThreadPoolUtil.execute(() -> {
                LOG.debug("update mongo login user");
                mongoLoginUserService.updateByUserId(userId);
            });
        }
    }

    /**
     * 更新mongo
     *
     * @param userIds
     */
    private void updateMongoLoginUser(List<String> userIds) {
        if (mongoLoginUserService != null) {
            CachedThreadPoolUtil.execute(() -> {
                LOG.debug("update mongo login user");
                mongoLoginUserService.updateByUserIds(userIds);
            });
        }
    }


    /**
     * Excel导入错误对象
     *
     * @param userExcel
     * @param reason
     * @return
     */
    private UserExcelError getUserExcelError(UserExcel userExcel, String reason) {
        UserExcelError userExcelError = new UserExcelError();
        userExcelError.setUserUsername(userExcel.getUserUsername());
        userExcelError.setUserName(userExcel.getUserName());
        userExcelError.setUserPhone(userExcel.getUserPhone());
        userExcelError.setUserEmail(userExcel.getUserEmail());
        userExcelError.setReason(reason);
        return userExcelError;
    }

    /**
     * 更新用户名记录
     *
     * @param userId
     * @param oldUsername
     * @param updateUsernameVO
     */
    private void updateUsernameAdjustment(String userId, String oldUsername, UpdateUsernameVO updateUsernameVO) {
        Map<String, Object> params = getHashMap(1);
        UserDTO updateUserDTO = get(userId);
        if (updateUserDTO == null) {
            throw new SearchException("修改用户不存在");
        }
        UserDTO userDTO = getByUsername(updateUsernameVO.getUsername());
        if (userDTO != null && !StringUtils.equals(userId, userDTO.getUserId())) {
            throw new SearchException("新用户名已经存在");
        }
        params.put("userId", userId);
        params.put("userUsername", updateUsernameVO.getUsername());
        userDao.updateUsername(params);

        // 日志
        UserAdjustmentBO userAdjustmentBO = new UserAdjustmentBO();
        userAdjustmentBO.setUserId(userId);
        userAdjustmentBO.setUserName(updateUserDTO.getUserName());
        userAdjustmentBO.setUpdateType(UserUpdateTypeEnum.USERNAME.getValue());
        userAdjustmentBO.setOldValue(oldUsername);
        userAdjustmentBO.setNewValue(updateUsernameVO.getUsername());
        userAdjustmentBO.setUpdateReason(updateUsernameVO.getUpdateReason());
        userAdjustmentBO.setCreator(securityComponent.getCurrentUser().getUserId());
        userAdjustmentBO.setCreatorName(securityComponent.getCurrentUser().getUserName());
        userAdjustmentBO.setGmtCreate(DateUtil.getTime());
        userAdjustmentService.save(userAdjustmentBO);
    }

    /**
     * 下载默认用户头像
     *
     * @param response
     */
    private void downloadDefaultAvatar(HttpServletResponse response) {
        File file;
        try {
            file = ResourceUtil.getResourceFile("classpath:static/assets/images/profile-photo.jpg");
            response.setHeader("Content-Length", String.valueOf(file.length()));
            response.setHeader("Content-Disposition", "inline;fileName=" + URLEncoder.encode("profile-photo.jpg", "UTF-8"));
            response.setContentType("image/jpeg");
        } catch (IOException e) {
            throw new FileException("默认头像不存在");
        }
        try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file)); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(response.getOutputStream());) {
            int readSize;
            for (byte[] buf = new byte[IFileService.INPUT_STREAM_SIZE]; (readSize = bufferedInputStream.read(buf)) > -1; ) {
                System.out.println(readSize);
                bufferedOutputStream.write(buf, 0, readSize);
            }
            bufferedOutputStream.flush();
        } catch (Exception e) {
            LOG.error("默认头像不存在");
        }
    }

    /**
     * 删除关联用户
     *
     * @param userIds
     */
    private void deleteRelationUser(List<String> userIds) {
        // 小程序关联用户
        if (miniappUserBaseService != null) {
            miniappUserBaseService.delete(userIds);
        }
        // 微信公众号关联用户
        if (officialAccountBaseService != null) {
            officialAccountBaseService.delete(userIds);
        }
    }

}
