package nckd.jxccl.hrmp.hbpm.plugin.operate.hr.validator;

import com.google.common.collect.Lists;
import kd.bos.common.enums.EnableEnum;
import kd.bos.dataentity.OperateOption;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.entity.ExtendedDataEntity;
import kd.bos.entity.operate.OperateOptionConst;
import kd.bos.entity.operate.result.OperateErrorInfo;
import kd.bos.entity.operate.result.OperationResult;
import kd.bos.entity.validate.AbstractValidator;
import kd.bos.entity.validate.ValidateResult;
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.servicehelper.operation.OperationServiceHelper;
import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
import kd.hr.hbp.common.util.HRStringUtils;
import nckd.jxccl.hrmp.hbpm.business.hr.service.impl.PositionBillSaveHelper;
import nckd.jxccl.hrmp.hbpm.business.hr.service.impl.PositionBillServiceHelper;
import nckd.jxccl.hrmp.hbpm.common.hr.PositionBillConstant;
import nckd.jxccl.hrmp.hbpm.common.hr.PositionChangeTypeEnum;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 岗位申请单保存校验器
 * @from: kd.hr.homs.opplugin.web.orgbatch.validator.AdminOrgBillSaveValidator
 * @author: jtd
 * @date: 2026/1/2 16:21
 */
public class PositionBillSaveValidator extends AbstractValidator {
    private static final Log LOG = LogFactory.getLog(PositionBillSaveValidator.class);
    private final Map<String, HRBaseServiceHelper> helperMap = new ConcurrentHashMap(PositionChangeTypeEnum.values().length);
    private final String suffix = "“%s”中：";
    private final String suffix_with_name = "“%s”中“%s”：";

    @Override
    public void validate() {
        ExtendedDataEntity[] entities = getDataEntities();

        for(ExtendedDataEntity entity : entities) {
            checkNotCommonEntryData(entity);
        }
    }

    private void checkNotCommonEntryData(ExtendedDataEntity entity) {
        PositionBillSaveHelper positionBillSaveHelper = PositionBillSaveHelper.getInstance();
        DynamicObject dataEntity = entity.getDataEntity();
        long billId = dataEntity.getLong(PositionBillConstant.ID_KEY);
        Date effDate = dataEntity.getDate(PositionBillConstant.NCKD_EFFDT);
        List<DynamicObject> positionBillEntryEntityDyns = getAllDbEntryDys(billId);
        Map<Long, List<DynamicObject>> positionId2DynFromDBListMap = positionBillEntryEntityDyns.stream().collect(Collectors.groupingBy((dyn) -> dyn.getLong(String.join(".", PositionBillConstant.NCKD_POSITION_KEY, PositionBillConstant.ID_KEY))));
        DynamicObjectCollection allEntryEntityDyn = Arrays.stream(PositionChangeTypeEnum.values()).map(changeTypeEnum -> dataEntity.getDynamicObjectCollection(changeTypeEnum.getTag(PositionBillConstant.NCKD_ENTRYENTITYUNDERLINE_KEY))).collect(DynamicObjectCollection::new, DynamicObjectCollection::addAll, DynamicObjectCollection::addAll);
        if (!allEntryEntityDyn.isEmpty()) {
            List<Long> positionIdList = positionBillSaveHelper.getAllEntryPositionId(allEntryEntityDyn);
            Map<Long, DynamicObject> positionId2BasicInfoDynMap = PositionBillServiceHelper.getPositionId2BasicInfoDynMapByIds(positionIdList);
            List<DynamicObject> needSaveEntryDynList = Lists.newArrayListWithExpectedSize(allEntryEntityDyn.size());

            for(DynamicObject entryEntityDyn : allEntryEntityDyn) {
                String suffix = positionBillSaveHelper.getSuffixFromEntryEntityDyn(entryEntityDyn);
                String changeTypeNumber = PositionChangeTypeEnum.getNumberByTag(suffix);
                Long positionId = positionBillSaveHelper.getPositionId(entryEntityDyn, suffix);
                if (positionId != null && positionId != 0L) {
                    DynamicObject positionBillEntryDyn = null;
                    List<DynamicObject> dbEntryDys = positionId2DynFromDBListMap.get(positionId);
                    if (dbEntryDys != null) {
                        for(DynamicObject dbEntryDy : dbEntryDys) {
                            String dbChangeTypeNumber = dbEntryDy.getString(String.join(".", PositionBillConstant.NCKD_CHANGETYPE, PositionBillConstant.NUMBER_KEY));
                            if (HRStringUtils.equals(dbChangeTypeNumber, changeTypeNumber)) {
                                positionBillEntryDyn = dbEntryDy;
                                break;
                            }
                        }
                    }

                    if (positionBillEntryDyn == null) {
                        HRBaseServiceHelper helper = getHelperByChangeType(changeTypeNumber);
                        if (helper == null) {
                            continue;
                        }

                        positionBillEntryDyn = helper.generateEmptyDynamicObject();
                        positionBillEntryDyn.set(PositionBillConstant.NCKD_BILLID, dataEntity.getLong(PositionBillConstant.ID_KEY));
                        DynamicObject basicInfoDyn = positionId2BasicInfoDynMap.get(positionId);
                        positionBillSaveHelper.assembleSaveEntryDyn(positionBillEntryDyn, basicInfoDyn);
                    }

                    positionBillSaveHelper.coverdEntryValue(positionBillEntryDyn, entryEntityDyn, suffix);
                    Object enable = positionBillEntryDyn.get(PositionBillConstant.ENABLE);
                    if (enable == null) {
                        positionBillEntryDyn.set(PositionBillConstant.ENABLE, EnableEnum.YES.getCode());
                    }

                    positionBillEntryDyn.set(PositionBillConstant.NCKD_BSED, effDate);
                    needSaveEntryDynList.add(positionBillEntryDyn);
                }
            }

            Map<String, List<DynamicObject>> groupByMap = needSaveEntryDynList.stream().collect(Collectors.groupingBy((dy) -> dy.getString(String.join(".", PositionBillConstant.NCKD_CHANGETYPE, PositionBillConstant.NUMBER_KEY))));
            OperateOption operateOption = OperateOption.create();
            operateOption.setVariableValue(PositionBillConstant.OP_VALIDATOR_BILL_POSITION_ALL_CHANGE_POSITION_KEY, PositionBillServiceHelper.getThisBillAllValidateDataStr(dataEntity));
            operateOption.setVariableValue(PositionBillConstant.OP_VALIDATOR_BILL_POSITION_NEW_POSITION_NUMBERS_KEY, PositionBillServiceHelper.getThisBillPositionNumbersStr(dataEntity));
            operateOption.setVariableValue(PositionBillConstant.OP_BILL_SIBLING_NAMES_MAP, PositionBillServiceHelper.getThisBillPositionNamesStr(dataEntity));
            operateOption.setVariableValue(PositionBillConstant.OP_VALIDATOR_SUFFIX_IGNORE, Boolean.TRUE.toString());

            for(Map.Entry<String, List<DynamicObject>> entry : groupByMap.entrySet()) {
                String changeTypeNumber = entry.getKey();
                List<DynamicObject> entryDynList = entry.getValue();
                Map<Object, DynamicObject> saveMap = entryDynList.stream().collect(Collectors.toMap((dy) -> dy.get(PositionBillConstant.ID_KEY), (dy) -> dy, (v1, v2) -> v1));
                String tagName = PositionChangeTypeEnum.getTipByNumber(changeTypeNumber);
                String entityNumber = PositionChangeTypeEnum.getTagByNumber(PositionBillConstant.NCKD_POSBILLENTRY_KEY, changeTypeNumber);
                OperationResult operationResult = executeOperateOnlyValidate(entryDynList.toArray(new DynamicObject[0]), entityNumber, operateOption, PositionBillConstant.SAVE_OP);
                if (operationResult != null && !operationResult.isSuccess()) {
                    for(ValidateResult validateError : operationResult.getValidateResult().getValidateErrors()) {
                        for(OperateErrorInfo operateErrorInfo : validateError.getAllErrorInfo()) {
                            Object pkValue = operateErrorInfo.getPkValue();
                            DynamicObject errorDy = saveMap.get(pkValue);
                            String message = operateErrorInfo.getMessage();
                            if (errorDy == null) {
                                addErrorMessage(entity, String.format(this.suffix, tagName) + message);
                            } else {
                                DynamicObject versionDy = errorDy.getDynamicObject(PositionBillConstant.NCKD_POSITION_KEY);
                                if (HRStringUtils.isNotEmpty(message) && message.contains(versionDy.getString(PositionBillConstant.NAME_KEY))) {
                                    addErrorMessage(entity, String.format(this.suffix, tagName) + message);
                                } else {
                                    addErrorMessage(entity, String.format(this.suffix_with_name, tagName, versionDy.getString(PositionBillConstant.NAME_KEY)) + message);
                                }
                            }
                        }
                    }
                }
            }

        }
    }

    private OperationResult executeOperateOnlyValidate(DynamicObject[] positionBillEntries, String entityNumber, OperateOption option, String opKey) {
        OperateOption operateOption = option;
        if (option == null) {
            operateOption = OperateOption.create();
        }

        operateOption.setVariableValue(OperateOptionConst.ISHASRIGHT, Boolean.TRUE.toString());
        operateOption.setVariableValue(OperateOptionConst.ONLY_VALIDATE, Boolean.TRUE.toString());

        try {
            return OperationServiceHelper.executeOperate(opKey, entityNumber, positionBillEntries, operateOption);
        } catch (Exception ex) {
            LOG.error("executeSaveOperateOnlyValidate_error", ex);
            throw ex;
        }
    }

    private List<DynamicObject> getAllDbEntryDys(long billId) {
        List<DynamicObject> entryDys = Lists.newArrayListWithExpectedSize(10);

        for(PositionChangeTypeEnum changeTypeEnum : PositionChangeTypeEnum.values()) {
            DynamicObject[] entries = getDbEntryDysByChangeType(billId, changeTypeEnum.getNumber());
            if (entries != null) {
                entryDys.addAll(Arrays.asList(entries));
            }
        }

        return entryDys;
    }

    private DynamicObject[] getDbEntryDysByChangeType(long billId, String changeTypeNumber) {
        HRBaseServiceHelper helper = getHelperByChangeType(changeTypeNumber);
        if (helper == null) {
            return new DynamicObject[0];
        } else {
            QFilter billIdFilter = new QFilter(PositionBillConstant.NCKD_BILLID, QCP.equals, billId);
            QFilter changeTypeFilter = new QFilter(String.join(".", PositionBillConstant.NCKD_CHANGETYPE, PositionBillConstant.NUMBER_KEY), QCP.equals, changeTypeNumber);
            return helper.loadDynamicObjectArray(new QFilter[]{billIdFilter, changeTypeFilter});
        }
    }

    private HRBaseServiceHelper getHelperByChangeType(String changeTypeNumber) {
        String entityNumber = PositionChangeTypeEnum.getTagByNumber(PositionBillConstant.NCKD_POSBILLENTRY_KEY, changeTypeNumber);
        if (HRStringUtils.isNotEmpty(entityNumber)) {
            HRBaseServiceHelper helper = helperMap.get(entityNumber);
            if (helper == null) {
                helper = new HRBaseServiceHelper(entityNumber);
                helperMap.put(entityNumber, helper);
            }

            return helper;
        } else {
            return null;
        }
    }
}
