package nckd.jxccl.hr.hdm.plugin.operate.transfer;

import com.google.common.collect.Lists;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.entity.operate.result.IOperateInfo;
import kd.bos.entity.operate.result.OperationResult;
import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
import kd.bos.entity.plugin.PreparePropertysEventArgs;
import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
import kd.bos.exception.BosErrorCode;
import kd.bos.exception.ErrorCode;
import kd.bos.exception.KDBizException;
import kd.bos.exception.KDException;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.orm.util.CollectionUtils;
import kd.bos.servicehelper.operation.SaveServiceHelper;
import kd.bos.servicehelper.user.UserServiceHelper;
import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
import kd.hr.hbp.business.servicehelper.HRMServiceHelper;
import kd.hr.hbp.common.api.HrApiResponse;
import kd.hr.hbp.common.util.HRObjectUtils;
import kd.hr.hbp.common.util.HRStringUtils;
import kd.hr.hlcm.common.enums.ContractCategoryEnum;
import kd.hr.hlcm.common.enums.PostypeEnum;
import kd.sdk.hr.hdm.common.enums.reg.RegBillStatusEnum;
import kd.sdk.hr.hlcm.common.enums.BusinessTypeEnum;
import nckd.jxccl.base.common.utils.QueryFieldBuilder;
import nckd.jxccl.hr.hdm.common.transfer.TransferApplyBillConstant;
import nckd.jxccl.hr.homs.common.application.event.GECEventConstant;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 调动生效后解除合同操作插件
 * @entity: nckd_hdm_transferbase_ext
 * @operate: canclecontract_aftereffect
 * @author: jtd
 * @date: 2026/1/6 11:38
 */
public class CancelContractAfterEffectOpPlugin extends AbstractOperationServicePlugIn {
    private static final Log log = LogFactory.getLog(CancelContractAfterEffectOpPlugin.class);
    private static final HRBaseServiceHelper contractSourceHelper = HRBaseServiceHelper.create(TransferApplyBillConstant.HLCM_CONTRACTSOURCE_ENTITY);
    private static final HRBaseServiceHelper contractHelper = HRBaseServiceHelper.create(TransferApplyBillConstant.HLCM_CONTRACT_ENTITY);
    private static final HRBaseServiceHelper contractApplyCancelHelper = HRBaseServiceHelper.create(TransferApplyBillConstant.HLCM_CONTRACTAPPLYCANCEL_ENTITY);
    private static final HRBaseServiceHelper contractReasonHelper = HRBaseServiceHelper.create(TransferApplyBillConstant.HLCM_CONTRACTREASON_ENTITY);

    @Override
    public void onPreparePropertys(PreparePropertysEventArgs e) {
        e.getFieldKeys().addAll(billEntityType.getAllFields().keySet());
    }

    @Override
    public void beginOperationTransaction(BeginOperationTransactionArgs e) {
        super.beginOperationTransaction(e);

        DynamicObject[] dataEntites = e.getDataEntities();
        List<DynamicObject> transferData = Arrays.stream(dataEntites).filter(data -> data.getBoolean(TransferApplyBillConstant.NCKD_ISTERMORIGCONT_KEY)).collect(Collectors.toList());
        List<DynamicObject> cancelContractDyoList = new ArrayList<DynamicObject>();
        for (DynamicObject data : transferData) {
            cancelContractDyoList.add(buildContract(data));
        }

        OperationResult operationResult = SaveServiceHelper.saveOperate(TransferApplyBillConstant.HLCM_CONTRACTAPPLYCANCEL_ENTITY, cancelContractDyoList.toArray(new DynamicObject[0]));
        if (!operationResult.isSuccess()) {
            List<String> errorMsgList = new ArrayList<String>();
            for (IOperateInfo operateInfo : operationResult.getAllErrorOrValidateInfo()) {
                errorMsgList.add(operateInfo.getMessage());
            }

            if(StringUtils.isBlank(operationResult.getMessage())){
                errorMsgList.add(operationResult.getMessage());
            }
            throw new KDBizException(new ErrorCode("CancelContractAfterEffect.SaveContract.Error", String.join(System.lineSeparator(), errorMsgList)));
        }
    }

    private  DynamicObject buildContract(DynamicObject data) {
        DynamicObject cancelContract = getCancelContractByErManFile(data);

        DynamicObject contractApplyCancelDyo = contractApplyCancelHelper.generateEmptyDynamicObject();
        // 设置 姓名
        contractApplyCancelDyo.set(TransferApplyBillConstant.EMPNAME_KEY, data.get(String.join(".", TransferApplyBillConstant.BB_EM_TID, TransferApplyBillConstant.NAME_KEY)));
        // 设置 人事管理组织
        contractApplyCancelDyo.set(TransferApplyBillConstant.ORG_KEY, data.get(TransferApplyBillConstant.ORG_KEY));
        // 设置 工号
        contractApplyCancelDyo.set(TransferApplyBillConstant.EMP_NUMBER_KEY, data.get(String.join(".", TransferApplyBillConstant.BB_EM_TID, TransferApplyBillConstant.EMP_NUMBER_KEY)));
        // 设置 证件类型
        contractApplyCancelDyo.set(TransferApplyBillConstant.CARDTYPE_KEY, cancelContract.get(TransferApplyBillConstant.CARDTYPE_KEY));
        // 设置 证件号码
        contractApplyCancelDyo.set(TransferApplyBillConstant.CARDNUMBER_KEY, cancelContract.get(TransferApplyBillConstant.CARDNUMBER_KEY));
        // 设置 单据编号
        /*CodeRuleInfo codeRuleInfo = CodeRuleServiceHelper.getCodeRule(contractApplyCancelDyo.getDataEntityType().getName(), contractApplyCancelDyo, data.getString(String.format("%s_id", TransferApplyBillConstant.ORG_KEY)));
        String number = CodeRuleServiceHelper.readNumber(codeRuleInfo, contractApplyCancelDyo);
        contractApplyCancelDyo.set(TransferApplyBillConstant.NUMBER_KEY, number);*/
        // 设置 审批状态
        contractApplyCancelDyo.set(TransferApplyBillConstant.AUDIT_STATUS, RegBillStatusEnum.TEMPSTORAGE.getCode());// 暂存
        // 设置 公司历史
        contractApplyCancelDyo.set(TransferApplyBillConstant.SIGNEDCOMPANYHIS_KEY, data.get(TransferApplyBillConstant.BCOMPANY_KEY));
        // 设置 行政组织历史F7
        contractApplyCancelDyo.set(TransferApplyBillConstant.DEPARTMENTHIS_KEY, data.get(TransferApplyBillConstant.BB_PO_ADMINORG_KEY));
        // 设置 岗位历史
        contractApplyCancelDyo.set(TransferApplyBillConstant.POSTIONHIS_KEY, data.get(TransferApplyBillConstant.BB_PO_POSITION));
        // 设置 国籍
        contractApplyCancelDyo.set(TransferApplyBillConstant.NATION_KEY, data.get(String.join(".", TransferApplyBillConstant.BB_EM_TID, TransferApplyBillConstant.NATIONALITY_KEY)));
        // 设置 常驻工作地
        contractApplyCancelDyo.set(TransferApplyBillConstant.BASELOCATION_KEY, data.get(TransferApplyBillConstant.BB_PO_WORKPLACE_KEY));
        // 设置 联系方式
        contractApplyCancelDyo.set(TransferApplyBillConstant.EMPPHONE_KEY, cancelContract.getString(TransferApplyBillConstant.EMPPHONE_KEY));
        // 设置 合同协议类型
        contractApplyCancelDyo.set(TransferApplyBillConstant.PROTOCOLTYPE_KEY, "1");// 劳动合同
        // 设置 签署业务类型
        contractApplyCancelDyo.set(TransferApplyBillConstant.BUSINESSTYPE_KEY, BusinessTypeEnum.CANCEL.getCombKey());
        // 设置 签署方式
        contractApplyCancelDyo.set(TransferApplyBillConstant.SIGNWAY_KEY, cancelContract.get(TransferApplyBillConstant.SIGNWAY_KEY));
        // 设置 合同开始日期
        contractApplyCancelDyo.set(TransferApplyBillConstant.STARTDATE_KEY, cancelContract.get(TransferApplyBillConstant.STARTDATE_KEY));
        // 设置 实际结束日期
        contractApplyCancelDyo.set(TransferApplyBillConstant.ENDDATE_KEY, cancelContract.get(TransferApplyBillConstant.ENDDATE_KEY));
        // 设置 签订日期
        //contractApplyCancelDyo.set(TransferApplyBillConstant.SIGNEDDATE_KEY, cancelContract.get(TransferApplyBillConstant.SIGNEDDATE_KEY));// 解除不能设置
        // 设置 合同期限
        contractApplyCancelDyo.set(TransferApplyBillConstant.PERIOD_KEY, cancelContract.get(TransferApplyBillConstant.PERIOD_KEY));
        // 设置 实签单位
        contractApplyCancelDyo.set(TransferApplyBillConstant.ACTUALSIGNCOMPANY_KEY, cancelContract.get(TransferApplyBillConstant.ACTUALSIGNCOMPANY_KEY));
        // 设置 实签单位历史
        contractApplyCancelDyo.set(TransferApplyBillConstant.ACTUALSIGNCOMPANYHIS_KEY, cancelContract.get(TransferApplyBillConstant.ACTUALSIGNCOMPANYHIS_KEY));
        // 设置 合同解除日期
        contractApplyCancelDyo.set(TransferApplyBillConstant.CANCELDATE_KEY, data.get(TransferApplyBillConstant.B_EFFECTIVEDATE_KEY));
        // 设置 合同编号
        contractApplyCancelDyo.set(TransferApplyBillConstant.OLDCONTRACT_KEY, cancelContract);
        // 设置 业务处理状态
        //contractApplyCancelDyo.set(TransferApplyBillConstant.HANDLESTATUS_KEY);
        // 设置 任职类型
        contractApplyCancelDyo.set(TransferApplyBillConstant.POSTYPE, data.get(TransferApplyBillConstant.BB_PO_POSTYPE_KEY));
        // 设置 实际签订日期
        //contractApplyCancelDyo.set(TransferApplyBillConstant.ACTUALSIGNDATE_KEY);
        // 设置 合同期限单位
        //contractApplyCancelDyo.set(TransferApplyBillConstant.PERIODUNIT_KEY);
        // 设置 单据状态
        contractApplyCancelDyo.set(TransferApplyBillConstant.BILL_STATUS_KEY, RegBillStatusEnum.TEMPSTORAGE.getCode());
        // 设置 职位
        Long jobHis = getJobHis(data.getLong(String.join(".", TransferApplyBillConstant.BB_PO_JOB_KEY, TransferApplyBillConstant.ID_KEY)));
        contractApplyCancelDyo.set(TransferApplyBillConstant.JOB_KEY, jobHis);
        // 设置 公司
        contractApplyCancelDyo.set(TransferApplyBillConstant.CURCOMPANY_KEY, data.get(TransferApplyBillConstant.BCOMPANYBO_KEY));
        // 设置 部门
        contractApplyCancelDyo.set(TransferApplyBillConstant.CURDEPT_KEY, data.get(TransferApplyBillConstant.BB_PO_ADMINORGBO_KEY));
        // 设置 岗位
        contractApplyCancelDyo.set(TransferApplyBillConstant.CURPOSTION_KEY, data.get(TransferApplyBillConstant.BB_PO_POSITIONBO_KEY));
        // 设置 职位
        contractApplyCancelDyo.set(TransferApplyBillConstant.CURJOB_KEY, data.get(TransferApplyBillConstant.BB_PO_JOB_KEY));
        // 设置 员工(HR员工)
        contractApplyCancelDyo.set(TransferApplyBillConstant.EMPLOYEE_KEY, data.get(TransferApplyBillConstant.BB_EM_TID));
        // 设置 员工(组织分配)
        contractApplyCancelDyo.set(TransferApplyBillConstant.ASSIGNMENT, data.get(TransferApplyBillConstant.BB_A_TID_KEY));
        // 设置 任职序号
        contractApplyCancelDyo.set(TransferApplyBillConstant.ORGRELSEQ_KEY, data.get(TransferApplyBillConstant.BB_PO_ORGRELSEQ_KEY));
        // 设置 居住地址
        contractApplyCancelDyo.set(TransferApplyBillConstant.RESIDENTIALADDRESS_KEY, cancelContract.getString(TransferApplyBillConstant.RESIDENTIALADDRESS_KEY));
        // 设置 户籍地址
        contractApplyCancelDyo.set(TransferApplyBillConstant.HOUSEHOLDREGISTER_KEY, cancelContract.getString(TransferApplyBillConstant.HOUSEHOLDREGISTER_KEY));

        // 设置 续签次数（续签用）
        contractApplyCancelDyo.set(TransferApplyBillConstant.RENEWCOUNT_KEY, getRenewCount(contractApplyCancelDyo));
        // 设置 人事管理组织
        contractApplyCancelDyo.set(TransferApplyBillConstant.ERMANORG_KEY, data.get(TransferApplyBillConstant.ORG_KEY));
        // 设置 管理部门
        contractApplyCancelDyo.set(TransferApplyBillConstant.ADMINORORG_KEY, data.get(TransferApplyBillConstant.BB_PO_ADMINORGBO_KEY));
        // 设置 员工组
        contractApplyCancelDyo.set(TransferApplyBillConstant.ERMANPERORG_KEY, data.get(TransferApplyBillConstant.BB_A_EMPGROUP_KEY));
        // 设置 档案类型
        setContractCategory(contractApplyCancelDyo);
        // 设置 解除原因
        DynamicObject contractReasonDy = contractReasonHelper.generateEmptyDynamicObject();
        contractReasonDy.set(TransferApplyBillConstant.ID_KEY, 1040L);
        contractApplyCancelDyo.set(TransferApplyBillConstant.CANCELREASONTYPE_KEY, contractReasonDy);// 其他

        // 设置 创建人
        contractApplyCancelDyo.set(GECEventConstant.CREATOR_KEY, UserServiceHelper.getCurrentUserId());

        return contractApplyCancelDyo;
    }

    // from: kd.hr.hlcm.business.domian.repository.ContractSignApplyRepository.getCancelContractByErManFile
    public DynamicObject getCancelContractByErManFile(DynamicObject dataEntity) {
        QFilter protocolTypeFilter = new QFilter(TransferApplyBillConstant.PROTOCOLTYPE_KEY, QCP.equals, "1");// 劳动合同
        QFilter personFilter = new QFilter(TransferApplyBillConstant.EMPLOYEE_KEY, QCP.equals, dataEntity.getLong(String.format(Locale.ROOT, "%s_id", TransferApplyBillConstant.BB_EM_TID)));
        QFilter posTypeFilter = new QFilter(TransferApplyBillConstant.POSTYPE, QCP.equals, dataEntity.getLong(String.format(Locale.ROOT, "%s_id", TransferApplyBillConstant.BB_PO_POSTYPE_KEY)));
        QFilter contractStatusFilter = new QFilter(TransferApplyBillConstant.CONTRACTSTATUS_KEY, QCP.equals, "1");// 生效中
        QFilter isCurFilter = new QFilter(TransferApplyBillConstant.IS_CURRENT_VERSION, QCP.equals, "1");
        String selectProperties = QueryFieldBuilder.create().add(TransferApplyBillConstant.STARTDATE_KEY)
                .add(TransferApplyBillConstant.PLANENDDATE_KEY)
                .add(TransferApplyBillConstant.NUMBER_KEY)
                .add(TransferApplyBillConstant.SUGGESTSIGNCOMPANY_KEY)
                .add(TransferApplyBillConstant.ACTUALSIGNCOMPANY_KEY)
                .add(TransferApplyBillConstant.CONTRACTSTATUS_KEY)
                .add(TransferApplyBillConstant.NAME_KEY)
                .add(TransferApplyBillConstant.CARDTYPE_KEY)
                .add(TransferApplyBillConstant.CARDNUMBER_KEY)
                .add(TransferApplyBillConstant.HOUSEHOLDREGISTER_KEY)
                .add(TransferApplyBillConstant.RESIDENTIALADDRESS_KEY)
                .add(TransferApplyBillConstant.EMPPHONE_KEY)
                .add(TransferApplyBillConstant.ACTUALSIGNCOMPANYHIS_KEY)
                .add(TransferApplyBillConstant.PERIODTYPE_KEY)
                .add(TransferApplyBillConstant.PERIODUNIT_KEY)
                .add(TransferApplyBillConstant.PERIOD_KEY)
                .buildSelect();
        // 这里要查所有属性出来，否则用到没查出来的字段会报异常
        DynamicObject[] contractDy = contractSourceHelper.loadDynamicObjectArray(new QFilter[]{protocolTypeFilter, personFilter, contractStatusFilter, posTypeFilter, isCurFilter});

        return getNewestContract(contractDy).orElse(null);
    }

    // from: kd.hr.hlcm.business.domian.repository.ContractSignApplyRepository.getNewestContract
    private Optional<DynamicObject> getNewestContract(DynamicObject[] contracts) {
        Comparator<DynamicObject> multipleComparator = buildNewestComparator();
        return Stream.of(contracts).max(multipleComparator);
    }

    // from: kd.hr.hlcm.business.domian.repository.ContractSignApplyRepository.buildNewestComparator
    private Comparator<DynamicObject> buildNewestComparator() {
        Comparator<DynamicObject> contractStatusComparator = Comparator.comparing((dy) -> dy.getString(TransferApplyBillConstant.CONTRACTSTATUS_KEY));
        Comparator<DynamicObject> comparingStartDate = Comparator.comparing((dy) -> dy.getDate(TransferApplyBillConstant.STARTDATE_KEY));
        Comparator<DynamicObject> comparingId = Comparator.comparingLong((dy) -> dy.getLong(TransferApplyBillConstant.ID_KEY));
        Comparator<DynamicObject> multipleComparing = contractStatusComparator.thenComparing(comparingStartDate).thenComparing(comparingId);
        return multipleComparing;
    }

    // from: kd.hr.hlcm.business.domian.repository.ContractSignApplyRepository.getRenewCount
    public static int getRenewCount(DynamicObject signBill) {
        DynamicObject oldContract = signBill.getDynamicObject(TransferApplyBillConstant.OLDCONTRACT_KEY);
        String businessType = signBill.getString(TransferApplyBillConstant.BUSINESSTYPE_KEY);
        if (Objects.isNull(oldContract)) {
            log.warn("renew select oldContract is null,curBusinessType|{}", businessType);
            return 0;
        } else {
            DynamicObject preContract = contractHelper.queryOne(TransferApplyBillConstant.RENEWCOUNT_KEY, new QFilter[]{new QFilter(TransferApplyBillConstant.ID_KEY, QCP.equals, oldContract.getPkValue())});
            int preRenewCount = preContract.getInt(TransferApplyBillConstant.RENEWCOUNT_KEY);
            log.info("preRenewCount|{},curBusinessType|{}", preRenewCount, businessType);
            return HRStringUtils.equals(businessType, BusinessTypeEnum.RENEW.getCombKey()) ? preRenewCount + 1 : preRenewCount;
        }
    }

    // from: kd.hr.hlcm.business.domian.utils.ContractSignUtils.setContractCategory
    public static void setContractCategory(DynamicObject signBill) {
        if (HRStringUtils.equals(signBill.getString(TransferApplyBillConstant.PROTOCOLTYPE_KEY), "1")) {
            DynamicObject posType = signBill.getDynamicObject(TransferApplyBillConstant.POSTYPE);
            if (!HRObjectUtils.isEmpty(posType)) {
                Object posTypeId = posType.getPkValue();
                if (Objects.equals(posTypeId, PostypeEnum.FULL.getCombKey())) {
                    signBill.set(TransferApplyBillConstant.CONTRACTCATEGORY_KEY, ContractCategoryEnum.MAIN.getCombKey());
                } else if (Objects.equals(posTypeId, PostypeEnum.EXPATRIATE.getCombKey())) {
                    signBill.set(TransferApplyBillConstant.CONTRACTCATEGORY_KEY, ContractCategoryEnum.OUTER.getCombKey());
                } else {
                    log.warn("posTypeId|{} is not 1010 or 1040", posTypeId);
                }

            }
        }
    }

    // from: kd.hr.hlcm.business.infrastructure.client.hbpm.impl.HbpmServiceImpl.getJobHis(java.lang.Long)
    public Long getJobHis(Long jobId) {
        Map<Long, Long> jobHisMap = getJobHis(Lists.newArrayList(jobId), new Date());
        return Optional.ofNullable(jobHisMap.get(jobId)).orElse(0L);
    }

    // from: kd.hr.hlcm.business.infrastructure.client.hbpm.impl.HbpmServiceImpl.getJobHis(java.util.List<java.lang.Long>)
    public Map<Long, Long> getJobHis(List<Long> jobIds, Date date) {
        filterEmpty(jobIds);
        Map<Long, Long> currIdHisIdMap = new HashMap<>(jobIds.size());
        if (jobIds.isEmpty())
            return currIdHisIdMap;
        try {
            HrApiResponse jobHisMap = HRMServiceHelper.invokeHRMPService("hbjm", "IHBJMJobService", "queryJobHisInfoByBoIdToMap", new Object[] { jobIds, date });
            log.info("IHBJMJobService queryJobHisInfoByBoIdToMap param response|{}", jobIds, jobHisMap);
            if (HRObjectUtils.isEmpty(jobHisMap))
                return currIdHisIdMap;
            List<Map<String, Object>> dataMap = (List<Map<String, Object>>)jobHisMap.getData();
            if (CollectionUtils.isEmpty(dataMap))
                return currIdHisIdMap;
            for (Map<String, Object> map : dataMap) {
                Object vid = map.get(TransferApplyBillConstant.ID_KEY);
                Object id = map.get(TransferApplyBillConstant.BOID_KEY);
                if (vid != null && id != null)
                    currIdHisIdMap.put((Long)id, Long.valueOf(vid.toString()));
            }
            log.info("getJobHis result|{}", currIdHisIdMap);
        } catch (Exception ex) {
            log.error("HbpmServiceImpl.getJobHis======jobBoid error..", ex);
            throw new KDException(ex, BosErrorCode.systemError, new Object[0]);
        }
        return currIdHisIdMap;
    }

    // from: kd.hr.hlcm.business.infrastructure.client.hbpm.impl.HbpmServiceImpl.filterEmpty
    private void filterEmpty(List<Long> ids) {
        log.info("before filter ids|{}", ids);
        ids.removeIf((id) -> id == null || id == 0L);
        log.info("after filter ids|{}", ids);
    }
}
