package cn.iocoder.yudao.module.system.service.user;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.string.DTO.IdCardDO;
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.module.infra.api.file.FileApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserApiDTO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserPageApiDTO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.controller.admin.user.dto.UserDTO;
import cn.iocoder.yudao.module.system.controller.admin.user.dto.UserPageDTO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.factoryUser.FactoryUserPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.*;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupuser.AttendanceGroupUserMapper;
import cn.iocoder.yudao.module.system.dal.mysql.dept.UserPostMapper;
import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.dept.PostService;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.tenant.TenantService;
import cn.iocoder.yudao.module.system.service.worklog.LogUseService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.annotations.VisibleForTesting;
import com.xingyuv.http.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;

/**
 * 后台用户 Service 实现类
 */
@Service("adminUserService")
@Slf4j
public class AdminUserServiceImpl implements AdminUserService {

    @Value("${sys.user.init-password:123456}")
    private String userInitPassword;

    @Resource
    private AdminUserMapper userMapper;

    @Resource
    private DeptService deptService;
    @Resource
    private PostService postService;
    @Resource
    @Lazy // 延迟，避免循环依赖报错
    private PermissionService permissionService;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    @Lazy // 延迟，避免循环依赖报错
    private TenantService tenantService;

    @Resource
    private UserPostMapper userPostMapper;
    @Resource
    private AttendanceGroupUserMapper attendanceGroupUserMapper;

    @Resource
    private FileApi fileApi;

    @Resource
    private LogUseService logUseService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserOpenId(Long id, String openId) {
        userMapper.updateById(new AdminUserDO().setId(id).setOpenId(openId));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createUser(UserSaveReqVO createReqVO) {
        // 校验账户配合
        tenantService.handleTenantInfo(tenant -> {
            long count = userMapper.selectCount();
            if (count >= tenant.getAccountCount()) {
                throw exception(USER_COUNT_MAX, tenant.getAccountCount());
            }
        });
        // 校验正确性
        validateUserForCreateOrUpdate(null, createReqVO.getUsername(),
                createReqVO.getMobile(), createReqVO.getEmail(), createReqVO.getDeptId(), createReqVO.getPostIds());
        // 插入用户
        AdminUserDO user = BeanUtils.toBean(createReqVO, AdminUserDO.class);
        user.setStatus(createReqVO.getStatus() == null ? CommonStatusEnum.ENABLE.getStatus() : createReqVO.getStatus()); // 默认开启
        user.setPassword(encodePassword(createReqVO.getPassword())); // 加密密码
        userMapper.insert(user);

        // 插入关联岗位
        if (CollectionUtil.isNotEmpty(user.getPostIds())) {
            userPostMapper.insertBatch(convertList(user.getPostIds(),
                    postId -> new UserPostDO().setUserId(user.getId()).setPostId(postId)));
        }

        // 默认赋予用户 普通角色
        permissionService.assignUserRole(user.getId(), Collections.singleton(2L));

        // 判断用户是工厂部门的用户 并且userType != 2时
        if (deptService.getDept(user.getDeptId()).getFactoryId() != null) {
            // 工厂用户添加到GPS定位系统中
            gpsIncrementalSynchronizationOfUsers(user);
        }

        return user.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(UserSaveReqVO updateReqVO) {
        updateReqVO.setPassword(null); // 特殊：此处不更新密码
        // 校验正确性
        validateUserForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getUsername(),
                updateReqVO.getMobile(), updateReqVO.getEmail(), updateReqVO.getDeptId(), updateReqVO.getPostIds());
        // 更新用户
        AdminUserDO updateObj = BeanUtils.toBean(updateReqVO, AdminUserDO.class);
        userMapper.updateById(updateObj);
        // 更新岗位
        updateUserPost(updateReqVO, updateObj);

        // 更新日志使用人信息
        logUseService.updateUseDeptId(updateObj.getId(), updateObj.getDeptId());

    }

    private void updateUserPost(UserSaveReqVO reqVO, AdminUserDO updateObj) {

        Long userId = reqVO.getId();
        Set<Long> dbPostIds = convertSet(userPostMapper.selectListByUserId(userId), UserPostDO::getPostId);
        // 计算新增和删除的岗位编号
        Set<Long> postIds = CollUtil.emptyIfNull(updateObj.getPostIds());
        Collection<Long> createPostIds = CollUtil.subtract(postIds, dbPostIds);
        Collection<Long> deletePostIds = CollUtil.subtract(dbPostIds, postIds);
        // 执行新增和删除。对于已经授权的菜单，不用做任何处理
        if (!CollectionUtil.isEmpty(createPostIds)) {
            userPostMapper.insertBatch(convertList(createPostIds,
                    postId -> new UserPostDO().setUserId(userId).setPostId(postId)));
        }
        if (!CollectionUtil.isEmpty(deletePostIds)) {
            userPostMapper.deleteByUserIdAndPostId(userId, deletePostIds);
        }
    }

    @Override
    public void updateUserLogin(Long id, String loginIp) {
        userMapper.updateById(new AdminUserDO().setId(id).setLoginIp(loginIp).setLoginDate(LocalDateTime.now()));
    }

    @Override
    public void updateUserProfile(Long id, UserProfileUpdateReqVO reqVO) {
        // 校验正确性
        validateUserExists(id);
        validateEmailUnique(id, reqVO.getEmail());
        validateMobileUnique(id, reqVO.getMobile());

        //解析身份证号码
        IdCardDO idCardDO = StrUtils.IdCardAnalysis(reqVO.getIdcard());

        //设置 性别、年龄、出生日期
        AdminUserDO adminUserDO = BeanUtils.toBean(reqVO, AdminUserDO.class).setId(id);
        adminUserDO.setSex(idCardDO.getSex());
        adminUserDO.setAge(idCardDO.getAge());
        adminUserDO.setBirthdayDay(idCardDO.getDate());

        // 执行更新
        userMapper.updateById(adminUserDO);
    }

    @Override
    public void updateUserPassword(Long id, UserProfileUpdatePasswordReqVO reqVO) {
        // 校验旧密码密码
        validateOldPassword(id, reqVO.getOldPassword());
        // 执行更新
        AdminUserDO updateObj = new AdminUserDO().setId(id);
        updateObj.setPassword(encodePassword(reqVO.getNewPassword())); // 加密密码
        userMapper.updateById(updateObj);
    }

    @Override
    public String updateUserAvatar(Long id, String name, InputStream avatarFile) throws IOException {
        //validateUserExists(id);
        if (id == null) {
            return "";
        }
        AdminUserDO user = userMapper.selectById(id);
        if (user == null) {
            throw exception(USER_NOT_EXISTS);
        }

        byte[] content = IoUtil.readBytes(avatarFile);
        String avatar = "";
        if (StringUtil.isEmpty(user.getAvatar())) {
            //没有头像 新增
            // 存储文件
//            BusinessFile file = new BusinessFile().setBusinessType(3L).setContent(content).setName(name);
            avatar = fileApi.createBusinessFile(3L, name, content);
        } else {
            //有头像  修改
            //变更infra_file_content的content字段内容
            avatar = fileApi.updateBusinessFileContent(user.getAvatar(), 3L, name, content);
        }
        user.setAvatar(avatar);
        userMapper.updateById(user);
        return user.getAvatar();
    }

    @Override
    public void updateUserPassword(Long id, String password) {
        // 校验用户存在
        validateUserExists(id);
        // 更新密码
        AdminUserDO updateObj = new AdminUserDO();
        updateObj.setId(id);
        updateObj.setPassword(encodePassword(password)); // 加密密码
        userMapper.updateById(updateObj);
    }

    @Override
    public void updateUserStatus(Long id, Integer status) {
        // 校验用户存在
        validateUserExists(id);
        // 更新状态
        AdminUserDO updateObj = new AdminUserDO();
        updateObj.setId(id);
        updateObj.setStatus(status);
        switch (status) {
            case 0:
                // 开启状态 设置用户编制为在职
                updateObj.setUserStaffing(7);
                break;
            case 1:
                // 关闭状态 设置用户编制为离职
                updateObj.setUserStaffing(8);
                // -- 将当前用户移除所在考情组
                attendanceGroupUserMapper.delete(new LambdaQueryWrapper<AttendanceGroupUserDO>()
                        .eq(AttendanceGroupUserDO::getUserId, id));
                break;
        }
        userMapper.updateById(updateObj);
    }

    @Override
    public void updateFieldwork(Long id, Integer fieldworkFlag) {
        // 更新状态
        AdminUserDO updateObj = new AdminUserDO();
        updateObj.setId(id);
        updateObj.setFieldworkFlag(fieldworkFlag);
        updateObj.setFieldworkType(fieldworkFlag == 1 ? 1 : 0);  //设置为 永久外勤类型
        userMapper.updateById(updateObj);
    }

    @Override
    public void updateUserStaffing(Long id, Integer userStaffing) {

        userMapper.updateById(new AdminUserDO().setId(id).setUserStaffing(userStaffing));
    }

    @Override
    public void updateFieldworkType(Collection<Long> id, Integer fieldworkFlag) {
        // 更新状态
        AdminUserDO updateObj = new AdminUserDO();
        updateObj.setFieldworkFlag(fieldworkFlag);
        updateObj.setFieldworkType(fieldworkFlag == 1 ? 2 : 0);  //设置为 临时外勤类型
        userMapper.update(updateObj, new LambdaQueryWrapperX<AdminUserDO>()
                .in(AdminUserDO::getId, id)
                .ne(AdminUserDO::getFieldworkType, 1));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteUser(Long id) {
        // 校验用户存在
        validateUserExists(id);
        // 删除用户
        userMapper.deleteById(id);
        // 删除用户关联数据
        permissionService.processUserDeleted(id);
        // 删除用户拓展信息

        // 删除用户岗位
        userPostMapper.deleteByUserId(id);
    }

    @Override
    public AdminUserDO getUserByUsername(String username) {
        return userMapper.selectByUsername(username);
    }

    @Override
    public AdminUserDO getUserByMobile(String mobile) {
        return userMapper.selectByMobile(mobile);
    }

    @Override
    public PageResult<AdminUserDO> getUserPage(UserPageReqVO reqVO) {
        return userMapper.selectPage(reqVO, getDeptCondition(reqVO.getDeptId()));
    }

    @Override
    public PageResult<AdminUserDO> getUserBringDeptPage(UserPageReqVO reqVO) {
        List<Long> deptIds = new ArrayList<>(getDeptCondition(reqVO.getDeptId()));
        reqVO.setDeptIds(deptIds);
        IPage<AdminUserDO> pageResult = userMapper.getUserBringDeptPage(MyBatisUtils.buildPage(reqVO), reqVO);
        return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
    }

    @Override
    public void gpsFullUserUpdate() {
        // 查询出所有带工厂id的部门ids
        List<DeptDO> deptList = deptService.getFactoryDeptList();
        List<Long> deptCondition = deptList.stream().map(DeptDO::getId).collect(Collectors.toList());
        List<AdminUserDO> adminUserDOS = userMapper.selectList(new LambdaQueryWrapper<AdminUserDO>()
                .in(AdminUserDO::getDeptId, deptCondition));
        for (AdminUserDO adminUserDO : adminUserDOS) {
            this.gpsIncrementalSynchronizationOfUsers(adminUserDO);
        }
    }


    @Override
    public List<AdminUserDO> getFactoryUsers(Long factoryId) {
        List<DeptDO> deptList = deptService.getFactoryDeptList(factoryId);
        List<Long> deptCondition = deptList.stream().map(DeptDO::getId).collect(Collectors.toList());
        return userMapper.selectList(new LambdaQueryWrapper<AdminUserDO>()
                .in(AdminUserDO::getDeptId, deptCondition)
                .eq(AdminUserDO::getUserType, 2)
                .eq(AdminUserDO::getStatus, 0));
    }

    @Override
    public void gpsIncrementalSynchronizationOfUsers(AdminUserDO adminUserDO) {
        try {
            JSONObject object = new JSONObject().set("name", adminUserDO.getNickname()).set("uniqueId", adminUserDO.getMobile());
            // 请求的 URL
            String url = "http://127.0.0.1:8082/api/devices";
            // TODO: 2024/9/11 需要判断下是否ck失效
            // 发送 POST 请求
            HttpResponse response = HttpRequest.post(url)
                    .header("Accept", "*/*")
                    .header("Accept-Language", "zh-CN,zh;q=0.9")
                    .header("Connection", "keep-alive")
                    .header("Content-Type", "application/json")
                    .header("Cookie", "JSESSIONID=node07ayjwewvdr8q3ov9smy6m94c3668.node0")
                    .header("Origin", "http://127.0.0.1:8082")
                    .header("Referer", "http://127.0.0.1:8082/settings/device")
                    .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36")
                    .body(JSONUtil.toJsonStr(object))
                    .timeout(20000)  // 设置超时时间
                    .execute();  // 执行请求并获取响应
            log.info(response.body());
        } catch (Exception e) {
            log.info("添加工厂用户到GPS系统中失败", e);
        }
    }

    @Override
    public PageResult<AdminUserDO> getFactoryUserPage(FactoryUserPageReqVO reqVO) {

        // 根据工厂ID 获取 对应部门ID
        DeptDO deptDO = deptService.getDeptByFactoryId(reqVO.getFactoryId());

        if (reqVO.getFactoryId() != null && deptDO == null) {

            return new PageResult<>();
        }

        return userMapper.selectFactoryUserPage(reqVO, deptDO == null ? null : deptDO.getId());
    }

    @Override
    public AdminUserDO getUser(Long id) {
        return userMapper.selectById(id);
    }

    @Override
    public List<AdminUserDO> getUserListByDeptIds(Collection<Long> deptIds, Integer status) {
        if (CollUtil.isEmpty(deptIds)) {
            return Collections.emptyList();
        }
        return userMapper.selectListByDeptIds(deptIds, status);
    }

    @Override
    public List<UserRespVO> getUserByDeptIds(Collection<Long> deptIds) {
        if (CollUtil.isEmpty(deptIds)) {
            return Collections.emptyList();
        }
        return userMapper.selectByDeptIds(deptIds);
    }

    @Override
    public List<UserRespVO> selectByDeptIdsFilterGroupUser(Collection<Long> deptIds, Long groupId) {
        if (CollUtil.isEmpty(deptIds)) {
            return Collections.emptyList();
        }
        return userMapper.selectByDeptIdsFilterGroupUser(deptIds, groupId);
    }

    @Override
    public List<AdminUserDO> getListUserByDeptId(Long deptId) {

        return userMapper.selectListByDeptId(deptId, getLoginUserId());
    }

    @Override
    public List<AdminUserDO> getUserListByPostIds(Collection<Long> postIds) {
        if (CollUtil.isEmpty(postIds)) {
            return Collections.emptyList();
        }
        Set<Long> userIds = convertSet(userPostMapper.selectListByPostIds(postIds), UserPostDO::getUserId);
        if (CollUtil.isEmpty(userIds)) {
            return Collections.emptyList();
        }
        return userMapper.selectBatchIds(userIds);
    }

    @Override
    public List<AdminUserDO> getUserList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return userMapper.selectBatchIds(ids);
    }

    @Override
    public void validateUserList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        // 获得岗位信息
        List<AdminUserDO> users = userMapper.selectBatchIds(ids);
        Map<Long, AdminUserDO> userMap = CollectionUtils.convertMap(users, AdminUserDO::getId);
        // 校验
        ids.forEach(id -> {
            AdminUserDO user = userMap.get(id);
            if (user == null) {
                throw exception(USER_NOT_EXISTS);
            }
            if (!CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus())) {
                throw exception(USER_IS_DISABLE, user.getNickname());
            }
        });
    }

    @Override
    @DataPermission(enable = false)
    public Map<Long, AdminUserDO> getUserListByIds(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return new HashMap<>();
        }
        return CollectionUtils.convertMap(getUserList(ids), AdminUserDO::getId);
    }

    @Override
    public List<AdminUserDO> getUserListByNickname(String nickname) {
        return userMapper.selectListByNickname(nickname);
    }

    /**
     * 获得部门条件：查询指定部门的子部门编号们，包括自身
     *
     * @param deptId 部门编号
     * @return 部门编号集合
     */
    private Set<Long> getDeptCondition(Long deptId) {
        if (deptId == null) {
            return Collections.emptySet();
        }
        Set<Long> deptIds = convertSet(deptService.getChildDeptList(deptId), DeptDO::getId);
        deptIds.add(deptId); // 包括自身
        return deptIds;
    }

    private void validateUserForCreateOrUpdate(Long id, String username, String mobile, String email,
                                               Long deptId, Set<Long> postIds) {
        // 关闭数据权限，避免因为没有数据权限，查询不到数据，进而导致唯一校验不正确
        DataPermissionUtils.executeIgnore(() -> {
            // 校验用户存在
            validateUserExists(id);
            // 校验用户名唯一
            validateUsernameUnique(id, username);
            // 校验手机号唯一
            validateMobileUnique(id, mobile);
            // 校验邮箱唯一
            validateEmailUnique(id, email);
            // 校验部门处于开启状态
            deptService.validateDeptList(CollectionUtils.singleton(deptId));
            // 校验岗位处于开启状态
            postService.validatePostList(postIds);
        });
    }

    @VisibleForTesting
    void validateUserExists(Long id) {
        if (id == null) {
            return;
        }
        AdminUserDO user = userMapper.selectById(id);
        if (user == null) {
            throw exception(USER_NOT_EXISTS);
        }
    }

    @VisibleForTesting
    void validateUsernameUnique(Long id, String username) {
        if (StrUtil.isBlank(username)) {
            return;
        }
        AdminUserDO user = userMapper.selectByUsername(username);
        if (user == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的用户
        if (id == null) {
            throw exception(USER_USERNAME_EXISTS);
        }
        if (!user.getId().equals(id)) {
            throw exception(USER_USERNAME_EXISTS);
        }
    }

    @VisibleForTesting
    void validateEmailUnique(Long id, String email) {
        if (StrUtil.isBlank(email)) {
            return;
        }
        AdminUserDO user = userMapper.selectByEmail(email);
        if (user == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的用户
        if (id == null) {
            throw exception(USER_EMAIL_EXISTS);
        }
        if (!user.getId().equals(id)) {
            throw exception(USER_EMAIL_EXISTS);
        }
    }

    @VisibleForTesting
    void validateMobileUnique(Long id, String mobile) {
        if (StrUtil.isBlank(mobile)) {
            return;
        }
        AdminUserDO user = userMapper.selectByMobile(mobile);
        if (user == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的用户
        if (id == null) {
            throw exception(USER_MOBILE_EXISTS);
        }
        if (!user.getId().equals(id)) {
            throw exception(USER_MOBILE_EXISTS);
        }
    }

    /**
     * 校验旧密码
     *
     * @param id          用户 id
     * @param oldPassword 旧密码
     */
    @VisibleForTesting
    void validateOldPassword(Long id, String oldPassword) {
        AdminUserDO user = userMapper.selectById(id);
        if (user == null) {
            throw exception(USER_NOT_EXISTS);
        }
        if (!isPasswordMatch(oldPassword, user.getPassword())) {
            throw exception(USER_PASSWORD_FAILED);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class) // 添加事务，异常则回滚所有导入
    public UserImportRespVO importUserList(List<UserImportExcelVO> importUsers, boolean isUpdateSupport) {
        if (CollUtil.isEmpty(importUsers)) {
            throw exception(USER_IMPORT_LIST_IS_EMPTY);
        }
        UserImportRespVO respVO = UserImportRespVO.builder().createUsernames(new ArrayList<>()).updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build();

        List<UserPostDO> userPostDOS = new ArrayList<>();
        importUsers.forEach(importUser -> {
            //校验，判断是否有不符合的原因
            try {
                if (!isUpdateSupport) {
                    validateUserForCreateOrUpdate(null, null, importUser.getMobile(), importUser.getEmail(), null, null);
                }
            } catch (ServiceException ex) {
                respVO.getFailureUsernames().put(importUser.getNickname(), ex.getMessage());
                return;
            }

            AdminUserDO updateUser = BeanUtils.toBean(importUser, AdminUserDO.class);

            //解析身份证号码
            IdCardDO idCardDO = StrUtils.IdCardAnalysis(updateUser.getIdcard());

            //设置 性别、年龄、出生日期
            updateUser.setSex(idCardDO.getSex());
            updateUser.setAge(idCardDO.getAge());
            updateUser.setBirthdayDay(idCardDO.getDate());

            //设置部门ID
            if (importUser.getDeptName() != null && !importUser.getDeptName().isEmpty()) {

                //excel接受到部门名称格式为 id:name
                updateUser.setDeptId(Long.valueOf(importUser.getDeptName().split(":")[0]));
            }

            //设置岗位ID
            if (importUser.getPostName() != null && !importUser.getPostName().isEmpty()) {

                //excel接受到部门名称格式为 id:name
                String postID = importUser.getPostName().split(":")[0];

                updateUser.setPostIds(Collections.singleton(Long.valueOf(postID)));
            }

            // 判断如果不存在，在进行插入
            AdminUserDO existUser = userMapper.selectByUsername(importUser.getMobile());
            if (existUser == null) {
                userMapper.insert(updateUser.setPassword(encodePassword(userInitPassword))); // 设置默认密码

                // 设置 user_post关联表
                userPostDOS.addAll(convertList(updateUser.getPostIds(),
                        postId -> new UserPostDO().setUserId(updateUser.getId()).setPostId(postId)));

                respVO.getCreateUsernames().add(importUser.getNickname());
                return;
            }

            // 如果存在，判断是否允许更新
            if (!isUpdateSupport) {

                respVO.getFailureUsernames().put(importUser.getNickname(), USER_USERNAME_EXISTS.getMsg());
                return;
            }

            updateUser.setId(existUser.getId());
            userMapper.updateById(updateUser);
            // 更新用户岗位关联表
            updateUserPost(new UserSaveReqVO().setId(existUser.getId()), new AdminUserDO().setPostIds(updateUser.getPostIds()));
            respVO.getUpdateUsernames().add(importUser.getNickname());
        });

        // 插入user_post
        if (CollectionUtil.isNotEmpty(userPostDOS)) {
            userPostMapper.insertBatch(userPostDOS);
        }
        return respVO;
    }

    @Override
    public List<AdminUserDO> getUserListByStatus(Integer userType, Long deptId, Integer status, String roleCodes, Integer filterCrmUserFlag) {
        List<Long> deptIds = new ArrayList<>();
        if (deptId != null) {
            deptIds = convertList(deptService.getChildDept(deptId), DeptDO::getId);
        }
        List<String> roleCodeList = new ArrayList<>();
        if (StringUtil.isNotEmpty(roleCodes)) {
            roleCodeList = Arrays.asList(roleCodes.split(","));
        }
        return userMapper.selectListByCondition(userType, deptIds, status, roleCodeList, filterCrmUserFlag);
    }

    @Override
    public boolean isPasswordMatch(String rawPassword, String encodedPassword) {
        return passwordEncoder.matches(rawPassword, encodedPassword);
    }

    @Override
    public List<Long> getUserIdsByDeptId(Long deptId) {
        List<Long> userIds = new ArrayList<>();
        List<AdminUserDO> adminUserDOS = userMapper.selectListByDeptIds(Arrays.asList(deptId), null);
        if (!adminUserDOS.isEmpty()) {
            userIds = adminUserDOS.stream().map(AdminUserDO::getId).collect(Collectors.toList());
        }
        return userIds;
    }

    @Override
    public void emptyOpenId(String openId) {
        userMapper.emptyOpenId(openId);
    }

    /**
     * 对密码进行加密
     *
     * @param password 密码
     * @return 加密后的密码
     */
    private String encodePassword(String password) {
        return passwordEncoder.encode(password);
    }

    @Override
    public String getSignImgPath(Long userId) {
        //2L 用户签名
        String path = fileApi.getUserSignImgPath(userId).getData();
        return path;
    }

    @Override
    public List<Long> getUserByBoss() {

        return userMapper.selectUserByBoss();
    }

    @Override
    public List<AdminUserDO> selectByUserIds(Collection<Long> userIds) {
        if (CollectionUtil.isEmpty(userIds)) {
            return Collections.emptyList();
        }
        return userMapper.selectBatchIds(userIds);
    }

    @Override
    public List<AdminUserDO> getAllList(Integer status, Integer type, List<Long> userIds) {
        if (CollUtil.isEmpty(userIds)) {
            return Collections.emptyList();
        }
        return userMapper.selectList(new LambdaQueryWrapper<AdminUserDO>()
                .eq(status != null, AdminUserDO::getStatus, status)
                .eq(type != null, AdminUserDO::getUserType, type)
                .in(CollectionUtil.isNotEmpty(userIds), AdminUserDO::getId, userIds));
    }

    @Override
    public List<AdminUserDO> getAllList(UserDTO dto) {
        return userMapper.getAllList(dto);
    }

    @Override
    public IPage<UserSimpleRespVO> getAllUserListByGroupIds(UserPageDTO dto) {
        return userMapper.getAllUserListByGroupIds(MyBatisUtils.buildPage(dto), dto);
    }

    @Override
    public List<AdminUserDO> getListByNature(Integer userNature) {
        return userMapper.selectList(AdminUserDO::getUserNature, userNature);
    }

    @Override
    public List<AdminUserDO> getUserListByUserStaffing(Integer userStaffing) {

        return userMapper.selectList(AdminUserDO::getUserStaffing, userStaffing);
    }

    @Override
    public PageResult<UserBirthdayRespVO> getUserListByBirthday(UserBirthdayPageReqVO pageReqVO) {

        List<Long> deptIds = new ArrayList<>();
        if (pageReqVO.getDeptId() != null) {
            deptIds = convertList(deptService.getChildDept(pageReqVO.getDeptId()), DeptDO::getId);
        }

        LocalDate date = LocalDate.now();
        if (pageReqVO.getMonth() != null) {
            // 获取该月份的第一天
            date = LocalDate.of(LocalDate.now().getYear(), pageReqVO.getMonth(), 1);
        }

        return userMapper.selectUserPageByBirthday(pageReqVO, deptIds, date);
    }

    @Override
    public List<AdminUserDO> getUserListByIdCard(List<String> idCards) {

        return userMapper.selectList(new LambdaQueryWrapperX<AdminUserDO>()
                .inIfPresent(AdminUserDO::getIdcard, idCards));
    }

    @Override
    public void updateUserEntryDate(Long id, LocalDateTime entryDate) {
        userMapper.updateById(new AdminUserDO().setId(id).setEntryDate(entryDate));
    }

    @Override
    public List<AdminUserDO> getUserList(AdminUserApiDTO dto) {
        List<Long> deptIds = new ArrayList<>();
        if (dto.getDeptId() != null) {
            if (dto.getNextDept() == null || dto.getNextDept() == 0) {
                deptIds.add(dto.getDeptId());
            } else {
                deptIds = new ArrayList<>(this.getDeptCondition(dto.getDeptId()));
            }
        }
        return userMapper.selectList(new LambdaQueryWrapper<AdminUserDO>()
                .eq(dto.getStatus() != null, AdminUserDO::getStatus, dto.getStatus())
                .in(CollectionUtil.isNotEmpty(deptIds), AdminUserDO::getDeptId, deptIds));
    }

    @Override
    public List<Long> getUserListBySubordinateIds(Long adminId) {
        List<AdminUserRespDTO> adminUserRespDTOS = getUserListBySubordinate(adminId);
        List<Long> ids = adminUserRespDTOS.stream().map(AdminUserRespDTO::getId).collect(Collectors.toList());
        if (ids.isEmpty()) {
            ids.add(-99L);
        }
        return ids;
    }

    @Override
    public List<AdminUserRespDTO> getUserListBySubordinate(Long id) {
        // 1.1 获取用户负责的部门
        AdminUserDO user = this.getUser(id);
        if (user == null) {
            return Collections.emptyList();
        }
        DeptDO dept = deptService.getDept(user.getDeptId());
        if (dept == null) {
            return Collections.emptyList();
        }
        // -- 获取当前用户所有负责的部门列表
        List<DeptDO> deptByLeaderIdList = deptService.getDeptByLeaderId(id);
        List<Long> ids = deptByLeaderIdList.stream().map(DeptDO::getId).collect(Collectors.toList());
        List<Long> nextIds = new ArrayList<>();
        // 获取所有可用部门列表
        List<DeptDO> deptList = deptService.getAllList();
        Map<Long, List<DeptDO>> map = deptList.stream().collect(Collectors.groupingBy(DeptDO::getParentId));
        this.getSubordinateDeptIds(map, nextIds, ids);
        nextIds.add(dept.getId());
        nextIds = nextIds.stream().distinct().collect(Collectors.toList());
        // 2. 获取部门对应的用户信息
        List<AdminUserDO> users = this.getUserListByDeptIds(nextIds, null);
        users.removeIf(item -> ObjUtil.equal(item.getId(), id)); // 排除自己
        return BeanUtils.toBean(users, AdminUserRespDTO.class);
    }

    private void getSubordinateDeptIds(Map<Long, List<DeptDO>> map, List<Long> deptIds, List<Long> nextIds) {
        if (CollUtil.isEmpty(nextIds)) {
            return;
        }
        List<DeptDO> deptDOS = map.get(nextIds.get(0));
        if (CollUtil.isNotEmpty(deptDOS)) {
            List<Long> ids = deptDOS.stream().map(DeptDO::getId).collect(Collectors.toList());
            deptIds.addAll(ids);
            nextIds.addAll(ids);
        }
        nextIds.remove(0);
        nextIds = nextIds.stream().distinct().collect(Collectors.toList());
        getSubordinateDeptIds(map, deptIds, nextIds);
    }

    @Override
    public void updateUnionId(Long id, String unionId) {
        userMapper.updateById(new AdminUserDO().setId(id).setUnionId(unionId));
    }

    @Override
    public AdminUserDO getUserByUnionId(String unionId) {
        return userMapper.selectOne(new LambdaQueryWrapper<AdminUserDO>()
                .eq(AdminUserDO::getUnionId, unionId));
    }

    @Override
    public PageResult<AdminUserDO> getUserPageByRole(AdminUserPageApiDTO pageReqVO) {
        List<String> roleCodeList = new ArrayList<>();
        if (StringUtil.isNotEmpty(pageReqVO.getRoleCodes())) {
            roleCodeList = Arrays.asList(pageReqVO.getRoleCodes().split(","));
        }

        IPage<AdminUserDO> mpPage = MyBatisUtils.buildPage(pageReqVO);
        IPage<AdminUserDO> page = userMapper.selectUserPageByRole(mpPage, pageReqVO, roleCodeList);
        return new PageResult<>(page.getRecords(), page.getTotal());
    }

    @Override
    public List<AdminUserDO> getUserListByDepts(Integer userType, List<Long> deptIds, Integer status) {
        return userMapper.selectList(new LambdaQueryWrapperX<AdminUserDO>()
                .eqIfPresent(AdminUserDO::getUserType, userType)
                .eqIfPresent(AdminUserDO::getStatus, status)
                .inIfPresent(AdminUserDO::getDeptId, deptIds));
    }
}
