package com.bcxin.tenant.domain.entities;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdcardUtil;
import com.bcxin.Infrastructures.TenantContext;
import com.bcxin.Infrastructures.components.EventDispatcher;
import com.bcxin.Infrastructures.components.JsonProvider;
import com.bcxin.Infrastructures.entities.EntityAbstract;
import com.bcxin.Infrastructures.entities.IAggregate;
import com.bcxin.Infrastructures.enums.*;
import com.bcxin.Infrastructures.exceptions.ArgumentTenantException;
import com.bcxin.Infrastructures.exceptions.BadTenantException;
import com.bcxin.Infrastructures.exceptions.NotAllowedTenantException;
import com.bcxin.Infrastructures.utils.AuthUtil;
import com.bcxin.Infrastructures.utils.UUIDUtil;
import com.bcxin.tenant.domain.entities.valueTypes.LocationValueType;
import com.bcxin.tenant.domain.enums.EventAction;
import com.bcxin.tenant.domain.events.TenantCheckStatusChangedEvent;
import com.bcxin.tenant.domain.events.TenantCredentialChangedEvent;
import com.bcxin.tenant.domain.events.TenantCredentialChangedValidateEvent;
import com.bcxin.tenant.domain.events.TenantUserTelephoneChangedEvent;
import com.bcxin.tenant.domain.services.TenantEventService;
import com.bcxin.tenant.domain.services.commands.CreateTenantEventCommand;
import com.bcxin.tenant.domain.snapshots.GisLocationSnapshot;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import org.springframework.util.StringUtils;

import javax.persistence.*;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Optional;

/**
 * 租户用户
 */
@Getter
@Setter(AccessLevel.PROTECTED)
@Table(name = "tenant_users")
@Entity
public class TenantUserEntity extends EntityAbstract implements IAggregate {
    @Id
    @Column(length = 50, nullable = false)
    private String id;

    //用户唯一标识
    @Column(name = "third_party_loginNo", length = 200)
    private String thirdPartyLoginNo;

    /**
     * 姓名
     */
    @Column(name = "name", nullable = false)
    private String name;

    /**
     * 头像
     */
    @Column(name = "head_photo")
    private String headPhoto;

    /**
     * IM标识符
     * 一般采用id的方式, 但是对于旧数据，我们手机号码，但是手机号码又会发生变更，因此采用这个字段来进行表示
     */
    @Column(name = "im_identity",length = 100)
    private String imIdentity;

    /**
     * 性别
     */
    @Enumerated(EnumType.ORDINAL)
    @Column(nullable = false, name = "sex")
    private Sex sex;

    /**
     * 手机号码
     */
    @Column(nullable = false, name = "telephone", length = 50)
    private String telephone;

    @Column(nullable = true, name = "email", length = 50)
    private String email;

    /**
     * 经纬度信息
     */
    @Column(nullable = true, name = "lon_lat_json", length = 200)
    private String lonLatJson;

    @Temporal(TemporalType.DATE)
    @Column(nullable = true, name = "birthdate")
    private Date birthdate;

    /**
     * 核验状态
     */
    @Enumerated(EnumType.ORDINAL)
    @Column(nullable = false, name = "checked_status")
    private UserCheckedStatus checkedStatus;

    /**
     * 实名认证状态
     */
    @Enumerated(EnumType.ORDINAL)
    @Column(nullable = false, name = "authenticated_status")
    private RealNameAuthenticatedStatus authenticateStatus;

    /**
     * 实名认证结果
     */
    @Column(name = "authenticated_result")
    private String authenticatedResult;

    /**
     * 实名认证时间
     */
    @Column(name = "authenticated_time")
    private Timestamp authenticatedTime;

    /**
     * 身高
     */
    @Column(name = "stature", length = 50)
    private String stature;

    /**
     * 人员类型
     */
    @Enumerated(EnumType.ORDINAL)
    @Column(name = "user_type", nullable = false)
    private UserType userType;

    /**
     * 民族
     */
    @Column(name = "nation",length = 100)
    private String nation;

    /**
     * 国籍
     */
    @Column(name = "nationality")
    private String nationality;

    /**
     * 从业年限
     */
    @Column(name = "work_year")
    private Integer workYear;

    /**
     * 疾病历史
     */
    @Column(name = "diseases_history")
    private String diseasesHistory;

    /**
     * 政治面貌
     */
    @Column(name = "politics_status",length = 100)
    private String politicsStatus;

    /**
     * 兵役情况
     */
    @Column(name = "military_status",length = 100)
    private String militaryStatus;

    /**
     * 户籍类型
     */
    @Column(name = "household_type",length = 100)
    private String householdType;

    /**
     * 文化程度
     */
    @Column(name = "education",length = 100)
    private String education;

    /**
     * 籍贯
     */
    @Column(name = "native_place",length = 100)
    private String nativePlace;

    /**
     * 婚姻状况
     */
    @Column(name = "marital_status",length = 100)
    private String maritalStatus;


    @Column(name = "created_time", nullable = false)
    private Timestamp createdTime;

    /**
     * 解决定时任务中推送数据到Identity的问题
     */
    @OneToMany(mappedBy = "tenantUser",cascade = CascadeType.ALL)
    private Collection<TenantUserCredentialsEntity> credentials;

    @OneToOne(cascade = CascadeType.ALL)
    private TenantUserCredentialsEntity selectedCredential;

    @Column(name = "habit_setting", length = 800)
    private String habitSetting;

    /**
     * 一寸免冠白底彩照
     */
    @Column(name = "one_inch_color_white_photo",length = 1000)
    private String oneInchColorWhitePhoto;

    /**
     * 两寸免冠蓝底彩照
     */
    @Column(name = "two_inch_color_blue_photo",length = 1000)
    private String twoInchColorBluePhoto;

    @Column(name = "cid",length = 200)
    private String cid;

    @Column(name = "wechat",length = 100)
    private String wechat;

    @Column(name = "wechat_nicky",length = 100)
    private String wechatNicky;

    @Column(name = "last_updated_time", nullable = true)
    private Timestamp lastUpdatedTime;

    @Column(name = "last_checked_status_time", nullable = true)
    private Timestamp lastCheckedStatusTime;

    /**
     * 最后同步时间
     */
    @Column(name = "last_sync_time")
    private Timestamp lastSyncTime;


    /**
     * 背景筛查状态
     */
    @Column(name = "background_screening_status",nullable = false)
    private BackgroundScreeningStatus backgroundScreeningStatus;

    /**
     * 最后一次背景筛查时间
     */
    @Column(name = "last_background_screening_time",nullable = true)
    private Timestamp lastBackGroundScreeningTime;

    /**
     * 紧急联系人
     */
    @Column(name = "emergency_contact")
    private String emergencyContact;

    /**
     * 紧急联系人电话
     */
    @Column(name = "emergency_phone")
    private String emergencyPhone;

    /**
     * 驾照等级
     */
    @Column(name = "license_level")
    private String licenseLevel;

    @Column(name = "certificate_image")
    private String CertificateImage;

    /**
     * 现住地址
     */
    @Embedded
    @AttributeOverrides({
            @AttributeOverride(name="province.code",
                    column=@Column(name="place_Of_now_province_code")),
            @AttributeOverride(name="province.name",
                    column=@Column(name="place_Of_now_province_name")),
            @AttributeOverride(name="city.code",
                    column=@Column(name="place_Of_now_city_code")),
            @AttributeOverride(name="city.name",
                    column=@Column(name="place_Of_now_city_name")),
            @AttributeOverride(name="district.code",
                    column=@Column(name="place_Of_now_district_code")),
            @AttributeOverride(name="district.name",
                    column=@Column(name="place_Of_now_district_name")),
            @AttributeOverride(name="address",
                    column=@Column(name="place_Of_now_address")),
    })
    private LocationValueType placeOfNow;

    @Enumerated(EnumType.ORDINAL)
    @Column(name = "last_appeal_status")
    private AppealStatus lastAppealStatus;

    @Column(name = "last_appeal_result")
    private String lastAppealResult;
    @Temporal(TemporalType.DATE)
    @Column(name = "last_appeal_time")
    private Date lastAppealTime;
    @OneToMany(mappedBy = "tenantUser", cascade = CascadeType.REFRESH, fetch = FetchType.LAZY)
    private Collection<TenantUserAppealsEntity> appeals;

    public void addCredential(CredentialType credentialType,String credentialNumber, boolean isDefault) {
        credentialNumber = com.bcxin.Infrastructures.utils.StringUtils.toUpperCase(StringUtils.trimAllWhitespace(credentialNumber));
        Collection<TenantUserCredentialsEntity> tenantUserCredentialsEntities = this.getCredentials();
        if (tenantUserCredentialsEntities == null) {
            tenantUserCredentialsEntities = new ArrayList<>();
        }

        TenantUserCredentialsEntity tenantUserCredential = TenantUserCredentialsEntity.create(this, credentialType, credentialNumber);

        tenantUserCredentialsEntities.add(tenantUserCredential);

        this.setCredentials(tenantUserCredentialsEntities);

        if (isDefault) {
            this.setSelectedCredential(tenantUserCredential);
        }
    }

    protected TenantUserEntity() {
        this.setCreatedTime(Timestamp.from(Instant.now()));
        this.setLastUpdatedTime(Timestamp.from(Instant.now()));
        this.setLastSyncTime(Timestamp.from(Instant.now()));
    }

    protected TenantUserEntity(String name, String telephone) {
        this();

        if (!StringUtils.hasLength(name)) {
            throw new ArgumentTenantException("姓名不能为空!");
        }
        if (!StringUtils.hasLength(telephone)) {
            throw new ArgumentTenantException("手机号码不能为空!");
        }

        //这个字段作为账号 不对其手机号码验证
//        if (!TelephoneValidator.checkIsValid(telephone)) {
//            throw new ArgumentTenantException("手机号码格式不正确");
//        }

        this.setId(UUIDUtil.getShortUuid());
        this.setBackgroundScreeningStatus(BackgroundScreeningStatus.Init);

        this.setName(name);
        this.setTelephone(telephone);
        this.setAuthenticateStatus(RealNameAuthenticatedStatus.UnAuthenticated);
        this.changeCheckStatus(null, UserCheckedStatus.None);
        this.setSex(Sex.Unknown);
        this.setUserType(UserType.normal);
        this.setImIdentity(this.getId());
        this.setLastAppealStatus(AppealStatus.None);
    }

    public static TenantUserEntity create(TenantEventService eventService, String name, String telephone,boolean ignoreSms) {
        telephone = StringUtils.trimAllWhitespace(telephone);
        TenantUserEntity tenantUser = new TenantUserEntity(name, telephone);
        if(!ignoreSms) {
            /**
             * 记录创建tenantUser的事件
             */
            eventService.create(CreateTenantEventCommand.create(
                    EventAction.TenantUserAfterCreatedEventForSms,
                    tenantUser.getId(),
                    tenantUser.getTelephone()));
        }

        eventService.create(CreateTenantEventCommand.create(
                EventAction.TenantUserAfterCreatedEventForIdentity,
                tenantUser.getId(),
                tenantUser.getTelephone()));

        return tenantUser;
    }

    public static TenantUserEntity createImport(TenantEventService eventService,
                                                String name,
                                                String telephone,
                                                Sex sex,
                                                Date birthdate,
                                                String nation,
                                                String education,
                                                String politicsStatus,
                                                String militaryStatus,
                                                String maritalStatus,
                                                String emergencyContact,
                                                String emergencyPhone,
                                                String address,
                                                String householdType) {
        telephone = StringUtils.trimAllWhitespace(telephone);
        TenantUserEntity tenantUser = new TenantUserEntity(name, telephone);
        tenantUser.setSex(sex == null ? Sex.Unknown : sex);
        tenantUser.changeBirthdate(birthdate);
        tenantUser.setNation(nation);
        tenantUser.setEducation(education);
        tenantUser.setPoliticsStatus(politicsStatus);
        tenantUser.setMilitaryStatus(militaryStatus);
        tenantUser.setMaritalStatus(maritalStatus);
        tenantUser.setEmergencyContact(emergencyContact);
        tenantUser.setEmergencyPhone(emergencyPhone);
        tenantUser.setPlaceOfNow(LocationValueType.create(null, null, null, address));
        tenantUser.setHouseholdType(householdType);
        /**
         * 记录创建tenantUser的事件
         */
        eventService.create(
                CreateTenantEventCommand.create(
                EventAction.TenantUserAfterCreatedEventForSms,
                tenantUser.getId(),
                tenantUser.getTelephone()));

        eventService.create(CreateTenantEventCommand.create(
                EventAction.TenantUserAfterCreatedEventForIdentity,
                tenantUser.getId(),
                tenantUser.getTelephone())
        );

        return tenantUser;
    }

    /**
     * 组织列表
     */
    @OneToMany(mappedBy = "tenantUser", cascade = CascadeType.REFRESH)
    private Collection<OrganizationEntity> organizations;

    /**
     * 雇员的关系信息不是从这边发起的
     */
    @OneToMany(mappedBy = "tenantUser", cascade = CascadeType.REFRESH)
    private Collection<EmployeeEntity> employeeEntities;

    public void assignOrganization(OrganizationEntity organization) {
        Collection<OrganizationEntity> organizations = this.getOrganizations();
        if (organizations == null) {
            organizations = new ArrayList<>();
        }

        organizations.add(organization);

        this.setOrganizations(organizations);
    }

    public void change(Sex sex,
                       String nation,String diseasesHistory,String workYear, String politicsStatus,
                       String stature, String militaryStatus, Date birthdate,
                       String education, String householdType, String nativePlace,
                       String maritalStatus,
                        String emergencyContact,
                        String emergencyPhone,
                        String licenseLevel,
                        LocationValueType placeOfNow) {
        /**
         * 这个头像信息为身份证头像,因此, 不应该进行修改
         * if(StringUtils.hasLength(headPhoto)) {
         *             this.setHeadPhoto(headPhoto);
         *         }
         */

        this.setSex(sex);
        this.setNation(nation);
        this.setDiseasesHistory(diseasesHistory);
        /**
         * 先忽略提交无效的工作时间
         */
        if(StringUtils.hasLength(workYear)) {
            try {
                this.setWorkYear(Integer.parseInt(workYear));
            }
            catch (Exception ex){
                this.setWorkYear(null);
            }
        }else {
            this.setWorkYear(null);
        }

        this.setPoliticsStatus(politicsStatus);
        this.setStature(stature);
        this.setMilitaryStatus(militaryStatus);
        this.changeBirthdate(birthdate);
        this.setEducation(education);
        this.setHouseholdType(householdType);
        this.setNativePlace(nativePlace);
        this.setMaritalStatus(maritalStatus);
        this.setLastUpdatedTime(Timestamp.from(Instant.now()));
        this.setLastSyncTime(Timestamp.from(Instant.now()));
        this.setEmergencyContact(emergencyContact);
        this.setEmergencyPhone(emergencyPhone);
        this.setLicenseLevel(licenseLevel);
        this.setPlaceOfNow(placeOfNow);
    }

    public void changeEmail(String email) {
        this.setEmail(email);
        this.setLastUpdatedTime(Timestamp.from(Instant.now()));
        this.setLastSyncTime(Timestamp.from(Instant.now()));
    }

    public void changeName(String name) {
        this.setName(name);
        this.setLastUpdatedTime(Timestamp.from(Instant.now()));
        this.setLastSyncTime(Timestamp.from(Instant.now()));
    }

    public void changeTelephone(String telephone) {
        this.setTelephone(telephone);
        this.setLastUpdatedTime(Timestamp.from(Instant.now()));
        this.setLastSyncTime(Timestamp.from(Instant.now()));
    }

    public void changeSex(Sex sex) {
        this.setSex(sex);
        this.setLastUpdatedTime(Timestamp.from(Instant.now()));
        this.setLastSyncTime(Timestamp.from(Instant.now()));
    }

    public void changeBirthdate(Date birthdate) {
        if (birthdate != null) {
            this.setBirthdate(birthdate);
            this.setLastUpdatedTime(Timestamp.from(Instant.now()));
            this.setLastSyncTime(Timestamp.from(Instant.now()));
        }
    }

    public void changeBasic(String name, String telephone) {
        /*if (this.getCheckedStatus() != UserCheckedStatus.None) {
            throw new NotAllowedTenantException("已核验用户信息, 不允许被更改");
        }*/
        String oldName = this.getName();
        if (org.apache.commons.lang3.StringUtils.isNotBlank(name) && !oldName.equals(name)) {
            this.setName(name);
        }
        String oldPhone = this.getTelephone();
        if (org.apache.commons.lang3.StringUtils.isNotBlank(telephone) && !oldPhone.equals(telephone)) {
            telephone = StringUtils.trimAllWhitespace(telephone);
            this.setTelephone(telephone);
            this.recordEvent(TenantUserTelephoneChangedEvent.create(this.getId(), this.getTelephone(), oldPhone, this.getName(),this.getSelectIdNum()));
        }
        this.setLastUpdatedTime(Timestamp.from(Instant.now()));
        this.setLastSyncTime(Timestamp.from(Instant.now()));
    }

    public void changeLocation(String latitude, String longitude, JsonProvider jsonProvider) {
        String json = jsonProvider.getJson(GisLocationSnapshot.create(latitude, longitude));
        this.setLonLatJson(json);
        this.setLastUpdatedTime(Timestamp.from(Instant.now()));
        this.setLastSyncTime(Timestamp.from(Instant.now()));
    }

    public void changeDeviceId(String cid) {
        this.setCid(cid);
        this.setLastUpdatedTime(Timestamp.from(Instant.now()));
        this.setLastSyncTime(Timestamp.from(Instant.now()));
    }

    public void assignThirdPartyLoginNo(String thirdPartyLoginNo){
        if(!StringUtils.hasLength(this.thirdPartyLoginNo)){
            this.setThirdPartyLoginNo(thirdPartyLoginNo);
            this.setLastUpdatedTime(Timestamp.from(Instant.now()));
            this.setLastSyncTime(Timestamp.from(Instant.now()));
        }
    }

   public void assignBirthdateAndSex(Date date, Sex sex){
        if (date != null) {
            this.birthdate = date;
        }
        if (sex != null) {
            this.sex = sex;
        }
        if (date != null || sex != null) {
            this.setLastUpdatedTime(Timestamp.from(Instant.now()));
            this.setLastSyncTime(Timestamp.from(Instant.now()));
        }
    }
    /**
     * 更改证件信息
     * @param frontPhoto
     * @param reversePhoto
     */
    public void changeCredential(String headPhoto,
                                 String frontPhoto,
                                 String reversePhoto,
                                 String address,
                                 Date validDateFrom,
                                 Date validDateTo
                                 ) {
        Collection<TenantUserCredentialsEntity> credentials = this.getCredentials();
        if (credentials == null) {
            credentials = new ArrayList<>();
        }

        Optional<TenantUserCredentialsEntity> selectedTenantUserCredentialOptional =
                credentials.stream().filter(ii -> ii.getSelected() == TrueFalseStatus.True).findFirst();
        if (!selectedTenantUserCredentialOptional.isPresent()) {
            selectedTenantUserCredentialOptional = credentials.stream().findFirst();
        }

        TenantUserCredentialsEntity userCredentialsEntity = null;
        if (selectedTenantUserCredentialOptional.isPresent()) {
            userCredentialsEntity = selectedTenantUserCredentialOptional.get();
        } else {
            throw new ArgumentTenantException("证件信息不存在！");
        }
        this.setCredentials(credentials);
        this.setSelectedCredential(userCredentialsEntity);
        this.setHeadPhoto(headPhoto);
        userCredentialsEntity
                .changeDetail(headPhoto, frontPhoto, reversePhoto, address,validDateFrom,validDateTo);
        this.setLastSyncTime(Timestamp.from(Instant.now()));
        this.setLastUpdatedTime(Timestamp.from(Instant.now()));
    }

    /**
     * 更改证件信息
     * @param name
     * @param credentialType
     * @param headPhoto
     * @param number
     * @param validDateFrom
     * @param validDateTo
     * @param frontPhoto
     * @param reversePhoto
     * @param address
     */
    public void changeCredential(String name,
                                 CredentialType credentialType,
                                 String headPhoto,
                                 String number,
                                 Date validDateFrom,
                                 Date validDateTo,
                                 String frontPhoto,
                                 String reversePhoto,
                                 String address,
                                 boolean fromMobile,
                                 String certificateImage) {
        //只有未核验，未认证，认证失败的人员，才允许进行重新核验
        boolean allowedChangedCertificate =
                (this.getAuthenticateStatus() == RealNameAuthenticatedStatus.UnAuthenticated ||
                        this.getAuthenticateStatus() == RealNameAuthenticatedStatus.Failed) ||
                        this.getCheckedStatus() == UserCheckedStatus.None;

        if (CredentialType.IdCard == credentialType && !allowedChangedCertificate) {
            throw new NotAllowedTenantException(String.format("该用户{%s}已经认证，不允许进行重新核验。", this.getName()));
        }

        number = com.bcxin.Infrastructures.utils.StringUtils.toUpperCase(StringUtils.trimAllWhitespace(number));
        this.recordEvent(
                TenantCredentialChangedValidateEvent.create(this.getId(), this.getName(), credentialType, number, fromMobile)
        );

        if (!fromMobile) {
            if (UserCheckedStatus.Matched.equals(this.getCheckedStatus())
                    && (RealNameAuthenticatedStatus.UnAuthenticated.equals(this.getAuthenticateStatus())
                    || RealNameAuthenticatedStatus.Failed.equals(this.getAuthenticateStatus()))
            ) {
                if (!AuthUtil.isAdmin()) {
                    throw new ArgumentTenantException("已核验(未认证通过)状态，只有组织管理员才能修改姓名！");
                }

                credentialType = this.getSelectedCredential().getCredentialType();
                number = this.getSelectedCredential().getNumber();
                headPhoto = this.getSelectedCredential().getHeadPhoto();
                validDateFrom = this.getSelectedCredential().getValidDateFrom();
                validDateTo = this.getSelectedCredential().getValidDateTo();
                frontPhoto = this.getSelectedCredential().getFrontPhoto();
                reversePhoto = this.getSelectedCredential().getReversePhoto();
                address = this.getSelectedCredential().getAddress();
            }
        }

        Collection<TenantUserCredentialsEntity> credentials = this.getCredentials();
        if (credentials == null) {
            credentials = new ArrayList<>();
        }

        Optional<TenantUserCredentialsEntity> selectedTenantUserCredentialOptional =
                credentials.stream().filter(ii -> ii.getSelected() == TrueFalseStatus.True).findFirst();
        if (!selectedTenantUserCredentialOptional.isPresent()) {
            CredentialType finalCredentialType = credentialType;
            selectedTenantUserCredentialOptional = credentials.stream()
                    .filter(ii -> ii.getCredentialType() == finalCredentialType)
                    .findFirst();
        }

        TenantUserCredentialsEntity userCredentialsEntity = null;
        if (selectedTenantUserCredentialOptional.isPresent()) {
            userCredentialsEntity = selectedTenantUserCredentialOptional.get();
        } else {
            userCredentialsEntity = TenantUserCredentialsEntity.create(this, credentialType, number);
            credentials.add(userCredentialsEntity);
        }
        this.setCredentials(credentials);
        this.setSelectedCredential(userCredentialsEntity);


        Timestamp timestamp = Timestamp.from(Instant.now());

        /**
         * 只有认证失败/未认证（也是未核验）的人才可以更改身份证和姓名
         *
         * 其中姓名在未核验的时候，在Web端可以修改
         */
        if (credentialType == CredentialType.IdCard && allowedChangedCertificate && fromMobile) {
            String oldNumber = userCredentialsEntity.getNumber();
            this.setAuthenticateStatus(RealNameAuthenticatedStatus.Authenticating);
            this.setAuthenticatedTime(timestamp);

            if (!StringUtils.hasLength(certificateImage)) {
                throw new BadTenantException("系统异常, 活体采集头像不能为空");
            }

            this.setCertificateImage(certificateImage);
            this.setLastCheckedStatusTime(timestamp);

            /**
             * 身份证类型的话，则提交为已核验
             * 其他类型则: 已提交
             */
            if (this.getCheckedStatus() == UserCheckedStatus.None) {
                if (credentialType == CredentialType.IdCard) {
                    this.changeCheckStatus(number, UserCheckedStatus.Matched);
                } else {
                    this.changeCheckStatus(number, UserCheckedStatus.Commit);
                }
            }

            this.setName(name);

            this.setHeadPhoto(headPhoto);
            userCredentialsEntity
                    .changeDetail(
                            credentialType, name, number,
                            headPhoto, frontPhoto, reversePhoto,
                            address, validDateFrom, validDateTo
                    );

            /**
             * 如果是身份证与旧身份证不一致，修改背景筛查状态为未背景筛查
             */
            if (StringUtils.hasLength(oldNumber) &&
                    !com.bcxin.Infrastructures.utils.StringUtil.equal(oldNumber, number)) {
                this.setBackgroundScreeningStatus(BackgroundScreeningStatus.Init);
            }
        } else if (credentialType != CredentialType.IdCard || allowedChangedCertificate) {
            this.setName(name);

            this.setHeadPhoto(headPhoto);
            userCredentialsEntity
                    .changeDetail(
                            credentialType, name, number,
                            headPhoto, frontPhoto, reversePhoto,
                            address, validDateFrom, validDateTo
                    );
        }

        if (StringUtils.hasLength(number) && credentialType == CredentialType.IdCard) {
            //身份证号码不为空 && 是身份证，设置出生日期
            Date birthDate = IdcardUtil.getBirthDate(number);
            if (birthDate != null) {
                this.setBirthdate(birthDate);
            }
        }

        this.setLastUpdatedTime(timestamp);
        this.setLastSyncTime(timestamp);
    }

    public void changePhoto(String oneInchColorWhitePhoto,String twoInchColorBluePhoto ) {
        this.setOneInchColorWhitePhoto(oneInchColorWhitePhoto);
        this.setTwoInchColorBluePhoto(twoInchColorBluePhoto);
        Timestamp timestamp = Timestamp.from(Instant.now());

        this.setLastUpdatedTime(timestamp);
        this.setLastSyncTime(timestamp);
    }

    public void changeWechat(String wechat,String nicky) {
        this.setWechat(wechat);
        this.setWechatNicky(nicky);

        this.setLastUpdatedTime(Timestamp.from(Instant.now()));
        this.setLastSyncTime(Timestamp.from(Instant.now()));
    }

    public void redoAuthenticate() {
        if(this.getAuthenticateStatus()!=RealNameAuthenticatedStatus.Failed) {
            throw new NotAllowedTenantException("您已提交认证！");
        }

        this.setAuthenticateStatus(RealNameAuthenticatedStatus.Authenticating);
        this.setAuthenticatedResult("手动重新认证");

        Timestamp lastUpdatedTime = Timestamp.from(Instant.now());
        this.setAuthenticatedTime(lastUpdatedTime);
        this.setLastUpdatedTime(lastUpdatedTime);
        this.setLastSyncTime(lastUpdatedTime);
    }

    public void resetAuthenticateStatus() {
        this.setAuthenticateStatus(RealNameAuthenticatedStatus.Authenticating);
        this.setAuthenticatedResult("平台操作重新认证");

        Timestamp lastUpdatedTime = Timestamp.from(Instant.now());
        this.setAuthenticatedTime(lastUpdatedTime);
        this.setLastUpdatedTime(lastUpdatedTime);
        this.setLastSyncTime(lastUpdatedTime);
    }

    public String getSelectIdNum(){
        if(this.selectedCredential != null){
            return this.selectedCredential.getNumber();
        }
        return null;
    }

    public void recordCredentialChangeEvent() {
        this.recordEvent(TenantCredentialChangedEvent.create(this.getId(),this.getName(), this.selectedCredential.getCredentialType(),this.getTelephone(), this.selectedCredential.getNumber()));
    }

    public void changeAppealStatus(AppealStatus appealStatus){
        this.setLastAppealStatus(appealStatus);
        this.setLastUpdatedTime(Timestamp.from(Instant.now()));
    }

    public void changeCheckStatus(String idCardNum, UserCheckedStatus checkedStatus) {
        this.setCheckedStatus(checkedStatus);

        if (checkedStatus != UserCheckedStatus.None) {
            assert idCardNum != null;

            TenantContext.getInstance()
                    .resolve(EventDispatcher.class)
                    .dispatch(TenantCheckStatusChangedEvent.create(
                            this, idCardNum));
        }
    }
}
