package cn.cordys.crm.system.service;

import cn.cordys.aspectj.annotation.OperationLog;
import cn.cordys.aspectj.constants.LogModule;
import cn.cordys.aspectj.constants.LogType;
import cn.cordys.aspectj.context.OperationLogContext;
import cn.cordys.aspectj.dto.LogContextInfo;
import cn.cordys.aspectj.dto.LogDTO;
import cn.cordys.common.constants.InternalRole;
import cn.cordys.common.constants.InternalUser;
import cn.cordys.common.dto.BaseTreeNode;
import cn.cordys.common.dto.DeptUserTreeNode;
import cn.cordys.common.dto.OptionDTO;
import cn.cordys.common.exception.GenericException;
import cn.cordys.common.permission.PermissionCache;
import cn.cordys.common.uid.IDGenerator;
import cn.cordys.common.util.BeanUtils;
import cn.cordys.common.util.CodingUtils;
import cn.cordys.common.util.SubListUtils;
import cn.cordys.common.util.Translator;
import cn.cordys.crm.approval.service.ApprovalActionService;
import cn.cordys.crm.clue.mapper.ExtClueMapper;
import cn.cordys.crm.customer.mapper.ExtCustomerMapper;
import cn.cordys.crm.opportunity.mapper.ExtOpportunityMapper;
import cn.cordys.crm.search.mapper.ExtUserSearchConfigMapper;
import cn.cordys.crm.system.domain.*;
import cn.cordys.crm.system.dto.convert.UserRoleConvert;
import cn.cordys.crm.system.dto.request.*;
import cn.cordys.crm.system.dto.response.UserImportDTO;
import cn.cordys.crm.system.dto.response.UserImportResponse;
import cn.cordys.crm.system.dto.response.UserPageResponse;
import cn.cordys.crm.system.dto.response.UserResponse;
import cn.cordys.crm.system.excel.domain.UserExcelData;
import cn.cordys.crm.system.excel.domain.UserExcelDataFactory;
import cn.cordys.crm.system.excel.handler.UserTemplateWriteHandler;
import cn.cordys.crm.system.excel.listener.UserCheckEventListener;
import cn.cordys.crm.system.excel.listener.UserImportEventListener;
import cn.cordys.crm.system.mapper.*;
import cn.cordys.excel.utils.EasyExcelExporter;
import cn.cordys.mybatis.BaseMapper;
import cn.cordys.security.SessionUtils;
import cn.idev.excel.FastExcelFactory;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Strings;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


@Service("organizationUserService")
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class OrganizationUserService {

    @Resource
    private ExtOrganizationUserMapper extOrganizationUserMapper;
    @Resource
    private ExtUserMapper extUserMapper;
    @Resource
    private RoleService roleService;
    @Resource
    private BaseMapper<User> userMapper;
    @Resource
    private BaseMapper<OrganizationUser> organizationUserMapper;
    @Resource
    private BaseMapper<UserRole> userRoleMapper;
    @Resource
    private ExtUserRoleMapper extUserRoleMapper;
    @Resource
    private LogService logService;
    @Resource
    private ExtDepartmentCommanderMapper extDepartmentCommanderMapper;
    @Resource
    private ExtDepartmentMapper extDepartmentMapper;
    @Resource
    private BaseMapper<DepartmentCommander> departmentCommanderMapper;
    @Resource
    private BaseMapper<UserExtend> userExtendMapper;
    @Resource
    private ExtUserExtendMapper extUserExtendMapper;
    @Resource
    private BaseMapper<Department> departmentMapper;
    @Resource
    private DepartmentService departmentService;
    @Resource
    private SqlSessionFactory sqlSessionFactory;
    @Resource
    private ExtOpportunityMapper extOpportunityMapper;
    @Resource
    private ExtCustomerMapper extCustomerMapper;
    @Resource
    private ExtClueMapper extClueMapper;
    @Resource
    private ExtUserViewMapper extUserViewMapper;
    @Resource
    private ExtUserViewConditionMapper extUserViewConditionMapper;
    @Resource
    private ExtUserSearchConfigMapper extUserSearchConfigMapper;
    @Resource
    private PermissionCache permissionCache;
    @Resource
    private ExtNotificationMapper extNotificationMapper;
    @Resource
    private UserRoleService userRoleService;
    @Resource
    private ApprovalActionService approvalActionService;


    /**
     * 员工列表查询
     *
     * @param request
     * @return
     */
    public List<UserPageResponse> list(UserPageRequest request) {
        String orderByClause = buildOrderByFieldClause(request.getDepartmentIds());
        request.setDepartmentIds(request.getDepartmentIds().stream().filter(id -> id.chars().allMatch(Character::isDigit)).toList());
        List<UserPageResponse> list = extOrganizationUserMapper.list(request, orderByClause);
        handleData(list, request.getDepartmentIds().getFirst());
        return list;
    }

    private String buildOrderByFieldClause(List<String> departmentIds) {
        if (departmentIds == null || departmentIds.isEmpty()) {
            return "1"; // 默认排序，如果无部门ID传入
        }
        departmentIds = departmentIds.stream().filter(id -> id.chars().allMatch(Character::isDigit)).toList();
        StringJoiner sj = new StringJoiner(",", "FIELD(department_id, ", ")");
        for (String deptId : departmentIds) {
            sj.add("'" + deptId + "'");
        }
        return sj.toString();
    }


    private void handleData(List<UserPageResponse> list, String departmentId) {
        if (CollectionUtils.isNotEmpty(list)) {
            String orgId = list.stream().
                    map(UserPageResponse::getOrganizationId)
                    .toList()
                    .getFirst();
            List<String> userIds = list.stream()
                    .map(UserPageResponse::getUserId)
                    .toList();
            //获取用户角色
            List<UserRoleConvert> userRoles = extUserMapper.getUserRole(userIds, orgId);
            userRoles.forEach(role -> role.setName(roleService.translateInternalRole(role.getName())));
            Map<String, List<UserRoleConvert>> userRoleMap = userRoles.stream()
                    .collect(Collectors.groupingBy(UserRoleConvert::getUserId));
            //创建人 更新人
            List<String> ids = new ArrayList<>();
            ids.addAll(list.stream().map(UserPageResponse::getCreateUser).toList());
            ids.addAll(list.stream().map(UserPageResponse::getUpdateUser).toList());
            List<OptionDTO> options = extUserMapper.selectUserOptionByIds(ids);
            Map<String, String> userMap = options
                    .stream()
                    .collect(Collectors.toMap(OptionDTO::getId, OptionDTO::getName));
            //直属上级
            List<String> supervisorIds = list.stream()
                    .map(UserPageResponse::getSupervisorId)
                    .distinct()
                    .toList();
            List<OptionDTO> supervisors = extUserMapper.selectUserOptionByIds(supervisorIds);
            Map<String, String> supervisorMap = supervisors.stream()
                    .collect(Collectors.toMap(OptionDTO::getId, OptionDTO::getName));
            //部门
            List<String> departmentIds = list.stream()
                    .map(UserPageResponse::getDepartmentId)
                    .distinct()
                    .toList();
            List<Department> departmentList = departmentMapper.selectByIds(departmentIds.toArray(new String[0]));
            Map<String, String> departmentMap = departmentList.stream()
                    .collect(Collectors.toMap(Department::getId, Department::getName));
            //部门负责人
            List<String> commanderIds = extDepartmentCommanderMapper.selectCommander(departmentId, list.getFirst().getOrganizationId());

            //todo 暂无用户组 后续需求再处理
            list.forEach(user -> {
                if (userRoleMap.containsKey(user.getUserId())) {
                    user.setRoles(userRoleMap.get(user.getUserId()));
                }
                if (userMap.containsKey(user.getCreateUser())) {
                    user.setCreateUserName(userMap.get(user.getCreateUser()));
                }
                if (userMap.containsKey(user.getUpdateUser())) {
                    user.setUpdateUserName(userMap.get(user.getUpdateUser()));
                }
                if (departmentMap.containsKey(user.getDepartmentId())) {
                    user.setDepartmentName(departmentMap.get(user.getDepartmentId()));
                }
                if (supervisorMap.containsKey(user.getSupervisorId())) {
                    user.setSupervisorName(supervisorMap.get(user.getSupervisorId()));
                }
                if (commanderIds.contains(user.getUserId())) {
                    user.setCommander(true);
                }
            });

        }
    }


    /**
     * 添加员工
     *
     * @param request
     * @param organizationId
     * @param operatorId
     */
    @OperationLog(module = LogModule.SYSTEM_ORGANIZATION, type = LogType.ADD, operator = "{#operatorId}")
    public void addUser(UserAddRequest request, String organizationId, String operatorId) {
        String id = IDGenerator.nextStr();
        //邮箱和手机号唯一性校验
        checkEmailAndPhone(request.getEmail(), request.getPhone(), id);
        //add user base
        User user = addUserBaseData(request, operatorId, id);
        user.setLastOrganizationId(organizationId);
        //add user info
        addUserInfo(request, organizationId, operatorId, user.getId());
        //add user role
        addUserRole(request.getRoleIds(), user.getId(), operatorId);
        //todo add user group
        //添加日志上下文
        OperationLogContext.setContext(LogContextInfo.builder()
                .originalValue(null)
                .modifiedValue(user)
                .resourceName(user.getName())
                .resourceId(user.getId())
                .build());
    }


    /**
     * 添加用户角色关系
     *
     * @param roleIds
     * @param userId
     * @param operatorId
     */
    private void addUserRole(List<String> roleIds, String userId, String operatorId) {
        if (CollectionUtils.isNotEmpty(roleIds)) {
            List<UserRole> list = new ArrayList<>();
            roleIds.forEach(roleId -> {
                UserRole userRole = new UserRole();
                userRole.setId(IDGenerator.nextStr());
                userRole.setUserId(userId);
                userRole.setRoleId(roleId);
                userRole.setCreateTime(System.currentTimeMillis());
                userRole.setCreateUser(operatorId);
                userRole.setUpdateTime(System.currentTimeMillis());
                userRole.setUpdateUser(operatorId);
                list.add(userRole);
            });
            userRoleMapper.batchInsert(list);
        }
    }


    /**
     * 添加用戶信息
     *
     * @param request
     * @param organizationId
     * @param userId
     */
    private void addUserInfo(UserAddRequest request, String organizationId, String operatorId, String userId) {
        OrganizationUser orgUser = new OrganizationUser();
        BeanUtils.copyBean(orgUser, request);
        orgUser.setId(IDGenerator.nextStr());
        orgUser.setOrganizationId(organizationId);
        orgUser.setUserId(userId);
        orgUser.setCreateTime(System.currentTimeMillis());
        orgUser.setCreateUser(operatorId);
        orgUser.setUpdateTime(System.currentTimeMillis());
        orgUser.setUpdateUser(operatorId);
        orgUser.setOnboardingDate(request.getOnboardingDate());
        organizationUserMapper.insert(orgUser);
    }

    /**
     * 邮箱和手机号唯一性校验
     *
     * @param email
     * @param phone
     */
    private void checkEmailAndPhone(String email, String phone, String id) {
        if (extUserMapper.countByEmail(email, id) > 0) {
            throw new GenericException(Translator.get("email.exist"));
        }
        if (extUserMapper.countByPhone(phone, id) > 0) {
            throw new GenericException(Translator.get("phone.exist"));
        }

    }

    /**
     * 添加用户基本数据
     *
     * @param request
     * @param operatorId
     * @return
     */
    private User addUserBaseData(UserAddRequest request, String operatorId, String id) {
        User user = new User();
        BeanUtils.copyBean(user, request);
        user.setId(id);
        user.setPassword(CodingUtils.md5(request.getPhone().substring(request.getPhone().length() - 6)));
        user.setCreateTime(System.currentTimeMillis());
        user.setCreateUser(operatorId);
        user.setUpdateTime(System.currentTimeMillis());
        user.setUpdateUser(operatorId);
        user.setLanguage(Locale.SIMPLIFIED_CHINESE.toString());
        userMapper.insert(user);
        return user;
    }


    /**
     * 获取用户详情
     *
     * @param id
     * @return
     */
    public UserResponse getUserDetail(String id) {
        UserResponse userDetail = extUserMapper.getUserDetail(id);
        if (StringUtils.isNotBlank(userDetail.getSupervisorId())) {
            User user = userMapper.selectByPrimaryKey(userDetail.getSupervisorId());
            userDetail.setSupervisorName(Optional.ofNullable(user).map(User::getName).orElse(null));
        }
        //获取用户角色
        List<UserRoleConvert> userRoles = extUserMapper.getUserRole(List.of(userDetail.getUserId()), userDetail.getOrganizationId());
        userRoles.forEach(role -> role.setName(roleService.translateInternalRole(role.getName())));
        userDetail.setRoles(userRoles);
        return userDetail;
    }

    /**
     * 更新用户
     *
     * @param request
     * @param operatorId
     */
    @OperationLog(module = LogModule.SYSTEM_ORGANIZATION, type = LogType.UPDATE, operator = "{#operatorId}")
    public void updateUser(UserUpdateRequest request, String operatorId, String orgId) {
        UserResponse oldUser = getUserDetail(request.getId());
        //邮箱和手机号唯一性校验
        checkEmailAndPhone(request.getEmail(), request.getPhone(), oldUser.getUserId());
        //update user info
        updateUserInfo(request, operatorId, oldUser);
        //update user base
        updateUserBaseData(request, operatorId, oldUser.getUserId());
        //update user role
        updateUserRole(request.getRoleIds(), oldUser, operatorId, orgId);
        if (!request.getEnable()) {
            // 踢出该用户
            SessionUtils.kickOutUser(operatorId, oldUser.getUserId());
        }

        //添加日志上下文
        OperationLogContext.setContext(LogContextInfo.builder()
                .originalValue(oldUser)
                .resourceName(oldUser.getUserName())
                .modifiedValue(getUserDetail(request.getId()))
                .resourceId(oldUser.getId())
                .build());
    }

    /**
     * 更新用户角色
     *
     * @param roleIds
     * @param oldUser
     * @param operatorId
     */
    private void updateUserRole(List<String> roleIds, UserResponse oldUser, String operatorId, String orgId) {
        Optional.ofNullable(roleIds).ifPresent(ids -> extUserRoleMapper.deleteUserRoleByUserId(oldUser.getUserId()));
        if (CollectionUtils.isNotEmpty(roleIds)) {
            addUserRole(roleIds, oldUser.getUserId(), operatorId);
        }
        permissionCache.clearCache(oldUser.getUserId(), orgId);
    }

    /**
     * 更新用户信息
     *
     * @param request
     * @param operatorId
     */
    private void updateUserInfo(UserUpdateRequest request, String operatorId, UserResponse user) {
        OrganizationUser organizationUser = BeanUtils.copyBean(new OrganizationUser(), user);
        BeanUtils.copyBean(organizationUser, request);
        organizationUser.setUpdateTime(System.currentTimeMillis());
        organizationUser.setUpdateUser(operatorId);
        organizationUser.setOnboardingDate(request.getOnboardingDate());
        extOrganizationUserMapper.updateById(organizationUser);
    }


    /**
     * 更新用户基本数据
     *
     * @param request
     * @param operatorId
     * @param userId
     */
    private void updateUserBaseData(UserUpdateRequest request, String operatorId, String userId) {
        User updateUser = BeanUtils.copyBean(new User(), request);
        updateUser.setId(userId);
        updateUser.setUpdateTime(System.currentTimeMillis());
        updateUser.setUpdateUser(operatorId);
        userMapper.updateById(updateUser);
    }

    /**
     * 重置密码
     *
     * @param userId
     * @param operatorId
     */
    public void resetPassword(String userId, String operatorId, String orgId) {
        if (!Strings.CI.equals(userId, InternalUser.ADMIN.getValue())) {
            User user = userMapper.selectByPrimaryKey(userId);
            if (StringUtils.isBlank(user.getPhone())) {
                throw new GenericException(Translator.get("user_phone_not_exist"));
            }
            user.setPassword(CodingUtils.md5(user.getPhone().substring(user.getPhone().length() - 6)));
            user.setUpdateTime(System.currentTimeMillis());
            user.setUpdateUser(operatorId);
            userMapper.updateById(user);

            // 踢出该用户
            SessionUtils.kickOutUser(operatorId, userId);

            LogDTO logDTO = new LogDTO(orgId, userId, operatorId, LogType.UPDATE, LogModule.SYSTEM_ORGANIZATION, user.getName());
            Map<String, String> oldMap = new HashMap<>();
            oldMap.put("userPassword", "############");
            Map<String, String> newMap = new HashMap<>();
            newMap.put("userPassword", "************");
            logDTO.setOriginalValue(oldMap);
            logDTO.setModifiedValue(newMap);
            logService.add(logDTO);
        }
    }

    /**
     * 批量启用/禁用
     *
     * @param request
     * @param operatorId
     */
    public void enable(UserBatchEnableRequest request, String operatorId, String orgId) {
        extOrganizationUserMapper.enable(request, operatorId, System.currentTimeMillis());

        // 记录日志
        OrganizationUser originUser = new OrganizationUser();
        originUser.setEnable(!request.isEnable());
        OrganizationUser newUser = new OrganizationUser();
        newUser.setEnable(request.isEnable());
        SubListUtils.dealForSubList(request.getIds(), 50, ids -> {
            List<OptionDTO> orgUsers = extOrganizationUserMapper.selectEnableOrgUser(ids, !request.isEnable());
            if (!request.isEnable()) {
                List<String> userIds = orgUsers.stream().map(OptionDTO::getId).toList();
                approvalActionService.refreshApprovingTasksForDisabledUser(userIds, orgId);
            }

            List<LogDTO> logs = new ArrayList<>();
            orgUsers.forEach(orgUser -> {
                // 踢出该用户
                SessionUtils.kickOutUser(operatorId, orgUser.getId());

                LogDTO logDTO = new LogDTO(orgId, orgUser.getId(), operatorId, LogType.UPDATE, LogModule.SYSTEM_ORGANIZATION, orgUser.getName());
                logDTO.setOriginalValue(originUser);
                logDTO.setModifiedValue(newUser);
                logs.add(logDTO);
            });

            logService.batchAdd(logs);
        });
    }


    /**
     * 批量重置密码
     *
     * @param request
     * @param operatorId
     * @param orgId
     */
    public void batchResetPassword(UserBatchRequest request, String operatorId, String orgId) {
        List<User> userList = extOrganizationUserMapper.getUserList(request);
        if (CollectionUtils.isEmpty(userList)) {
            throw new GenericException(Translator.get("user_phone_not_exist"));
        }

        List<LogDTO> logs = new ArrayList<>();
        Map<String, String> oldMap = new HashMap<>();
        oldMap.put("userPassword", "############");
        Map<String, String> newMap = new HashMap<>();
        newMap.put("userPassword", "************");
        userList.forEach(user -> {
            if (!Strings.CI.equals(user.getId(), InternalUser.ADMIN.getValue())) {
                user.setPassword(CodingUtils.md5(user.getPhone().substring(user.getPhone().length() - 6)));
            }
            user.setUpdateTime(System.currentTimeMillis());
            user.setUpdateUser(operatorId);
            LogDTO logDTO = new LogDTO(orgId, user.getId(), operatorId, LogType.UPDATE, LogModule.SYSTEM_ORGANIZATION, user.getName());
            logDTO.setOriginalValue(oldMap);
            logDTO.setModifiedValue(newMap);
            logs.add(logDTO);
            // 踢出该用户
            SessionUtils.kickOutUser(operatorId, user.getId());
        });
        extUserMapper.batchUpdatePassword(userList);
        logService.batchAdd(logs);

    }


    /**
     * 删除用户
     *
     * @param orgId
     */
    public void deleteUser(String orgId) {
        List<String> departmentIds = extDepartmentMapper.selectAllDepartmentIds(orgId);
        if (CollectionUtils.isNotEmpty(departmentIds)) {
            extDepartmentCommanderMapper.deleteByDepartmentIds(departmentIds);
        }
        List<User> userList = extUserMapper.getAllUserIds(orgId);
        List<String> ids = userList.stream().map(User::getId).toList();
        if (CollectionUtils.isNotEmpty(ids)) {
            extUserMapper.deleteByIds(ids);
            extUserExtendMapper.deleteUser(ids);
            // 删除用户角色关联
            extUserRoleMapper.deleteUserRoleByUserIds(ids);
            extUserViewConditionMapper.deleteByUserIds(ids, orgId);
            extUserViewMapper.deleteUserViewByUserIds(ids, orgId);
            extUserSearchConfigMapper.deleteByUserIds(ids, orgId);
            //删除用户收到的公告和通知
            extNotificationMapper.deleteByReceivers(ids, orgId);
        }
        // 踢出用户
        userList.forEach(user -> SessionUtils.kickOutUser(user.getName()));
        extOrganizationUserMapper.deleteUserByOrgId(orgId);

    }

    /**
     * 保存同步信息
     *
     * @param users
     * @param userExtends
     * @param organizationUsers
     * @param departmentCommanders
     */
    public void save(List<User> users, List<UserExtend> userExtends, List<OrganizationUser> organizationUsers, List<DepartmentCommander> departmentCommanders) {
        userMapper.batchInsert(users);
        userExtendMapper.batchInsert(userExtends);
        organizationUserMapper.batchInsert(organizationUsers);
        departmentCommanderMapper.batchInsert(departmentCommanders);
    }

    public void disableUsers(List<OrganizationUser> userList) {
        try {
            userList.forEach(user -> SessionUtils.kickOutUser(user.getUserId()));
        } catch (Exception e) {
            log.error("disableUsers kick out user error", e);
        }
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        ExtUserMapper extUserMapper = sqlSession.getMapper(ExtUserMapper.class);
        ExtOrganizationUserMapper extOrganizationUserMapper = sqlSession.getMapper(ExtOrganizationUserMapper.class);
        userList.forEach(extUserMapper::updateUserInfo);
        userList.forEach(extOrganizationUserMapper::disableUser);
        sqlSession.flushStatements();
        SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
    }


    /**
     * 更新同步信息
     *
     * @param updateUsers
     * @param updateOrganizationUsers
     */
    public void update(List<User> updateUsers, List<OrganizationUser> updateOrganizationUsers) {
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        ExtUserMapper extUserMapper = sqlSession.getMapper(ExtUserMapper.class);
        ExtOrganizationUserMapper extOrganizationUserMapper = sqlSession.getMapper(ExtOrganizationUserMapper.class);
        updateUsers.forEach(extUserMapper::updateUser);
        updateOrganizationUsers.forEach(extOrganizationUserMapper::updateOrganizationUser);
        sqlSession.flushStatements();
        SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
    }


    /**
     * 批量编辑用户
     *
     * @param request
     * @param operatorId
     * @param organizationId
     */
    public void batchEditUser(UserBatchEditRequest request, String operatorId, String organizationId) {
        List<UserResponse> originUser = extOrganizationUserMapper.selectByIds(request.getIds());
        extOrganizationUserMapper.updateUserByIds(request, operatorId, organizationId);
        List<UserResponse> modifiedUser = extOrganizationUserMapper.selectByIds(request.getIds());
        Map<String, UserResponse> userMap = modifiedUser.stream().collect(Collectors.toMap(UserResponse::getUserId, Function.identity()));


        List<LogDTO> logs = originUser.stream()
                .map(origUser -> {
                    LogDTO logDTO = new LogDTO(organizationId, origUser.getUserId(), operatorId, LogType.UPDATE, LogModule.SYSTEM_ORGANIZATION, origUser.getUserName());
                    logDTO.setOriginalValue(origUser);
                    logDTO.setModifiedValue(userMap.get(origUser.getUserId()));
                    return logDTO;
                }).toList();
        logService.batchAdd(logs);

    }


    /**
     * excel导入-下载模板
     *
     * @param response
     */
    public void downloadExcelTemplate(HttpServletResponse response) {
        //获取表头字段
        List<List<String>> heads = getTemplateHead();
        //表头备注信息
        UserTemplateWriteHandler handler = new UserTemplateWriteHandler(heads);
        List<List<Object>> data = new ArrayList<>();

        new EasyExcelExporter()
                .exportByCustomWriteHandler(response, heads, data, Translator.get("user_import_template_name"),
                        Translator.get("user_import_template_sheet"), handler);
    }


    /**
     * 获取表头字段
     *
     * @return
     */
    private List<List<String>> getTemplateHead() {
        return new UserExcelDataFactory().getUserExcelDataLocal().getHead();
    }


    /**
     * 导入excel检查
     *
     * @param file
     * @return
     */
    public UserImportResponse preCheck(MultipartFile file, String orgId) {
        if (file == null) {
            throw new GenericException(Translator.get("file_cannot_be_null"));
        }

        UserImportResponse response = new UserImportResponse();
        checkImportExcel(response, file, orgId);
        return response;
    }


    private void checkImportExcel(UserImportResponse response, MultipartFile file, String orgId) {
        try {
            //根据本地语言环境选择用哪种数据对象进行存放读取的数据
            Class<?> clazz = new UserExcelDataFactory().getExcelDataByLocal();
            UserCheckEventListener eventListener = new UserCheckEventListener(clazz, orgId);
            FastExcelFactory.read(file.getInputStream(), eventListener).headRowNumber(3).sheet().doRead();
            response.setErrorMessages(eventListener.getErrList());
            response.setSuccessCount(eventListener.getList().size());
            response.setFailCount(eventListener.getErrList().size());
        } catch (Exception e) {
            log.error("checkImportExcel error", e);
            throw new GenericException(Translator.get("check_import_excel_error"));
        }
    }


    /**
     * 用户导入
     *
     * @param file
     * @param operatorId
     * @param orgId
     * @return
     */
    public UserImportResponse importByExcel(MultipartFile file, String operatorId, String orgId) {
        if (file == null) {
            throw new GenericException(Translator.get("file_cannot_be_null"));
        }
        try {
            UserImportResponse response = new UserImportResponse();
            //根据本地语言环境选择用哪种数据对象进行存放读取的数据
            Class<?> clazz = new UserExcelDataFactory().getExcelDataByLocal();
            UserImportEventListener eventListener = new UserImportEventListener(clazz, operatorId, orgId);
            FastExcelFactory.read(file.getInputStream(), eventListener).headRowNumber(3).sheet().doRead();
            response.setErrorMessages(eventListener.getErrList());
            response.setSuccessCount(eventListener.getSuccessCount());
            response.setFailCount(eventListener.getErrList().size());
            return response;
        } catch (Exception e) {
            log.error("checkImportExcel error", e);
            throw new GenericException(Translator.get("check_import_excel_error"));
        }
    }


    /**
     * 保存导入数据
     *
     * @param list
     * @param departmentTree
     * @param departmentMap
     * @param operatorId
     * @param orgId
     */
    @CacheEvict(value = "dept_tree_cache", key = "#orgId", beforeInvocation = true)
    public void saveImportData(List<UserExcelData> list, List<BaseTreeNode> departmentTree, Map<String, String> departmentMap, String operatorId, String orgId) {
        //部门
        List<String> departmentPath = list.stream().map(UserExcelData::getDepartment).toList();
        // 记录日志
        List<LogDTO> logs = new ArrayList<>();
        //构建部门树
        Map<String, String> departmentPathMap = departmentService.createDepartment(departmentPath, orgId, departmentTree, operatorId, departmentMap, logs);
        List<String> nameList = list.stream().map(UserExcelData::getSupervisor).filter(StringUtils::isNotBlank).toList();
        List<UserImportDTO> supervisorList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(nameList)) {
            supervisorList = extOrganizationUserMapper.selectSupervisor(nameList, orgId);
        }

        List<User> userList = new ArrayList<>();
        List<OrganizationUser> organizationUsers = new ArrayList<>();
        List<UserImportDTO> finalSupervisorList = supervisorList;
        list.forEach(userData -> {
            buildUser(userData, operatorId, userList, departmentPathMap, orgId, organizationUsers, finalSupervisorList, logs);
        });

        userMapper.batchInsert(userList);
        organizationUserMapper.batchInsert(organizationUsers);

        logService.batchAdd(logs);
    }

    private void buildUser(UserExcelData userData, String operatorId, List<User> userList, Map<String, String> departmentPathMap, String orgId, List<OrganizationUser> organizationUsers, List<UserImportDTO> supervisorList, List<LogDTO> logs) {
        User user = new User();
        user.setId(IDGenerator.nextStr());
        user.setLastOrganizationId(orgId);
        user.setName(userData.getName());
        user.setPhone(userData.getPhone());
        user.setEmail(userData.getEmail());
        user.setPassword(CodingUtils.md5(userData.getPhone().substring(userData.getPhone().length() - 6)));
        user.setLanguage(Locale.SIMPLIFIED_CHINESE.toString());
        user.setGender(Boolean.valueOf(userData.getGender()));
        user.setCreateUser(operatorId);
        user.setCreateTime(System.currentTimeMillis());
        user.setUpdateUser(operatorId);
        user.setUpdateTime(System.currentTimeMillis());
        userList.add(user);

        OrganizationUser organizationUser = new OrganizationUser();
        organizationUser.setId(IDGenerator.nextStr());
        organizationUser.setOrganizationId(orgId);
        organizationUser.setDepartmentId(departmentPathMap.get("/" + userData.getDepartment()));
        organizationUser.setUserId(user.getId());
        organizationUser.setEnable(true);
        organizationUser.setEmployeeId(userData.getEmployeeId());
        organizationUser.setPosition(userData.getPosition());
        organizationUser.setEmployeeType(userData.getEmployeeType());
        organizationUser.setSupervisorId(handleSupervisor(supervisorList, organizationUser.getDepartmentId(), userData.getSupervisor()));
        organizationUser.setWorkCity(userData.getWorkCity());
        organizationUser.setCreateTime(System.currentTimeMillis());
        organizationUser.setCreateUser(operatorId);
        organizationUser.setUpdateTime(System.currentTimeMillis());
        organizationUser.setUpdateUser(operatorId);
        organizationUsers.add(organizationUser);


        LogDTO logDTO = new LogDTO(orgId, user.getId(), operatorId, LogType.ADD, LogModule.SYSTEM_ORGANIZATION, userData.getName());
        logDTO.setModifiedValue(user);
        logs.add(logDTO);

    }


    /**
     * 所属上级
     *
     * @param supervisorList
     * @param departmentId
     * @param name
     * @return
     */
    private String handleSupervisor(List<UserImportDTO> supervisorList, String departmentId, String name) {
        if (StringUtils.isBlank(name)) {
            return null;
        }
        List<UserImportDTO> departmentUsers = supervisorList.stream().filter(supervisor -> Strings.CI.equals(supervisor.getName(), name) && Strings.CI.equals(supervisor.getDepartmentId(), departmentId)).toList();
        if (CollectionUtils.isNotEmpty(departmentUsers)) {
            List<String> userIds = departmentUsers.stream().map(UserImportDTO::getUserId).toList();
            List<DepartmentCommander> commanders = extDepartmentCommanderMapper.selectCommanderByUsers(departmentId, userIds);
            if (CollectionUtils.isNotEmpty(commanders)) {
                return commanders.getFirst().getUserId();
            }
            return departmentUsers.getFirst().getUserId();
        }

        List<UserImportDTO> unDepartmentUsers = supervisorList.stream().filter(supervisor -> Strings.CI.equals(supervisor.getName(), name)).toList();
        if (CollectionUtils.isNotEmpty(unDepartmentUsers)) {
            return unDepartmentUsers.getFirst().getUserId();
        }
        return null;
    }


    /**
     * 导入校验电话号码唯一
     *
     * @param phone
     * @return
     */
    public boolean checkPhone(String phone) {
        return extUserMapper.countByPhone(phone, null) > 0;
    }

    /**
     * 导入校验邮箱唯一
     *
     * @param email
     * @return
     */
    public boolean checkEmail(String email) {
        return extUserMapper.countByEmail(email, null) > 0;
    }

    /**
     * 获取系统用户options
     *
     * @param orgId 组织ID
     * @return 用户选项列表
     */
    public List<OptionDTO> getUserOptions(String orgId) {
        List<String> allDpIds = getSortDepartmentIds(orgId);
        String defaultOrder = CollectionUtils.isEmpty(allDpIds) ? StringUtils.EMPTY : buildOrderByFieldClause(allDpIds);
        return extUserMapper.selectUserOptionByOrgId(orgId, defaultOrder);
    }


    /**
     * 删除用户（单个）
     *
     * @param id
     * @param orgId
     */
    @OperationLog(module = LogModule.SYSTEM_ORGANIZATION, type = LogType.DELETE, resourceId = "{#id}")
    public void deleteUserById(String id, String orgId) {
        UserResponse user = extUserMapper.getUserDetail(id);
        if (checkUserResource(user.getUserId())) {
            approvalActionService.refreshApprovingTasksForDisabledUser(List.of(user.getUserId()), orgId);
            //删除后该员工在系统上的全部数据将会被清理
            deleteUserAllData(user.getUserId(), id, orgId);
            // 踢出该用户
            SessionUtils.kickOutUser(SessionUtils.getUserId(), user.getUserId());
            // 添加日志上下文
            OperationLogContext.setResourceName(user.getUserName());
        } else {
            throw new GenericException(Translator.get("user_resource_exist"));
        }

        permissionCache.clearCache(user.getUserId(), orgId);
    }


    /**
     * 删除用户全部数据
     *
     * @param userId
     */
    private void deleteUserAllData(String userId, String id, String orgId) {
        OrganizationUser organizationUser = new OrganizationUser();
        organizationUser.setUserId(userId);
        if (organizationUserMapper.countByExample(organizationUser) == 1) {
            //删除主用户
            userMapper.deleteByPrimaryKey(userId);
        }
        //删除用户
        organizationUserMapper.deleteByPrimaryKey(id);
        //删除用户关联角色
        List<String> userRoleIds = extUserRoleMapper.selectUserRole(userId, orgId);
        if (CollectionUtils.isNotEmpty(userRoleIds)) {
            extUserRoleMapper.deleteByIds(userRoleIds);
        }

    }

    public boolean checkUserResource(String id) {
        return extOpportunityMapper.countByOwner(id) <= 0 &&
                extCustomerMapper.countByOwner(id) <= 0 &&
                extClueMapper.countByOwner(id) <= 0;
    }

    public boolean deleteCheck(String id) {
        UserResponse user = extUserMapper.getUserDetail(id);
        return checkUserResource(user.getUserId());
    }

    public List<OrganizationUser> getUserByOrgId(String orgId) {
        return extOrganizationUserMapper.getUserByOrgId(orgId);
    }

    public String getSupervisorName(String id) {
        User user = userMapper.selectByPrimaryKey(id);
        return Optional.ofNullable(user).map(User::getName).orElse(null);
    }


    @OperationLog(module = LogModule.SYSTEM_ORGANIZATION, type = LogType.UPDATE, operator = "{#operatorId}")
    public void updateUserName(UserUpdateName request, String operatorId) {
        User originUser = userMapper.selectByPrimaryKey(request.getUserId());

        User user = new User();
        user.setName(request.getName());
        user.setUpdateTime(System.currentTimeMillis());
        user.setUpdateUser(operatorId);
        user.setId(request.getUserId());
        userMapper.update(user);

        extOrganizationUserMapper.updateUserByUserId(user.getId(), System.currentTimeMillis(), operatorId);

        Map<String, String> originalVal = new HashMap<>(1);
        originalVal.put("name", originUser.getName());
        Map<String, String> modifiedVal = new HashMap<>(1);
        modifiedVal.put("name", request.getName());
        OperationLogContext.setContext(LogContextInfo.builder()
                .originalValue(originalVal)
                .resourceName(request.getName())
                .modifiedValue(modifiedVal)
                .resourceId(request.getUserId())
                .build());

    }

    /**
     * 获取单个部门下的用户
     *
     * @param departmentId
     * @param orgId
     * @return
     */
    public List<DeptUserTreeNode> getUserTreeByDepId(String departmentId, String orgId) {
        List<DeptUserTreeNode> treeNodes = extDepartmentMapper.selectDeptUserTreeNode(orgId);
        List<DeptUserTreeNode> userNodes = extUserRoleMapper.selectUserDeptForOrg(orgId);
        userNodes.forEach(userNode -> {
            if (!Strings.CS.equals(userNode.getParentId(), departmentId)) {
                userNode.setEnabled(false);
            }
        });
        userNodes.addAll(treeNodes);
        return BaseTreeNode.buildTree(userNodes);
    }

    private List<String> getSortDepartmentIds(String orgId) {
        List<String> sortDpIds = new ArrayList<>();
        List<BaseTreeNode> dTree = departmentService.getTree(orgId);
        if (CollectionUtils.isEmpty(dTree)) {
            return new ArrayList<>();
        }
        Deque<BaseTreeNode> stack = new ArrayDeque<>();
        stack.push(dTree.getFirst());

        while (!stack.isEmpty()) {
            BaseTreeNode currentNode = stack.pop();
            sortDpIds.add(currentNode.getId());
            List<BaseTreeNode> childrenList = currentNode.getChildren();
            if (CollectionUtils.isNotEmpty(childrenList)) {
                for (int i = childrenList.size() - 1; i >= 0; i--) {
                    stack.push(childrenList.get(i));
                }
            }
        }

        return sortDpIds;
    }

    public List<OptionDTO> getAdminUserOptions(String organizationId) {
        return extUserRoleMapper.selectUserOptionByRoleId(organizationId, InternalRole.ORG_ADMIN.getValue());
    }
}