package nckd.jxccl.hrmp.hbpm.business.hr.service.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.metadata.IDataEntityProperty;
import kd.bos.dataentity.metadata.clr.DataEntityPropertyCollection;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
import kd.hr.hbp.common.util.HRDynamicObjectUtils;
import kd.hr.hbp.common.util.HRStringUtils;
import nckd.jxccl.base.common.utils.PatternUtil;
import nckd.jxccl.hrmp.hbpm.common.hr.PositionBillConstant;
import nckd.jxccl.hrmp.hbpm.common.hr.PositionChangeTypeEnum;

import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

;

/**
 * 岗位申请单保存服务
 * @from: kd.hr.homs.business.domain.orgbatch.service.impl.OrgBatchBillSaveHelper
 * @author: jtd
 * @date: 2025/12/27 15:04
 */
public class PositionBillSaveHelper {
    private static PositionBillSaveHelper INSTANCE = new PositionBillSaveHelper();
    private static final Log logger = LogFactory.getLog(PositionBillSaveHelper.class);
    private static final HRBaseServiceHelper positionBillEntryEntityHelper = new HRBaseServiceHelper(PositionBillConstant.NCKD_POSITIONBILLENTRY_ENTITY);

    public static PositionBillSaveHelper getInstance() {
        return INSTANCE;
    }

    public void positionBillSave(DynamicObject dataEntity) {
        long startTime = System.currentTimeMillis();
        HRBaseServiceHelper positionBillEntryEntityHelper = new HRBaseServiceHelper(PositionBillConstant.NCKD_POSITIONBILLENTRY_ENTITY);
        Long billId = dataEntity.getLong(PositionBillConstant.ID_KEY);
        QFilter billIdFilter = new QFilter(PositionBillConstant.NCKD_BILLID, QCP.equals, billId);
        DynamicObject[] positionBillEntryEntityDyns = positionBillEntryEntityHelper.loadDynamicObjectArray(new QFilter[]{billIdFilter});
        Set<Long> positionIdSetFromDB = Arrays.stream(positionBillEntryEntityDyns).map((dyn) -> dyn.getLong(String.join(".", PositionBillConstant.NCKD_POSITION_KEY, PositionBillConstant.ID_KEY))).collect(Collectors.toSet());
        Map<Long, DynamicObject> positionId2DynFromDBMap = Arrays.stream(positionBillEntryEntityDyns).collect(Collectors.toMap((dyn) -> dyn.getLong(String.join(".", PositionBillConstant.NCKD_POSITION_KEY, PositionBillConstant.ID_KEY)), (dyn) -> dyn, (k, v) -> k));
        DynamicObjectCollection allEntryEntityDyn = getEntryEntityData(dataEntity);
        if (allEntryEntityDyn.size() != 0) {
            List<Long> positionIdList = getAllEntryPositionId(allEntryEntityDyn);
            Map<Long, DynamicObject> positionId2BasicInfoDynMap = PositionBillServiceHelper.getPositionId2BasicInfoDynMapByIds(positionIdList);
            List<DynamicObject> needSaveEntryDynList = Lists.newArrayListWithExpectedSize(allEntryEntityDyn.size());

            for(DynamicObject entryEntityDyn : allEntryEntityDyn) {
                String suffix = getSuffixFromEntryEntityDyn(entryEntityDyn);
                Long positionId = getPositionId(entryEntityDyn, suffix);
                DynamicObject positionBillEntryDyn;
                if (positionIdSetFromDB.contains(positionId)) {
                    positionBillEntryDyn = positionId2DynFromDBMap.get(positionId);
                } else {
                    positionBillEntryDyn = positionBillEntryEntityHelper.generateEmptyDynamicObject();
                    positionBillEntryDyn.set(PositionBillConstant.NCKD_BILLID, dataEntity.getLong(PositionBillConstant.ID_KEY));
                    DynamicObject basicInfoDyn = positionId2BasicInfoDynMap.get(positionId);
                    assembleSaveEntryDyn(positionBillEntryDyn, basicInfoDyn);
                }

                boolean neeSave = coverdEntryValue(positionBillEntryDyn, entryEntityDyn, suffix);
                if (neeSave || !positionIdSetFromDB.contains(positionId)) {
                    needSaveEntryDynList.add(positionBillEntryDyn);
                }
            }

            if (needSaveEntryDynList.isEmpty()) {
                logger.info("needSaveEntryDynList is empty");
            }

            resetSequence(needSaveEntryDynList);
            setAdminOrgBoId(needSaveEntryDynList, positionId2BasicInfoDynMap);
            if (needSaveEntryDynList.isEmpty()) {
                logger.info("needSaveEntryDynList is empty");
            } else {
                positionBillEntryEntityHelper.save(needSaveEntryDynList.toArray(new DynamicObject[0]));
                billIdFilter.and(PositionBillConstant.CREATOR_KEY, QCP.equals, 0);
                positionBillEntryEntityHelper.deleteByFilter(billIdFilter.toArray());
                logger.info(String.format(Locale.ROOT, "positionBillSave() time cost is: %s", System.currentTimeMillis() - startTime));
            }
        }
    }

    private void resetSequence(List<DynamicObject> needSaveEntryDynList) {
        Map<Long, Integer> map = Maps.newHashMapWithExpectedSize(3);
        needSaveEntryDynList.stream().forEach((dyn) -> {
            long changeTypeId = dyn.getLong(String.join(".", PositionBillConstant.NCKD_CHANGETYPE, PositionBillConstant.ID_KEY));
            if (changeTypeId == 0L) {
                changeTypeId = dyn.getLong(PositionBillConstant.NCKD_CHANGETYPE);
            }

            if (Objects.isNull(map.get(changeTypeId))) {
                int sequence = 0;
                QFilter billIdFilter = new QFilter(PositionBillConstant.NCKD_BILLID, QCP.equals, dyn.get(PositionBillConstant.NCKD_BILLID));
                QFilter changeTypeFilter = new QFilter(String.join(".", PositionBillConstant.NCKD_CHANGETYPE, PositionBillConstant.ID_KEY), QCP.equals, changeTypeId);
                DynamicObject[] dys = positionBillEntryEntityHelper.query(PositionBillConstant.NCKD_SEQUENCE, new QFilter[]{billIdFilter, changeTypeFilter}, String.format("%s DESC", PositionBillConstant.NCKD_SEQUENCE), 1);
                if (dys != null && dys.length > 0) {
                    sequence = dys[0].getInt(PositionBillConstant.NCKD_SEQUENCE);
                }

                ++sequence;
                dyn.set(PositionBillConstant.NCKD_SEQUENCE, sequence);
                map.put(changeTypeId, sequence);
            } else {
                Integer sequence = map.get(changeTypeId);
                sequence = sequence + 1;
                dyn.set(PositionBillConstant.NCKD_SEQUENCE, sequence);
                map.put(changeTypeId, sequence);
            }

        });
    }

    public Long getPositionId(DynamicObject entryEntityDynFromPage, String suffix) {
        String idFieldName = String.join(".", PositionBillConstant.NCKD_POSITION_KEY, PositionBillConstant.ID_KEY);
        if (HRStringUtils.equals(entryEntityDynFromPage.getString(spliceTwoStringByUnderLine(suffix, String.join(".", PositionBillConstant.NCKD_CHANGETYPE, PositionBillConstant.NUMBER_KEY))), PositionChangeTypeEnum.ADD.getNumber())) {
            idFieldName = PositionBillConstant.NCKD_POSITION_KEY;
        }

        String positionFiledName = spliceTwoStringByUnderLine(suffix, idFieldName);
        return entryEntityDynFromPage.getLong(positionFiledName);
    }

    public String getSuffixFromEntryEntityDyn(DynamicObject entryEntityDynFromPage) {
        String entryEntityName = entryEntityDynFromPage.getDynamicObjectType().getName();
        int lastUnderLineIndex = entryEntityName.lastIndexOf("_");
        return entryEntityName.substring(lastUnderLineIndex + 1);
    }

    public void assembleSaveEntryDyn(DynamicObject positionBillEntryDyn, DynamicObject basicInfoDyn) {
        // 获取岗位要转换的键值
        Map<String, String> positionReverseTransKeyMap = PositionBillServiceHelper.getPositionTransKeyMap().entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey, (oldValue, newValue) -> newValue));
        HRDynamicObjectUtils.copy(basicInfoDyn, positionBillEntryDyn, positionReverseTransKeyMap);

        // 原上级岗位特殊处理
        positionBillEntryDyn.set(PositionBillConstant.NCKD_ORIPARENT_KEY, positionBillEntryDyn.get(PositionBillConstant.NCKD_PARENT));
    }

    public DynamicObjectCollection getEntryEntityData(DynamicObject dataEntity) {
        List<String> entryExcludeAddName = Arrays.stream(PositionChangeTypeEnum.values()).filter((changeType) -> changeType != PositionChangeTypeEnum.ADD).map((changeType) -> changeType.getTag(PositionBillConstant.NCKD_ENTRYENTITYUNDERLINE_KEY)).collect(Collectors.toList());
        DynamicObjectCollection dynColl = new DynamicObjectCollection();
        entryExcludeAddName.forEach((entryName) -> dynColl.addAll(dataEntity.getDynamicObjectCollection(entryName)));
        return dynColl;
    }

    public List<Long> getAllEntryPositionId(DynamicObjectCollection allEntryEntityDyns) {
        List<Long> positionIdList = Lists.newArrayListWithExpectedSize(allEntryEntityDyns.size());
        allEntryEntityDyns.forEach((dyn) -> {
            String suffix = getSuffixFromEntryEntityDyn(dyn);
            Long positionId = getPositionId(dyn, suffix);
            positionIdList.add(positionId);
        });
        return positionIdList;
    }

    private void setAdminOrgBoId(List<DynamicObject> needSaveEntryDynList, Map<Long, DynamicObject> positionId2BasicInfoDynMap) {
        needSaveEntryDynList.forEach((entryDyn) -> {
            long positionId = entryDyn.getLong(String.join(".", PositionBillConstant.NCKD_POSITION_KEY, PositionBillConstant.ID_KEY));
            DynamicObject basicInfoDyn = positionId2BasicInfoDynMap.get(positionId);
            entryDyn.set(PositionBillConstant.NCKD_ADMINORGBOID_KEY, basicInfoDyn.getDynamicObject(PositionBillConstant.ADMINORG).getLong(PositionBillConstant.BOID_KEY));
        });
    }

    public boolean coverdEntryValue(DynamicObject positionBillEntryDyn, DynamicObject entryEntity, String suffix) {
        boolean needSave = false;
        // 获取分录要转换的键值
        Map<String, String> posBillEntryTransKeyMap = PositionBillServiceHelper.getPosBillEntryTransKeyMap();
        DataEntityPropertyCollection props = positionBillEntryDyn.getDataEntityType().getProperties();

        for(IDataEntityProperty property : entryEntity.getDataEntityType().getProperties()) {
            String propName = property.getName();
            if (PatternUtil.isExProperty(propName) && propName.endsWith("_"+suffix)) {
                String propNameSub = PositionBillServiceHelper.getNoLineSuffixProp(propName, "_"+suffix);
                propNameSub = posBillEntryTransKeyMap.getOrDefault(propNameSub, propNameSub);
                IDataEntityProperty prop = props.get(propNameSub);
                Object oldVal = positionBillEntryDyn.get(propNameSub);
                Object newVal = entryEntity.get(propName);
                if (prop != null && !(oldVal == null && newVal == null)) {
                    if ((newVal == null && oldVal != null) || (newVal != null && oldVal == null) || !HRDynamicObjectUtils.compareValues(newVal, oldVal)) {
                        needSave = true;
                    }
                }

                // 类型相同的情况下才覆盖值，避免后续获取值的时候类型转换异常
                if (prop != null && property.getPropertyType() == prop.getPropertyType()) {
                    positionBillEntryDyn.set(propNameSub, newVal);
                }
            }
        }
        positionBillEntryDyn.set(PositionBillConstant.ID_KEY, entryEntity.get(PositionBillConstant.ID_KEY));

        return needSave;
    }

    public String spliceTwoStringByUnderLine(String oneString, String otherString) {
        String[] str = otherString.split("\\.");
        return str.length > 1 ? str[0] + "_" + oneString + "." + str[1] : otherString + "_" + oneString;
    }

}
