package com.bcxin.tenant.domain.services.impls;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.bcxin.Infrastructures.ExceptionConstant;
import com.bcxin.Infrastructures.TenantContext;
import com.bcxin.Infrastructures.TenantUserContext;
import com.bcxin.Infrastructures.UnitWork;
import com.bcxin.Infrastructures.components.EventDispatcher;
import com.bcxin.Infrastructures.entities.OperatorValueType;
import com.bcxin.Infrastructures.enums.AbnormalPersonnelEmployeeType;
import com.bcxin.Infrastructures.enums.EmploymentStatus;
import com.bcxin.Infrastructures.enums.MasterSlaveType;
import com.bcxin.Infrastructures.enums.OccupationType;
import com.bcxin.Infrastructures.exceptions.*;
import com.bcxin.Infrastructures.utils.ExceptionUtil;
import com.bcxin.api.interfaces.commons.CommonImportResponse;
import com.bcxin.api.interfaces.rbacs.custom.response.RbacPermitOptionResponse;
import com.bcxin.tenant.domain.DomainConstraint;
import com.bcxin.tenant.domain.conditions.EmployeeLeaveCondition;
import com.bcxin.tenant.domain.conditions.TenantUserSameValidator;
import com.bcxin.tenant.domain.conditions.requests.TenantUserSameCheckRequest;
import com.bcxin.tenant.domain.configs.EnvConfig;
import com.bcxin.tenant.domain.configs.TenantUserConfig;
import com.bcxin.tenant.domain.entities.*;
import com.bcxin.tenant.domain.enums.EmployeeEventType;
import com.bcxin.tenant.domain.events.EmployeeUpdatedEvent;
import com.bcxin.tenant.domain.exceptions.EmployeeConflictException;
import com.bcxin.tenant.domain.exceptions.ExceptionCodeConstant;
import com.bcxin.tenant.domain.exceptions.TenantExceptionConverter;
import com.bcxin.tenant.domain.readers.TenantDbReader;
import com.bcxin.tenant.domain.readers.dtos.EmployeeBasicDto;
import com.bcxin.tenant.domain.readers.dtos.EmployeeConditionDto;
import com.bcxin.tenant.domain.repositories.*;
import com.bcxin.tenant.domain.services.EmployeeService;
import com.bcxin.tenant.domain.services.commands.*;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.sql.Timestamp;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class EmployeeServiceImpl implements EmployeeService {
    private final OrganizationRepository organizationRepository;
    private final UnitWork unitWork;
    private final DepartmentRepository departmentRepository;
    private final EmployeeRepository employeeRepository;
    private final CompositeDataRepository compositeDataRepository;
    private final TenantDbReader tenantDbReader;
    private final EventDispatcher eventDispatcher;
    private final EmployeeLeaveCondition condition;
     private final EnvConfig envConfig;
     private final TenantUserSameValidator tenantUserSameValidator;
    private final TenantAbnormalPersonnelRepository tenantAbnormalPersonnelRepository;
    private final TenantUserConfig tenantUserConfig;

    public EmployeeServiceImpl(OrganizationRepository organizationRepository,
                               UnitWork unitWork,
                               DepartmentRepository departmentRepository,
                               EmployeeRepository employeeRepository,
                               CompositeDataRepository compositeDataRepository,
                               TenantDbReader tenantDbReader, EventDispatcher eventDispatcher,
                               EmployeeLeaveCondition condition, EnvConfig envConfig,
                               TenantUserSameValidator tenantUserSameValidator,
                               TenantAbnormalPersonnelRepository tenantAbnormalPersonnelRepository,
                               TenantUserConfig tenantUserConfig) {
        this.organizationRepository = organizationRepository;
        this.unitWork = unitWork;
        this.departmentRepository = departmentRepository;
        this.employeeRepository = employeeRepository;
        this.compositeDataRepository = compositeDataRepository;
        this.tenantDbReader = tenantDbReader;
        this.eventDispatcher = eventDispatcher;
        this.condition = condition;
        this.envConfig = envConfig;
        this.tenantUserSameValidator = tenantUserSameValidator;
        this.tenantAbnormalPersonnelRepository = tenantAbnormalPersonnelRepository;
        this.tenantUserConfig = tenantUserConfig;
    }

    @Override
    public String dispatch(CreateEmployeeRequestCommand command) {
        //判断是否对账号进行手机号码校验
        boolean isRequiredPhoneAsLoginName =
                envConfig.isRequiredPhoneAsLoginName();

        Optional<OrganizationEntity> organizationOptional =
                this.organizationRepository.findById(command.getOrganizationId());
        if (!organizationOptional.isPresent()) {
            throw new NotFoundTenantException(String.format("组织(%s)信息无效!", command.getOrganizationId()));
        }

        OrganizationEntity organization = organizationOptional.get();

        command.validate(isRequiredPhoneAsLoginName, tenantUserConfig);

        //验证是否异常人员
        if (command.getAbnormalPersonnelEmployeeType().getCode() != AbnormalPersonnelEmployeeType.NOT_VERIFY.getCode()
                && StringUtils.hasLength(organization.getSuperviseRegionCode()) && organization.getSuperviseRegionCode().length()>1) {
            //只要不是：NOT_VERIFY，并且监管区域不为空，就需要校验是否异常人员
            String regionCode = organization.getSuperviseRegionCode().substring(0, 2).concat("0000");
            List<TenantAbnormalPersonnelEntity> abnormalPersonnelList =
                    tenantAbnormalPersonnelRepository.findByIdCardNumAndRestrictedRegionCode(command.getCredential().getNumber(), regionCode);
            if (CollectionUtil.isNotEmpty(abnormalPersonnelList)) {
                TenantAbnormalPersonnelEntity abnormalPersonnel = abnormalPersonnelList.get(0);
                //身份属于异常人员范围，需要判断限制类型
                int restrictedType = abnormalPersonnel.getRestrictedType();
                //如果入职的是一般职员，不管限制类型是什么，都是仅提醒
                if (command.getOccupationType() == OccupationType.Normal) {
                    //一般职员
                    restrictedType = 1;
                }

                if (restrictedType == 1) {
                    //仅提醒，需要判断前端有没有传确认信息
                    if (command.getAbnormalPersonnelEmployeeType().getCode() != AbnormalPersonnelEmployeeType.NEED_VERIFY_REMIND_CONFIRM.getCode()) {
                        //前端没传仅提醒确定入职
                        throw new AbnormalPersonnelException(ExceptionConstant.ABNORMAL_EMPLOYEE_REMIND_EXCEPTION_CODE, String.format("该人员【%s】为从业异常人员，是否确认录用！", command.getName()), null);
                    }
                } else if (restrictedType == 2) {
                    //限制入职，直接不让入职
                    throw new AbnormalPersonnelException(ExceptionConstant.ABNORMAL_EMPLOYEE_RESTRICTED_EXCEPTION_CODE, String.format("该人员【%s】不符合担任保安员，无法录入系统！", command.getName()), null);
                }
            }
        }

        /**
         * todo: 如果虽然我们启用telephone作为账号, 但是我们是不是也是可以以
         */
        this.tenantUserSameValidator.
                validate(Collections.singleton(TenantUserSameCheckRequest.create(
                command.getCredential().getType(),
                command.getCredential().getNumber(),
                command.getTelephone()
        )));

        DepartmentEntity department =
                this.getAndValidateDepartment(organization, command.getDepartId());

        AtomicReference<EmployeeEntity> employeeAto = new AtomicReference<>();
        Collection<UniqueDataConstraintEntity> uniqueDataConstraints = new ArrayList<>();
        try {
            this.unitWork.executeTran(() -> {
                employeeAto.set(
                        EmployeeEntity.create(
                                this.eventDispatcher,
                                organization,
                                department,
                                command.getName(),
                                command.getTelephone(),
                                command.getPassword(),
                                command.getPosition(),
                                command.getHiredDate(),
                                MasterSlaveType.Normal,
                                command.getCredential().getType(),
                                command.getCredential().getNumber(),
                                command.getOccupationType(),
                                true,
                                command.getOperator()));

                employeeRepository.save(employeeAto.get());

                employeeAto.get().dispatchAfterCreatedEvent(isRequiredPhoneAsLoginName);
            });

            return employeeAto.get().getId();
        } catch (Exception ex) {
            TenantExceptionAbstract tenantExceptionAbstract = TenantExceptionConverter.cast(ex);
            if (tenantExceptionAbstract != null && tenantExceptionAbstract instanceof ConflictTenantException) {
                /**
                 * todo: 针对所有有发生变更的Entity, 这边需要做下detach操作, 然后才能执行复职
                 */
                if (employeeAto.get() != null) {
                    this.unitWork.detach(employeeAto.get());
                }

                uniqueDataConstraints.forEach(udi -> {
                    this.unitWork.detach(udi);
                });
/*
                throw new ConflictTenantException("该职员已经存在!", tenantExceptionAbstract);
 */
                /**
                 * 如果该职员存在, 那么直接进行复职操作
                 */
                EmployeeEntity selectedEmployee
                        = this.employeeRepository.getByIdNum(organization.getId(), command.getCredential().getNumber());
                if (selectedEmployee == null) {
                    throw ex;
                }

                /**
                 * 针对此情况; 需要进行复职操作
                 */
                if (selectedEmployee.getStatus() == EmploymentStatus.OffJob) {
                    this.unitWork.executeTran(() -> {
                        this.departmentRepository
                                .clearDuplicatedEmployeeRelationByEmployeeIds(
                                        Collections.singleton(selectedEmployee.getId())
                                );

                        /**
                         * 执行复职操作
                         */
                        selectedEmployee.back(
                                this.eventDispatcher,
                                department,
                                command.getOccupationType(),
                                command.getHiredDate(),
                                command.getOperator(),
                                false
                        );

                        this.employeeRepository.save(selectedEmployee);
                    });
                }

                return selectedEmployee.getId();
            } else {
                throw tenantExceptionAbstract;
            }
        }
    }

    @Override
    public void dispatch(UpdateEmployeeRequestCommand command) {
        command.validate();
        Optional<EmployeeEntity> employeeOptional = this.employeeRepository.findById(command.getId());
        if (employeeOptional == null) {
            throw new NotFoundTenantException(String.format("职员(%s)无效", command.getId()));
        }

        EmployeeEntity employee = employeeOptional.get();

        Collection<DepartmentEntity> departments = this.getAndValidateDepartments(employee.getOrganization(), command.getDepartIds());
        if (departments != null && departments.size() > 0) {
            employee.joinDepartments(departments, MasterSlaveType.Normal);
        }

        EmployeeEntity superor = null;
        if (StringUtils.hasLength(command.getSuperiorId())) {
            superor = this.employeeRepository.getByOrganIdAndId(command.getOrganizationId(), command.getSuperiorId());

            if (superor == null) {
                throw new NotFoundTenantException("找不到上级信息");
            }
        }

        employee.change(command.getHiredTime(), command.getPosition(), command.getPositiveDate(), superor,
                command.getInterview(),command.getPersonStatus(),command.getProbation(),command.getPlanPositiveDate(),command.getSalary());

        this.unitWork.executeTran(() -> {
            this.employeeRepository.save(employee);
            this.eventDispatcher.dispatch(
                    EmployeeUpdatedEvent.create(employee, EmployeeEventType.Other,
                            Timestamp.from(Instant.now()), "修改信息"));
        });
    }

    @Override
    public void dispatch(BatchMoveEmployeesCommand command) {
        command.validate();

        Collection<EmployeeEntity> employeeEntities = this.employeeRepository.getByIds(command.getOrganId(), command.getEmployeeIds());
        Collection<String> notExistsEmployees = command.getEmployeeIds().stream().filter(emId ->
                !employeeEntities.stream().anyMatch(ix -> ix.getId().equals(emId))).collect(Collectors.toList());

        if (notExistsEmployees.size() > 0) {
            throw new BadTenantException(String.format("找不到职员(%s)信息", notExistsEmployees.stream().collect(Collectors.joining(","))));
        }

        Collection<DepartmentEntity> destDepartments = this.departmentRepository.getByIds(command.getOrganId(), Collections.singleton(command.getDestDepartId()));
        if (CollectionUtils.isEmpty(destDepartments)) {
            throw new BadTenantException(String.format("找不到该部门(%s)信息", command.getDestDepartId()));
        }

        try {
            this.unitWork.executeTran(() -> {
                DepartmentEntity department = destDepartments.stream().findFirst().get();
                employeeEntities.forEach(ix -> {
                    ix.move2Department(department);

                    this.employeeRepository.save(ix);

                    this.eventDispatcher.dispatch(
                            EmployeeUpdatedEvent.create(ix, EmployeeEventType.Other,
                                    Timestamp.from(Instant.now()), "转移部门"));
                });
            });
        } catch (Exception ex) {
            TenantExceptionAbstract exceptionAbstract = TenantExceptionConverter.cast(ex);
            if (exceptionAbstract instanceof ConflictTenantException) {
                this.unitWork.detachAll();

                String detailMsg = ExceptionUtil.getStackMessage(ex);
                if (detailMsg.contains(DomainConstraint.UNIQUE_DEPARTMENT_EMPLOYEE_RELATION_DEPARTMENT_EMPLOYEE)) {
                    this.unitWork.executeTran(() -> {
                        this.departmentRepository.clearDuplicatedEmployeeRelationByEmployeeIdsAndDepartId(command.getEmployeeIds(), command.getDestDepartId());
                    });

                    throw new RetryableTenantException("用户已经再该部门, 无法重复转移, 请进行删除", ex);
                }
            }

            throw exceptionAbstract;
        }
    }

    @Override
    public String dispatch(BatchImportEmployeeCommand command) {
        command.validate(tenantUserConfig);

        Optional<OrganizationEntity> organizationOptional =
                this.organizationRepository.findById(command.getOrganizationId());
        if (!organizationOptional.isPresent()) {
            throw new NotFoundTenantException("组织无效!");
        }
        OrganizationEntity organization = organizationOptional.get();

        TenantUserContext.UserModel currentUser = TenantContext.getInstance().getUserContext().get();
        if (currentUser == null) {
            throw new UnAuthorizedTenantException("当前用户无效");
        }
        boolean isMaster = currentUser.isMaster();
        boolean isDepartAdmin = currentUser.isDepartAdmin();

        if (!isMaster && !isDepartAdmin) {
            throw new UnAuthorizedTenantException("只有组织管理员或部门管理员有权限操作");
        }

        //验证导入的人员列表是否异常人员，如果有异常人员，则不让导入，需要手动一个一个添加入职
        if (StringUtils.hasLength(organization.getSuperviseRegionCode()) && organization.getSuperviseRegionCode().length()>1) {
            //监管区域取前2位
            String regionCode = organization.getSuperviseRegionCode().substring(0, 2).concat("0000");
            //取出批量入职的身份证列表
            List<String> numberList = command.getCommandItems().stream().map(commandItem -> commandItem.getDataItem().getCredentialNumber()).collect(Collectors.toList());
            //查询这批身份证列表，是否有人是异常人员
            List<TenantAbnormalPersonnelEntity> abnormalPersonnelList = tenantAbnormalPersonnelRepository.findByIdCardNumInAndRestrictedRegionCode(numberList, regionCode);
            if (CollectionUtil.isNotEmpty(abnormalPersonnelList)) {
                Map<String, List<TenantAbnormalPersonnelEntity>> abnormalPersonnelListMap = abnormalPersonnelList.stream().collect(Collectors.groupingBy(TenantAbnormalPersonnelEntity::getIdCardNum));
                for (BatchImportEmployeeCommand.EmployeeCommandItem commandItem : command.getCommandItems()) {
                    List<TenantAbnormalPersonnelEntity> personnelList = abnormalPersonnelListMap.get(commandItem.getDataItem().getCredentialNumber());
                    if (CollectionUtil.isNotEmpty(personnelList)) {
                        TenantAbnormalPersonnelEntity abnormalPersonnel = personnelList.get(0);
                        //身份属于异常人员范围，需要判断限制类型
                        int restrictedType = abnormalPersonnel.getRestrictedType();
                        //如果入职的是一般职员，不管限制类型是什么，都是仅提醒
                        if (commandItem.getOccupationType() == OccupationType.Normal) {
                            //一般职员
                            restrictedType = 1;
                        }
                        if (restrictedType == 1) {
                            //仅提醒，需要判断前端有没有传确认信息
                            commandItem.addError("该人员为从业异常人员，不能批量导入，请单个添加！");
                        } else if (restrictedType == 2) {
                            //限制入职，直接不让入职
                            commandItem.addError("该人员不符合担任保安员，无法录入系统！");
                        }
                    }
                }
            }
        }

        String importedDataId = this.compositeDataRepository.execute(organization, command);

        return importedDataId;
    }

    @Override
    public void dispatch(BatchLeaveEmployeeCommand command) {
        /**
         * 不严谨: 通过note的内容为自动离职来判断是否为自动离职
         */
        boolean isScheduledLeave =
                !StringUtils.isEmpty(command.getNote()) && command.getNote().contains("人员自动离职");
        /**
         * changed by lhc: 上级的功能未在业务中使用, 暂时不进行过滤操作.
         * 后续使用的时候进行另外的优化操作
        Collection<EmployeeBasicDto> superiorEmployeeBasics =
                this.tenantDbReader.getSuperiorEmployeeBasics(command.getOrganizationId(), command.getIds());
        if (!CollectionUtils.isEmpty(superiorEmployeeBasics)) {
            Collection<String> invalidIds = superiorEmployeeBasics.stream().map(ix -> ix.getId()).collect(Collectors.toList());
            String juniorName = "";
            List<String> juniorNameList = this.employeeRepository.findJuniorNameListBySuperiorId(invalidIds);
            if (CollectionUtil.isNotEmpty(juniorNameList)) {
                juniorName = String.join("；", juniorNameList);
            }
            throw new DataOperationTenantException(
                    String.format("该职员作为其他职员(%s)的上级，请转移上级上级身份后再试", juniorName),
                    ExceptionCodeConstant.LEAVE_HAS_CHILD_CODE, invalidIds);
        }
         */

        command.validate();
        if (!isScheduledLeave) {
            //不是自动离职的
            TenantUserContext userContext = TenantContext.getInstance().getUserContext();
            if (userContext != null && userContext.get() != null && userContext.get().getEmployeeId() != null) {
                if (command.getIds().contains(userContext.get().getEmployeeId())) {
                    throw new DataOperationTenantException(
                            "不允许为自己办理离职",
                            ExceptionCodeConstant.LEAVE_SELF_CODE, userContext.get().getEmployeeId());
                }
            }
        }

        Collection<EmployeeEntity> employees =
                this.employeeRepository.getByIds(command.getOrganizationId(), command.getIds());
        Collection<String> notExistsEmployees = command.getIds()
                .stream().filter(id -> !employees.stream().anyMatch(ix -> ix.getId().equals(id)))
                .collect(Collectors.toList());

        if (!CollectionUtils.isEmpty(notExistsEmployees)) {
            throw new NotFoundTenantException("找不到职员(%s)信息", notExistsEmployees.stream().collect(Collectors.joining(",")));
        }

        String offJobEmployeeIds =
                employees.stream().filter(ii -> ii.getStatus() == EmploymentStatus.OffJob)
                .map(ii -> ii.getId())
                .collect(Collectors.joining(","));
        if (StringUtils.hasLength(offJobEmployeeIds)) {
            throw new NotAllowedTenantException(String.format("该职员(%s)已经处于离职状态", offJobEmployeeIds));
        }

        /**
         * 当前操作者, 可以为当前用户/也可以是固定后台用户
         */
        String operateId = null;
        String operateName = null;
        if (!isScheduledLeave) {
            //不是自动离职的
            TenantUserContext.UserModel currentUser = TenantContext.getInstance().getUserContext().get();
            if (currentUser == null) {
                throw new ForbidTenantException("必须有人来操作离职");
            }
            operateId = currentUser.getId();
            operateName = currentUser.getName();
        } else {
            List<EmployeeEntity> adminList = employeeRepository.getAdminByOrganId(command.getOrganizationId());
            if (CollectionUtil.isNotEmpty(adminList)) {
                operateId = adminList.get(0).getTenantUser().getId();
                operateName = adminList.get(0).getTenantUser().getName();
            }
        }

        List<EmployeeConditionDto> conditionDtos =
                this.condition.matchLeaveCondition(command.getIds());
        if (conditionDtos != null && conditionDtos.size() > 0) {
            throw new NotAllowedTenantException(String.format("职员(%s)包括资格证、等级证, 资格证申报通过或申报不通过或已撤销/等级证【申报通过】或【申报不通过】或【申报中且确认成绩】或【已撤销】，才能进行离职", conditionDtos.stream().map(EmployeeConditionDto::getInfo).collect(Collectors.joining(", "))));
        }

        List<EmployeeConditionDto> attendSiteDtos =
                this.condition.matchForAttendSite(command.getIds());
        if (attendSiteDtos != null && attendSiteDtos.size() > 0) {
            throw new NotAllowedTenantException(attendSiteDtos.stream().map(EmployeeConditionDto::getInfo).collect(Collectors.joining(", ")));
        }

        OperatorValueType operator =
                OperatorValueType.create(operateId, operateName);
        this.unitWork.executeTran(() -> {
            for (EmployeeEntity employee : employees) {
                employee.leave(command.getExpectedDate(), command.getNote(), operator);
                this.employeeRepository.save(employee);
            }
        });
    }

    @Override
    public CommonImportResponse dispatch(BatchLeaveEmployeeExcelCommand command) {
        command.validate();
        Optional<OrganizationEntity> organizationOptional =
                this.organizationRepository.findById(command.getOrganizationId());
        if (!organizationOptional.isPresent()) {
            throw new NotFoundTenantException("组织无效!");
        }

        OrganizationEntity organization = organizationOptional.get();
        Collection<BatchLeaveEmployeeExcelCommand.EmployeeCommandItem> commandItems = command.getCommandItems();
        TenantUserContext.UserModel currentUser = TenantContext.getInstance().getUserContext().get();
        if (currentUser == null) {
            throw new UnAuthorizedTenantException("当前用户无效");
        }

        boolean isMaster = currentUser.isMaster();
        boolean isDepartAdmin = currentUser.isDepartAdmin();

        if (!isMaster && !isDepartAdmin) {
            throw new UnAuthorizedTenantException("只有组织管理员或部门管理员有权限操作");
        }

        List<String> myDeptEmployeeIdList = new ArrayList<>();
        if (!isMaster) {
            //不是组织管理员 && 是部门管理员
            myDeptEmployeeIdList = tenantDbReader.getMyDeptEmployeeIdList(command.getTreeCodes());
        }

        int successCount = 0, failedCount = 0, totalCount = 0;
        String msg = "";
        List<String> idnums = commandItems.stream().map(ii -> ii.getDataItem().getIdNum()).collect(Collectors.toList());
        Collection<EmployeeEntity> employees = employeeRepository.getByIdNums(command.getOrganizationId(), idnums);
        Map<String, EmployeeEntity> employeeMap = employees.stream().collect(Collectors.toMap(EmployeeEntity::getSelectIdNum, Function.identity()));
        List<String> ids = employees.stream().map(EmployeeEntity::getId).collect(Collectors.toList());
        List<EmployeeConditionDto> conditionDtos = this.condition.matchLeaveCondition(ids);
        Map<String, EmployeeConditionDto> conditionMap = conditionDtos.stream().collect(Collectors.toMap(EmployeeConditionDto::getEmployeeId, Function.identity()));
        List<EmployeeConditionDto> attendSiteDtos = this.condition.matchForAttendSite(ids);
        Map<String, EmployeeConditionDto> attendSiteConditionMap = attendSiteDtos.stream().collect(Collectors.toMap(EmployeeConditionDto::getEmployeeId, Function.identity()));
        for (BatchLeaveEmployeeExcelCommand.EmployeeCommandItem commandItem : commandItems) {
            totalCount++;
            EmployeeEntity entity = employeeMap.get(commandItem.getDataItem().getIdNum());
            if (entity == null) {
                commandItem.getDataItem().setErrMsg("用户不存在");
                failedCount++;
            } else if (entity.getId().equals(currentUser.getEmployeeId())) {
                //不允许为自己办理离职
                commandItem.getDataItem().setErrMsg("不允许为自己办理离职");
                failedCount++;
            } else if (!isMaster && !myDeptEmployeeIdList.contains(entity.getId())) {
                //不是组织管理员，需要判断部门员工权限
                commandItem.getDataItem().setErrMsg("该职员属于其他部门，无权限操作离职");
                failedCount++;
            } else if (StrUtil.isNotEmpty(commandItem.getErrorResult())) {
                failedCount++;
            } else {
                if (EmploymentStatus.OffJob.equals(entity.getStatus())) {
                    commandItem.getDataItem().setErrMsg("该职员已经处于离职状态");
                    failedCount++;
                    continue;
                }
                EmployeeConditionDto conditionDto = conditionMap.get(entity.getId());
                if (conditionDto != null) {
                    commandItem.getDataItem().setErrMsg("该职员包括资格证、等级证, 资格证申报通过或申报不通过或已撤销/等级证【申报通过】或【申报不通过】或【申报中且确认成绩】或【已撤销】，才能进行离职");
                    failedCount++;
                    continue;
                }
                conditionDto = attendSiteConditionMap.get(entity.getId());
                if (conditionDto != null) {
                    commandItem.getDataItem().setErrMsg(conditionDto.getInfo());
                    failedCount++;
                    continue;
                }

                //判断是否保存成功
                try {
                    this.unitWork.executeTran(() -> {
                        entity.leave(commandItem.getDataItem().getLeaveDate(), commandItem.getDataItem().getRemark(), OperatorValueType.create(currentUser.getId(), currentUser.getName()));
                        this.employeeRepository.save(entity);
                    });
                    successCount++;
                } catch (TenantExceptionAbstract e) {
                    failedCount++;
                    String eMessage = e.getMessage();
                    commandItem.getDataItem().setErrMsg(eMessage);
                    this.unitWork.detach(entity);
                }
            }
        }
        String importedDataId = this.compositeDataRepository.execute(organization, command);
        if (failedCount != 0) {
            msg = "部分数据未成功离职";
        }
        if (successCount == commandItems.size()) {
            msg = "离职成功";
        }
        CommonImportResponse commonImportResponse = CommonImportResponse.create(importedDataId, totalCount, successCount, failedCount, msg);
        return commonImportResponse;
    }

    @Override
    public void dispatch(BackEmployeeCommand command) {
        command.validate(tenantUserConfig);

        Collection<EmployeeEntity> employees =
                this.employeeRepository.getByIds(
                        command.getOrganizationId(),
                        Collections.singleton(command.getId()));

        if (CollectionUtils.isEmpty(employees)) {
            throw new NotFoundTenantException("找不到该职员信息");
        }

        /**
         * 开始验证该人员是否出现同一个省份多种职业类型的情况
         * todo: 系统暂时不支持调整跨省份的监管归属的情况, 因此, 可以暂时忽略
         */
        EmployeeEntity selectedEmployee = employees.stream().findFirst().get();
        if(selectedEmployee.getStatus()!=EmploymentStatus.OffJob) {
            throw new NotAllowedTenantException("该职员已经在职; 无法重复复职");
        }

        Collection<DepartmentEntity> departments =
                this.departmentRepository.getByIds(command.getOrganizationId(),
                        Collections.singleton(command.getDepartId()));

        departments = departments.stream().filter(ix -> !ix.isDeleted())
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(departments)) {
            throw new NotFoundTenantException("找不到该部门信息");
        }

        DepartmentEntity selectedDepart =
                departments
                        .stream().findFirst().get();
        this.unitWork.executeTran(() -> {
            this.departmentRepository
                    .clearDuplicatedEmployeeRelationByEmployeeIds(
                            Collections.singleton(selectedEmployee.getId())
                    );

            /**
             * 执行复职操作
             */
            selectedEmployee.back(
                    this.eventDispatcher,
                    selectedDepart,
                    command.getOccupationType(),
                    command.getHiredDate(),
                    command.getOperator(),
                    false
            );

            this.employeeRepository.save(selectedEmployee);
        });
    }

    @Override
    public void dispatch(BatchAssignEmployeeSuperiorCommand command) {
        command.validate();

        Collection<String> ids = command.getComputedIds();
        Collection<EmployeeEntity> selectedEmployees =
                this.employeeRepository.getByIds(command.getOrganizationId(), ids);

        Collection<String> notExistsEmployeeIds = ids.stream().filter(ii -> !selectedEmployees.stream().anyMatch(ix -> ix.getId().equals(ii)))
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(notExistsEmployeeIds)) {
            throw new NotFoundTenantException("找不到职员(%s)信息", notExistsEmployeeIds.stream().collect(Collectors.joining(",")));
        }

        this.unitWork.executeTran(() -> {
            command.getItems().stream().forEach(item -> {
                String newSuperiorId = item.getNewSuperiorId();
                if (!StringUtils.hasLength(newSuperiorId)) {
                    newSuperiorId = null;
                }

                this.employeeRepository.replaceSuperior(command.getOrganizationId(), item.getOriginalSuperiorId(), newSuperiorId);
            });
        });
    }

    private DepartmentEntity getAndValidateDepartment(OrganizationEntity organization, String id) {
        if (!StringUtils.hasLength(id)) {
            return null;
        }

        Collection<DepartmentEntity> departments = this.departmentRepository.getByIds(organization.getId(), Collections.singleton(id));
        if (CollectionUtils.isEmpty(departments)) {
            throw new NotFoundTenantException(String.format("部门(%s)信息无效!", id));
        }

        return departments.stream().findFirst().get();
    }

    private Collection<DepartmentEntity> getAndValidateDepartments(OrganizationEntity organization, Collection<String> departIds) {
        if (departIds == null || departIds.size() == 0) {
            return null;
        }

        Collection<DepartmentEntity> departments = this.departmentRepository.getByIds(organization.getId(), departIds);
        if (CollectionUtils.isEmpty(departments) || departments.size() != departIds.size()) {
            throw new NotFoundTenantException(String.format("部门(%s)信息无效!", departIds.stream().collect(Collectors.joining(", "))));
        }

        return departments;
    }
}
