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

import com.alibaba.excel.util.DateUtils;
import com.alibaba.fastjson.JSON;
import com.bcxin.Infrastructures.TenantContext;
import com.bcxin.Infrastructures.UnitWork;
import com.bcxin.Infrastructures.components.EventDispatcher;
import com.bcxin.Infrastructures.components.JsonProvider;
import com.bcxin.Infrastructures.components.LockProvider;
import com.bcxin.Infrastructures.components.RetryProvider;
import com.bcxin.Infrastructures.enums.*;
import com.bcxin.Infrastructures.exceptions.*;
import com.bcxin.Infrastructures.utils.ExceptionUtil;
import com.bcxin.api.interfaces.buses.MessageRpcProvider;
import com.bcxin.api.interfaces.buses.enums.MessageType;
import com.bcxin.api.interfaces.buses.requests.MessageRequest;
import com.bcxin.api.interfaces.commons.PlatformOperateLogRpcProvider;
import com.bcxin.api.interfaces.identities.IdentityRpcProvider;
import com.bcxin.api.interfaces.tenants.requests.employees.ResetPassWordRequest;
import com.bcxin.api.interfaces.tenants.requests.operatelog.PlatformOperateLogRequest;
import com.bcxin.api.interfaces.tenants.requests.organizations.LocationRequest;
import com.bcxin.tenant.domain.DomainConstraint;
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.entities.valueTypes.ItemValueType;
import com.bcxin.tenant.domain.entities.valueTypes.LocationValueType;
import com.bcxin.tenant.domain.enums.EventAction;
import com.bcxin.tenant.domain.enums.EventProcessedStatus;
import com.bcxin.tenant.domain.events.TenantUserAfterCreatedEvent;
import com.bcxin.Infrastructures.exceptions.ConfirmCheckStatusException;
import com.bcxin.tenant.domain.exceptions.TenantExceptionConverter;
import com.bcxin.tenant.domain.readers.TenantDbReader;
import com.bcxin.tenant.domain.repositories.TenantEventRepository;
import com.bcxin.tenant.domain.repositories.TenantUserAppealsRepository;
import com.bcxin.tenant.domain.repositories.TenantUserRepository;
import com.bcxin.tenant.domain.repositories.UniqueDataConstraintRepository;
import com.bcxin.tenant.domain.services.TenantEventService;
import com.bcxin.tenant.domain.services.TenantUserService;
import com.bcxin.tenant.domain.services.commands.BatchCreateTenantUserCommand;
import com.bcxin.tenant.domain.services.commands.CreateTenantUserByEmployeeCommand;
import com.bcxin.tenant.domain.services.commands.SyncTenantUserLocationCommand;
import com.bcxin.tenant.domain.services.commands.UpdateTenantUserCommand;
import com.bcxin.tenant.domain.services.commands.tenantUsers.*;
import com.bcxin.tenant.domain.utils.PassAssembleUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class TenantUserServiceImpl implements TenantUserService {
    private final Logger logger = LoggerFactory.getLogger(TenantUserServiceImpl.class);

    private final TenantUserRepository tenantUserRepository;
    private final TenantUserAppealsRepository tenantUserAppealsRepository;
    private final UnitWork unitWork;
    private final RetryProvider retryProvider;
    private final JsonProvider jsonProvider;
    private final TenantEventService eventService;
    private final EventDispatcher eventDispatcher;
    private final TenantEventRepository eventRepository;
    private final MessageRpcProvider messageRpcProvider;
    private final TenantUserConfig tenantUserConfig;
    private final EnvConfig envConfig;
    private final LockProvider lockProvider;
    private final TenantDbReader dbReader;
    private final PlatformOperateLogRpcProvider platformOperateLogRpcProvider;
    private final IdentityRpcProvider identityRpcProvider;

    public TenantUserServiceImpl(TenantUserRepository tenantUserRepository,
                                 PlatformTransactionManager transactionManager,
                                 UnitWork unitWork,
                                 UniqueDataConstraintRepository uniqueDataConstraintRepository,
                                 TenantUserAppealsRepository tenantUserAppealsRepository,
                                 RetryProvider retryProvider,
                                 JsonProvider jsonProvider,
                                 TenantDbReader dbReader,
                                 TenantEventService eventService,
                                 EventDispatcher eventDispatcher,
                                 TenantEventRepository eventRepository,
                                 MessageRpcProvider messageRpcProvider,
                                 TenantUserConfig tenantUserConfig,
                                 EnvConfig envConfig,
                                 LockProvider lockProvider,
                                 PlatformOperateLogRpcProvider platformOperateLogRpcProvider,
                                 IdentityRpcProvider identityRpcProvider) {
        this.tenantUserRepository = tenantUserRepository;
        this.unitWork = unitWork;
        this.tenantUserAppealsRepository = tenantUserAppealsRepository;
        this.retryProvider = retryProvider;
        this.jsonProvider = jsonProvider;
        this.eventService = eventService;
        this.eventDispatcher = eventDispatcher;
        this.eventRepository = eventRepository;
        this.messageRpcProvider = messageRpcProvider;
        this.tenantUserConfig = tenantUserConfig;
        this.envConfig = envConfig;
        this.lockProvider = lockProvider;
        this.dbReader = dbReader;
        this.platformOperateLogRpcProvider = platformOperateLogRpcProvider;
        this.identityRpcProvider = identityRpcProvider;
    }

    /**
     * 新增租户信息的时候，直接采用约束来替换判断的方式
     * 考虑mpp数据库的问题: 通过uniqueDataConstraintRepository来解决
     * 添加唯一性约束（必须再建表的时候指定好）
     *
     * @param command
     */
    @Override
    public void create(CreateTenantUserByEmployeeCommand command) {
        AtomicReference<TenantUserEntity> tenantUserAto = new AtomicReference<>();
        Collection<UniqueDataConstraintEntity> uniqueDataConstraintEntities = new ArrayList<>();
        /**
         * isRequiredPhoneAsLoginName=true的仅针对内网和RT环境
         * changed by lhc: 2023-07-17 调整职业类型的时候; 优化调整判断逻辑
         */

        try {
            this.unitWork.executeNewTran(() -> {
                TenantUserEntity finalTenantUser = TenantUserEntity.createImport(this.eventService,
                        command.getName(),
                        command.getTelephone(),
                        command.getSex(),
                        command.getBirthdate(),
                        command.getNation(),
                        command.getEducation(),
                        command.getPoliticsStatus(),
                        command.getMilitaryStatus(),
                        command.getMaritalStatus(),
                        command.getEmergencyContact(),
                        command.getEmergencyPhone(),
                        command.getAddress(),
                        command.getHouseholdType());

                //判断是不是内网 内网加上这个
                if (tenantUserConfig.isIntranet()) {
                    finalTenantUser.assignThirdPartyLoginNo(this.generateThirdPartyLoginNo());
                }

                /**
                 * 确保手机号码唯一
                 */
//                UniqueDataConstraintEntity dataConstraintEntity = this.uniqueDataConstraintRepository.create("tenant_user", command.getTelephone());
//                uniqueDataConstraintEntities.add(dataConstraintEntity);
                if (StringUtils.hasLength(command.getCredentialNumber())) {
                    /**
                     * 确保证件号码唯一
                     */
//                    dataConstraintEntity = this.uniqueDataConstraintRepository.create("tenant_user_credential",
//                            String.format("type:%s;number:%s", command.getCredentialType(), command.getCredentialNumber()));
//                    uniqueDataConstraintEntities.add(dataConstraintEntity);
                    finalTenantUser.addCredential(command.getCredentialType(), command.getCredentialNumber(), true);
                }

                this.tenantUserRepository.save(finalTenantUser);
                tenantUserAto.set(finalTenantUser);
            });

            /**
             * 用于事后租户用户创建的消息通知
             */
            if (tenantUserAto.get() != null) {
                this.eventDispatcher.dispatch(TenantUserAfterCreatedEvent.create(tenantUserAto.get()));
            }
        } catch (Exception ex) {
            TenantExceptionAbstract tenantException = TenantExceptionConverter.cast(ex);
            if (tenantException instanceof ConflictTenantException) {
                if (tenantUserAto.get() != null) {
                    this.unitWork.detach(tenantUserAto.get());
                    uniqueDataConstraintEntities.forEach(ii -> {
                        this.unitWork.detach(ii);
                    });
                }
                tenantUserAto.set(this.tenantUserRepository.getByIdNum(command.getCredentialNumber(), command.getCredentialType()));
                if (tenantUserAto.get() == null) {
                    ex.printStackTrace();
                    throw new BadTenantException(String.format("该证件信息(%s)已经被其他用户注册!", command.getCredentialNumber()));
                }
            } else {
                ex.printStackTrace();
                throw ex;
            }
        } finally {
            /**
             * 传递当前的租户信息
             */
            if (tenantUserAto.get() != null) {
                TenantContext.getInstance().setValue(command.getEmployee(), tenantUserAto.get());
                this.unitWork.detach(tenantUserAto.get());
            }
        }
    }

    /**
     * 批量新增租户信息
     *
     * @param command
     * @return
     */
    @Override
    public Collection<TenantUserEntity> create(BatchCreateTenantUserCommand command) {
        Collection<TenantUserEntity> existsTenantUsers = new ArrayList<>();
        retryProvider.execute(() -> {
            executeCreate(command, existsTenantUsers);
            if (command.getItems().stream().anyMatch(ix -> !existsTenantUsers.stream().anyMatch(ext -> ext.getSelectedCredential().getNumber().equals(ix.getCredentialNumber())))) {
                throw new RetryableTenantException();
            }
        }, 3);

        return existsTenantUsers;
    }

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

        Optional<TenantUserEntity> userOptional = this.tenantUserRepository.findById(command.getId());
        if (!userOptional.isPresent()) {
            throw new NotFoundTenantException("找不到该用户信息");
        }

        TenantUserEntity userEntity = userOptional.get();
        userEntity.change(
                command.getSex(),
                command.getNation(),
                command.getDiseasesHistory(),
                command.getWorkYear(),
                command.getPoliticsStatus(),
                command.getStature(),
                command.getMilitaryStatus(),
                command.getBirthdate(),
                command.getEducation(),
                command.getHouseholdType(),
                command.getNativePlace(),
                command.getMaritalStatus(),
                command.getEmergencyContact(),
                command.getEmergencyPhone(),
                command.getLicenseLevel(),
                command.getPlaceOfNow() != null ? translateLocationItem(command.getPlaceOfNow()) : null);
        userEntity.changeEmail(command.getEmail());

        this.unitWork.executeTran(() -> {
            this.tenantUserRepository.save(userEntity);
        });
    }

    private LocationValueType translateLocationItem(LocationRequest locationRequest) {
        return LocationValueType.create(
                translateItemValueItem(locationRequest.getProvince() == null ? null : locationRequest.getProvince()),
                translateItemValueItem(locationRequest.getCity() == null ? null : locationRequest.getCity()),
                translateItemValueItem(locationRequest.getDistrict() == null ? null : locationRequest.getDistrict()),
                locationRequest.getAddress()
        );
    }

    private ItemValueType translateItemValueItem(LocationRequest.ItemValueRequest itemValueRequest) {
        if (itemValueRequest == null) {
            return ItemValueType.create(null, null);
        }

        return ItemValueType.create(itemValueRequest.getCode(), itemValueRequest.getName());
    }

    @Override
    public void dispatch(SyncTenantUserLocationCommand command) {
        Optional<TenantUserEntity> tenantUserOptional = this.tenantUserRepository.findById(command.getId());
        if (!tenantUserOptional.isPresent()) {
            throw new NotFoundTenantException("找不到用户信息");
        }

        TenantUserEntity tenantUser = tenantUserOptional.get();
        this.unitWork.executeTran(() -> {
            tenantUser.changeLocation(command.getLatitude(), command.getLongitude(), this.jsonProvider);
            this.tenantUserRepository.save(tenantUser);
        });
    }

    @Override
    public void dispatch(SyncDeviceCommand command) {
        if (!StringUtils.hasLength(command.getCid())) {
            return;
        }

        Optional<TenantUserEntity> tenantUserOptional = this.tenantUserRepository.findById(command.getUserId());
        if (!tenantUserOptional.isPresent()) {
            throw new NotFoundTenantException("找不到用户信息");
        }

        TenantUserEntity tenant = tenantUserOptional.get();
        if (!StringUtils.hasLength(tenant.getCid()) || !tenant.getCid().equalsIgnoreCase(command.getCid())) {
            this.unitWork.executeTran(() -> {
                tenant.changeDeviceId(command.getCid());
                this.tenantUserRepository.save(tenant);
            });
        }
    }

    @Override
    public void dispatch(SyncWechatLabelCommand command) {
        command.validate();
        Optional<TenantUserEntity> tenantUserOptional = this.tenantUserRepository.findById(command.getId());
        if (!tenantUserOptional.isPresent()) {
            throw new NotFoundTenantException("当前用户无效");
        }
        tenantUserOptional.get().changeWechat(command.getOpenId(), command.getNicky());

        this.unitWork.executeTran(() -> {
            this.tenantUserRepository.save(tenantUserOptional.get());
        });
    }

    @Override
    public void dispatch(UpdateBasicTenantUserCommand command) {
        command.validate(envConfig.isRequiredPhoneAsLoginName());
        Optional<TenantUserEntity> tenantUserOptional = this.tenantUserRepository.findById(command.getId());
        if (!tenantUserOptional.isPresent()) {
            throw new NotFoundTenantException("找不到用户信息");
        }

        TenantUserEntity tenantUser = tenantUserOptional.get();
        /*if(!command.getTelephone().equals(tenantUser.getTelephone())) {
            if (this.dbReader.checkIfTelephoneExists(command.getTelephone()) > 0) {
                throw new NotAllowedTenantException("该手机号已经被他人使用");
            }
        }*/

        this.unitWork.executeTran(() -> {
            //一定要放在这边，以确保是同一个事务
            tenantUser.changeBasic(command.getName(), command.getTelephone());

            this.tenantUserRepository.save(tenantUser);
        });
    }

    public void dispatch(UpdateCredentialCommand command) {
        Optional<TenantUserEntity> tenantUserOptional = this.tenantUserRepository.findById(command.getId());
        if (!tenantUserOptional.isPresent()) {
            throw new NotFoundTenantException("找不到用户信息");
        }
        TenantUserEntity tenantUser = tenantUserOptional.get();
        this.unitWork.executeTran(() -> {
            tenantUser.changeCredential(
                    command.getHeadPhoto(),
                    command.getFrontPhoto(),
                    command.getReversePhoto(),
                    command.getAddress(),
                    command.getValidDateFrom(),
                    command.getValidDateTo()
            );
            this.tenantUserRepository.save(tenantUser);
        });
    }

    @Override
    public void dispatch(UpdateUserCredentialCommand command) {
        command.validate();
        Optional<TenantUserEntity> tenantUserOptional = this.tenantUserRepository.findById(command.getId());
        if (!tenantUserOptional.isPresent()) {
            throw new NotFoundTenantException("找不到用户信息");
        }
        TenantUserEntity tenantUser = tenantUserOptional.get();

        try {
            this.unitWork.executeTran(() -> {
                tenantUser.changeCredential(
                        command.getName(),
                        command.getCredentialType(),
                        command.getHeadPhoto(),
                        command.getNumber(),
                        command.getValidDateFrom(),
                        command.getValidDateTo(),
                        command.getFrontPhoto(),
                        command.getReversePhoto(),
                        command.getAddress(),
                        command.isFromMobile(),
                        command.getCertificateImage()
                );

                Sex sex = getSexByCredential(command.getCredentialType(), command.getNumber());
                Date birthdate = getBirthdateByCredential(command.getCredentialType(), command.getNumber());
                if (sex != null) {
                    tenantUser.changeSex(sex);
                }
                if (birthdate != null) {
                    tenantUser.changeBirthdate(birthdate);
                }

                this.assignHistoryCredential(command.getNumber(), tenantUser);
                this.tenantUserRepository.save(tenantUser);
                tenantUser.recordCredentialChangeEvent();

            });
        } catch (Exception ex) {
            String detailEx = ExceptionUtil.getStackMessage(ex);
            if (detailEx.contains(DomainConstraint.UNIQUE_TENANT_USER_CREDENTIAL_NUMBER)) {
                throw new ConflictTenantException("该证件号已被注册。若需要将该证件号码所属人员入职到组织下，请通过新增用户功能入职。本条数据可离职移除。", ex);
            }

            throw ex;
        }
    }

    private static Sex getSexByCredential(CredentialType credentialType, String credentialNumber) {
        Sex sex = null;
        if (credentialType.ordinal() == CredentialType.IdCard.ordinal() && StringUtils.hasLength(credentialNumber)) {
            //证件类型是身份证，需要根据身份证号码，获取出生日期、性别
            String sexText = "";
            if (credentialNumber.length() == 15) {
                //15位身份证
                sexText = credentialNumber.substring(14);
            } else if (credentialNumber.length() == 18) {
                //18位身份证
                sexText = credentialNumber.substring(16, 17);
            } else {
                throw new ArgumentTenantException("身份证号码格式错误");
            }
            sex = isEvenNumber(Integer.parseInt(sexText)) ? Sex.Female : Sex.Male;
        }
        return sex;
    }

    private static Date getBirthdateByCredential(CredentialType credentialType, String credentialNumber) {
        Date birthdate = null;
        if (credentialType.ordinal() == CredentialType.IdCard.ordinal() && StringUtils.hasLength(credentialNumber)) {
            //证件类型是身份证，需要根据身份证号码，获取出生日期、性别
            String birthdateText = "";
            if (credentialNumber.length() == 15) {
                //15位身份证
                birthdateText = "19" + credentialNumber.substring(6, 12);
            } else if (credentialNumber.length() == 18) {
                //18位身份证
                birthdateText = credentialNumber.substring(6, 14);
            } else {
                throw new ArgumentTenantException("身份证号码格式错误");
            }
            try {
                birthdate = DateUtils.parseDate(birthdateText, "yyyyMMdd");
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return birthdate;
    }

    private static boolean isEvenNumber(int num) {
        if (num == 0)
            return true;
        else if (num % 2 == 0)
            return true;
        else
            return false;
    }

    private void assignHistoryCredential(String idCardNum,TenantUserEntity tenantUser) {
        //查询所有未绑定的证书信息
        if (StringUtils.hasLength(idCardNum)) {
            List<String> idNums = Stream.of(idCardNum).collect(Collectors.toList());

            this.tenantUserRepository.updateCredentialDetailsTenantUserId(idNums, tenantUser.getId());
        }
    }

    @Override
    public void dispatch(UpdateUserPhotoCommand command) {
        command.validate();
        Optional<TenantUserEntity> tenantUserOptional = this.tenantUserRepository.findById(command.getId());
        if (!tenantUserOptional.isPresent()) {
            throw new NotFoundTenantException("当前用户信息无效(找不到)");
        }

        TenantUserEntity tenantUser = tenantUserOptional.get();

        this.unitWork.executeTran(() -> {
            tenantUser.changePhoto(command.getOneInchColorWhitePhoto(), command.getTwoInchColorBluePhoto());
            this.tenantUserRepository.save(tenantUser);
        });
    }

    @Override
    public void dispatch(RedoAuthorizationCommand command) {
        command.validate();
        Optional<TenantUserEntity> tenantUserOptional = this.tenantUserRepository.findById(command.getId());
        if (!tenantUserOptional.isPresent()) {
            throw new NotFoundTenantException("当前用户信息无效(找不到)");
        }

        this.unitWork.executeTran(() -> {
            tenantUserOptional.get().redoAuthenticate();
            this.tenantUserRepository.save(tenantUserOptional.get());
        });
    }

    @Override
    public void dispatch(NotifyNewUserCommand command) {
        AtomicReference<TenantUserEntity> tenantUserAtomic = new AtomicReference<>();

        this.retryProvider.execute(() -> {
            Optional<TenantUserEntity> tenantUserOptional = this.tenantUserRepository.findById(command.getId());
            if (tenantUserOptional.isPresent()) {
                tenantUserAtomic.set(tenantUserOptional.get());
            } else {
                throw new RetryableTenantException();
            }
        }, 10);

        TenantUserEntity tenantUser = tenantUserAtomic.get();

        this.lockProvider.execute(String.format("nf_%s", command.getEventId()), () -> {
            Optional<TenantEventEntity> tenantEventOptional = this.eventRepository.findById(command.getEventId());
            if (!tenantEventOptional.isPresent()) {
                return;
            }

            if (tenantEventOptional.get().getEventAction() != EventAction.TenantUserAfterCreatedEventForSms) {
                throw new BadTenantException(String.format("程序有误, 该事件(%s, %s)并不是处理SMS消息内容",
                        tenantEventOptional.get().getId(), tenantEventOptional.get().getEventAction()));
            }
            TenantEventEntity selectedTenantEvent = tenantEventOptional.get();
            if (selectedTenantEvent.getStatus() == EventProcessedStatus.Processed) {
                logger.error("重复短信-该短信之前已经发送过(id={})", selectedTenantEvent.getId());
                return;
            }

            // 配置的密码前缀+身份证后六位
            String pass = PassAssembleUtils.assemble(tenantUser.getSelectIdNum(), envConfig.getPassPrefix());
            Map<String, Object> huaWeiSmsContent = new HashMap<>();
            huaWeiSmsContent.put("smsCode", "B98");
            List<String> sendParams = new ArrayList();
            sendParams.add(pass);
            /*sendParams.add(tenantUser.getName());
            sendParams.add(tenantUser.getSelectIdNum());
            sendParams.add("账号后六位");
            sendParams.add("http://www.baibaodun.cn/a");*/
            huaWeiSmsContent.put("params", JSON.toJSONString(sendParams));

            String telephone = tenantUser.getTelephone();
            huaWeiSmsContent.put("mobile", telephone);

            this.messageRpcProvider.dispatch(MessageRequest.create(
                    MessageType.SMS, huaWeiSmsContent
            ));

            this.unitWork.executeNewTran(() -> {
                selectedTenantEvent.done("事件消费成功-短信发送成功");
                this.eventRepository.save(selectedTenantEvent);
            });
        });
    }

    /**
     * 避免查询，执行插入->报错->重置->插入
     * todo 考虑mpp数据库不支持唯一性约束的问题
     *
     * @param command
     * @param existsTenantUsers
     */
    private void executeCreate(BatchCreateTenantUserCommand command, Collection<TenantUserEntity> existsTenantUsers) {
        Collection<TenantUserEntity> finalExistsTenantUsers = this.tenantUserRepository.findAllByNumbers(command.getItems().stream().map(BatchCreateTenantUserCommand.TenantUserCommandItem::getCredentialNumber).collect(Collectors.toList()));
        Map<String, TenantUserEntity> userMap = new HashMap<>();
        if (finalExistsTenantUsers.size() > 0) {
            userMap = finalExistsTenantUsers.stream().collect(Collectors.toMap(TenantUserEntity::getSelectIdNum, Function.identity()));
        }

        Collection<TenantUserEntity> newTenantUserEntities = new ArrayList<>();
        try {
            Map<String, TenantUserEntity> finalUserMap = userMap;
            this.unitWork.executeTran(() -> {
                for (BatchCreateTenantUserCommand.TenantUserCommandItem item : command.getItems()) {
                    if (finalUserMap.get(item.getCredentialNumber()) != null) {
                        continue;
                    }
                    TenantUserEntity tenantUser = TenantUserEntity.create(this.eventService, item.getName(), item.getTelephone(),false);
                    //判断环境，生成第三方登录标识
                    if (tenantUserConfig.isIntranet()) {
                        tenantUser.assignThirdPartyLoginNo(this.generateThirdPartyLoginNo());
                    }
                    /**
                     * 添加默认证书
                     */
                    tenantUser.addCredential(item.getCredentialType(), item.getCredentialNumber(), true);

                    Sex sex = getSexByCredential(item.getCredentialType(), item.getCredentialNumber());
                    Date birthdate = getBirthdateByCredential(item.getCredentialType(), item.getCredentialNumber());
                    if (sex != null) {
                        tenantUser.changeSex(sex);
                    }
                    if (birthdate != null) {
                        tenantUser.changeBirthdate(birthdate);
                    }

                    newTenantUserEntities.add(tenantUser);
                    finalExistsTenantUsers.add(tenantUser);
                    this.tenantUserRepository.save(tenantUser);
                }
            });
            existsTenantUsers.clear();
            existsTenantUsers.addAll(finalExistsTenantUsers);
            /**
             * 用于事后租户用户创建的消息通知
             */
            for (TenantUserEntity tenantUser : newTenantUserEntities) {
                this.eventDispatcher.dispatch(TenantUserAfterCreatedEvent.create(tenantUser));
            }
        } catch (Exception ex) {
            if (ex.toString().contains(DomainConstraint.UNIQUE_TENANT_USER_CREDENTIAL_NUMBER)) {
                throw new RetryableTenantException();
            }

            throw ex;
        }
    }

    private String generateThirdPartyLoginNo() {
        String code = tenantUserConfig.getCode();
        int count = 999999;
        while (count > 0) {

            String str = System.currentTimeMillis() + "";
            String value = code + str.substring(str.length() - 6);
            TenantUserEntity tenantUserEntity = tenantUserRepository.getByThirdPartyLoginNo(value);
            if (tenantUserEntity == null) {
                return value;
            }
            count--;

        }
        return "";

    }


    @Override
    public void createAppeal(CreateAuthAppealCommand command) {
        if (StringUtils.isEmpty(command.getId())) {
            throw new ArgumentTenantException("人员id不能为空");
        }
        if (StringUtils.isEmpty(command.getAppealPhoto())) {
            throw new ArgumentTenantException("申诉图片不能为空");
        }
        if (StringUtils.isEmpty(command.getRegionCode())) {
            throw new ArgumentTenantException("公司区域编码不能为空");
        }
        Optional<TenantUserEntity> tenantUserOpt = tenantUserRepository.findById(command.getId());
        if (!tenantUserOpt.isPresent()) {
            throw new NotFoundTenantException(String.format("%s人员信息不存在", command.getId()));
        }
        TenantUserEntity tenantUser = tenantUserOpt.get();
        RealNameAuthenticatedStatus authStatus = tenantUser.getAuthenticateStatus();
        if (authStatus != RealNameAuthenticatedStatus.Failed) {
            throw new BadTenantException(String.format("当前实名认证状态为%s, 不允许进行申诉", authStatus.getTypeName()));
        }
        this.unitWork.executeTran(() -> {
            //创建申诉记录
            TenantUserAppealsEntity appealsEntity = TenantUserAppealsEntity.create(
                    tenantUser,
                    command.getAppealPhoto(),
                    command.getRegionCode());
            this.tenantUserAppealsRepository.save(appealsEntity);
            //更新人员申诉状态
            tenantUser.changeAppealStatus(AppealStatus.Request);
            this.tenantUserRepository.save(tenantUser);
        });
    }

    /**
     * description：平台操作-变更用户姓名/手机信息
     * author：linchunpeng
     * date：2024/11/13
     */
    @Override
    public void dispatch(PlatformUpdateUserBasicCommand command) {
        command.validate();
        Optional<TenantUserEntity> tenantUserOptional = this.tenantUserRepository.findById(command.getTenantUserId());
        if (!tenantUserOptional.isPresent()) {
            throw new NotFoundTenantException("找不到登录用户信息");
        }
        Optional<TenantUserEntity> operateUserOptional = this.tenantUserRepository.findById(command.getOperateUserId());
        if (!operateUserOptional.isPresent()) {
            throw new NotFoundTenantException("找不到被操作的用户信息");
        }
        StringBuffer operateContent = new StringBuffer(64);

        TenantUserEntity tenantUser = tenantUserOptional.get();
        TenantUserEntity operateUser = operateUserOptional.get();

        String oldName = operateUser.getName();
        String oldPhone = operateUser.getTelephone();

        if (org.apache.commons.lang3.StringUtils.isNotBlank(command.getName())) {
            //修改了姓名
            operateContent.append("修改了姓名，原值：[").append(oldName).append("]，改为：[").append(command.getName()).append("]。");
        }
        if (org.apache.commons.lang3.StringUtils.isNotBlank(command.getTelephone())) {
            //修改了手机号码
            operateContent.append("修改了手机号码，原值：[").append(oldPhone).append("]，改为：[").append(command.getTelephone()).append("]。");
        }

        this.unitWork.executeTran(() -> {
            operateUser.changeBasic(command.getName(), command.getTelephone());
            this.tenantUserRepository.save(operateUser);

            if (org.apache.commons.lang3.StringUtils.isNotBlank(command.getName()) && !oldName.equals(command.getName())) {
                //修改了姓名
                tenantUserRepository.updateCredentialNameByTenantUserId(operateUser.getId(), command.getName());
            }

            //记录日志
            platformOperateLogRpcProvider.logOperate(new PlatformOperateLogRequest(tenantUser.getId(), command.getEmployeeId(),
                    tenantUser.getName(), 1, operateUser.getId(), operateContent.toString(), command.getOperateReason(),
                    command.getIpAddress()));
        });
    }

    /**
     * description：平台操作重新认证
     * author：linchunpeng
     * date：2024/11/13
     */
    @Override
    public void dispatch(PlatformResetAuthenticateStatusCommand command) {
        command.validate();
        Optional<TenantUserEntity> tenantUserOptional = this.tenantUserRepository.findById(command.getTenantUserId());
        if (!tenantUserOptional.isPresent()) {
            throw new NotFoundTenantException("找不到登录用户信息");
        }
        Optional<TenantUserEntity> operateUserOptional = this.tenantUserRepository.findById(command.getOperateUserId());
        if (!operateUserOptional.isPresent()) {
            throw new NotFoundTenantException("找不到被操作的用户信息");
        }

        TenantUserEntity tenantUser = tenantUserOptional.get();
        TenantUserEntity operateUser = operateUserOptional.get();


        this.unitWork.executeTran(() -> {
            operateUser.resetAuthenticateStatus();
            this.tenantUserRepository.save(operateUser);

            //记录日志
            platformOperateLogRpcProvider.logOperate(new PlatformOperateLogRequest(tenantUser.getId(), command.getEmployeeId(),
                    tenantUser.getName(), 2, operateUser.getId(), "平台操作重新认证", command.getOperateReason(),
                    command.getIpAddress()));
        });
    }

    /**
     * description：重置密码
     * author：linchunpeng
     * date：2024/11/13
     */
    @Override
    public void dispatch(PlatformResetPasswordCommand command) {
        command.validate();
        Optional<TenantUserEntity> tenantUserOptional = this.tenantUserRepository.findById(command.getTenantUserId());
        if (!tenantUserOptional.isPresent()) {
            throw new NotFoundTenantException("找不到登录用户信息");
        }
        Optional<TenantUserEntity> operateUserOptional = this.tenantUserRepository.findById(command.getOperateUserId());
        if (!operateUserOptional.isPresent()) {
            throw new NotFoundTenantException("找不到被操作的用户信息");
        }

        TenantUserEntity tenantUser = tenantUserOptional.get();
        TenantUserEntity operateUser = operateUserOptional.get();


        ResetPassWordRequest request = new ResetPassWordRequest();
        request.setLoginName(operateUser.getSelectIdNum());
        request.setNewPassword("");
        //存在用户并且不是离职状态
        identityRpcProvider.resetPassword(request);

        this.unitWork.executeTran(() -> {
            //记录日志
            platformOperateLogRpcProvider.logOperate(new PlatformOperateLogRequest(tenantUser.getId(), command.getEmployeeId(),
                    tenantUser.getName(), 5, operateUser.getId(), "平台重置密码", null,
                    command.getIpAddress()));
        });
    }

    @Override
    public TocWechatCgiConfirmCheckStatusCommand.TocWechatCgiConfirmCheckStatusCommandResult dispatch(
            TocWechatCgiConfirmCheckStatusCommand command
    ) {
        TenantUserEntity findTenantUser =
                this.tenantUserRepository.getByIdNum(command.getNumber(), command.getCredentialType());

        if (findTenantUser != null && findTenantUser.getCheckedStatus() != UserCheckedStatus.None) {
            //throw new ConfirmCheckStatusException(findTenantUser.getId(), findTenantUser.getCheckedStatus());
            return TocWechatCgiConfirmCheckStatusCommand.TocWechatCgiConfirmCheckStatusCommandResult.create(
                    findTenantUser.getId()
            );
        }

        AtomicReference<Boolean> existsUser = new AtomicReference<>(false);
        AtomicReference<String> tenantUserIdAto = new AtomicReference<>();
        this.unitWork.executeTran(() -> {
            TenantUserEntity tenantUser = findTenantUser;
            if (tenantUser == null) {
                tenantUser = TenantUserEntity.create(this.eventService,
                        command.getName(),
                        command.getPhone(),
                        true
                );

                existsUser.set(true);
            }

            tenantUserIdAto.set(tenantUser.getId());
            tenantUser.changeTelephone(command.getPhone());

            tenantUser.changeCredential(
                    command.getName(),
                    command.getCredentialType(),
                    command.getHeadPhoto(),
                    command.getNumber(),
                    command.getValidDateFrom(),
                    command.getValidDateTo(),
                    command.getFrontPhoto(),
                    command.getReversePhoto(),
                    command.getAddress(),
                    true,
                    command.getCertificateImage());

            this.tenantUserRepository.save(tenantUser);
        });

        return TocWechatCgiConfirmCheckStatusCommand.TocWechatCgiConfirmCheckStatusCommandResult.create(
                tenantUserIdAto.get()
        );
    }
}
