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

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import kd.bos.common.enums.EnableEnum;
import kd.bos.dataentity.OperateOption;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.metadata.IDataEntityProperty;
import kd.bos.dataentity.metadata.clr.DataEntityPropertyCollection;
import kd.bos.entity.operate.OperateOptionConst;
import kd.bos.entity.operate.result.IOperateInfo;
import kd.bos.entity.operate.result.OperationResult;
import kd.bos.exception.KDBizException;
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.service.operation.OperationServiceImpl;
import kd.hr.hbp.business.service.history.util.HisModelCopyUtil;
import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
import kd.hr.hbp.common.util.HRDynamicObjectUtils;
import kd.sdk.hr.hdm.common.enums.reg.RegBillStatusEnum;
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.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 岗位申请单生效服务
 * @from: kd.hr.homs.business.service.batcheffect.OrgBillBatchEffectService
 * @author: jtd
 * @date: 2026/1/10 15:49
 */
public class PositionBillEffectService {
    private static final Log log = LogFactory.getLog(PositionBillEffectService.class);

    HRBaseServiceHelper positionHelper = new HRBaseServiceHelper(PositionBillConstant.HBPM_POSITIONHR);

    public void billEffect(DynamicObject[] bills) {
        for (DynamicObject bill : bills) {
            Date effDate = bill.getDate(PositionBillConstant.NCKD_EFFDT);
            if (effDate == null) {
                throw new KDBizException("生效日期不能为空");
            }

            long billId = bill.getLong(PositionBillConstant.ID_KEY);
            Map<String, List<DynamicObject>> billEntryPositionDyMap = getBillEntryPositionDyMap(billId);
            Map<Long, DynamicObject> positionBoIdMap = getAllCurrentVersionParentDyMap(billEntryPositionDyMap);
            newAddPositionEffect(billEntryPositionDyMap.get(PositionChangeTypeEnum.ADD.getNumber()), billId, effDate);
            confirmChangePositionEffect(billEntryPositionDyMap.get(PositionChangeTypeEnum.CHANGE.getNumber()), positionBoIdMap, billId, effDate);
            auditBill(billId);
        }
    }

    private void confirmChangePositionEffect(List<DynamicObject> confirmChangePositionEntity, Map<Long, DynamicObject> positionBoIdMap, long billId, Date effDate) {
        if (confirmChangePositionEntity != null && !confirmChangePositionEntity.isEmpty()) {
            Map<Long, DynamicObject> dbPositionMap = getDbDyMap(confirmChangePositionEntity);
            List<DynamicObject> confirmChangePositionDys = Lists.newArrayListWithExpectedSize(confirmChangePositionEntity.size());
            HisModelCopyUtil hisModelCopyUtil = new HisModelCopyUtil();

            // 获取 行政组织业务ID
            List<Long> adminorgBoIds = Lists.newArrayListWithExpectedSize(confirmChangePositionEntity.size());
            for (DynamicObject confirmChangePosition : confirmChangePositionEntity) {
                adminorgBoIds.add(confirmChangePosition.getLong(PositionBillConstant.NCKD_ADMINORGBOID_KEY));
            }

            // 根据组织BOID从数据库中获取组织信息
            DynamicObject[] adminOrgDyos = HRBaseServiceHelper.create(PositionBillConstant.ADMINORG_ENTITYID).loadDynamicObjectArray(new QFilter[]{new QFilter(PositionBillConstant.ID_KEY, QCP.in, adminorgBoIds)});
            Map<Long, DynamicObject> dbAdminOrgMap = Maps.newHashMapWithExpectedSize(adminOrgDyos.length);
            for (DynamicObject adminOrgDyo : adminOrgDyos) {
                dbAdminOrgMap.put(adminOrgDyo.getLong(PositionBillConstant.BOID_KEY), adminOrgDyo);
            }

            // 获取岗位要转换的键值
            Map<String, String> positionTransKeyMap = PositionBillServiceHelper.getPositionTransKeyMap();
            for(DynamicObject confirmChangePosition : confirmChangePositionEntity) {
                DynamicObject positionDy = confirmChangePosition.getDynamicObject(PositionBillConstant.NCKD_POSITION_KEY);
                long positionId = positionDy.getLong(PositionBillConstant.BOID_KEY);
                DynamicObject dbPositionDy = dbPositionMap.get(positionId);
                if (dbPositionDy != null) {
                    DynamicObject copyDy = hisModelCopyUtil.copyTempVersionData(dbPositionDy, positionHelper);
                    HRDynamicObjectUtils.copy(confirmChangePosition, copyDy, positionTransKeyMap);
                    DynamicObject parentVersionDy = confirmChangePosition.getDynamicObject(PositionBillConstant.NCKD_PARENT);
                    if (parentVersionDy != null) {
                        copyDy.set(PositionBillConstant.PARENT_KEY, positionBoIdMap.get(parentVersionDy.getLong(PositionBillConstant.BOID_KEY)));
                    } else {
                        copyDy.set(PositionBillConstant.PARENT_KEY, null);
                    }

                    copyDy.set(PositionBillConstant.BSED_KEY, effDate);
                    copyDy.set(PositionBillConstant.ENABLE, EnableEnum.YES.getCode());
                    // 设置 行政组织为业务对象
                    copyDy.set(PositionBillConstant.ADMINORG, dbAdminOrgMap.get(confirmChangePosition.getLong(PositionBillConstant.NCKD_ADMINORGBOID_KEY)));

                    confirmChangePositionDys.add(copyDy);
                }
            }

            if (!confirmChangePositionDys.isEmpty()) {
                OperateOption operateOption = OperateOption.create();
                operateOption.setVariableValue(OperateOptionConst.ISHASRIGHT, "true");
                OperationServiceImpl opImpl = new OperationServiceImpl();
                operateOption.setVariableValue(OperateOptionConst.SKIPCHECKPERMISSION, "true");
                OperationResult operationResult = opImpl.localInvokeOperation(PositionBillConstant.CONFIRMCHANGE_OP, confirmChangePositionDys.toArray(new DynamicObject[0]), operateOption);
                if (!operationResult.isSuccess()) {
                    StringBuilder errorMsg = new StringBuilder();

                    for(IOperateInfo operateInfo : operationResult.getAllErrorOrValidateInfo()) {
                        errorMsg.append(operateInfo.getMessage());
                    }

                    throw new KDBizException(errorMsg.toString());
                }
            }

        }
    }

    private void newAddPositionEffect(List<DynamicObject> newAddPositionEntity, long billId, Date effDate) {
        if (newAddPositionEntity != null && !newAddPositionEntity.isEmpty()) {
            Map<Long, DynamicObject> dbPositionMap = getDbDyMap(newAddPositionEntity);
            List<DynamicObject> addPositionDys = Lists.newArrayListWithExpectedSize(newAddPositionEntity.size());

            for(DynamicObject addPositionEntry : newAddPositionEntity) {
                DynamicObject positionDy = addPositionEntry.getDynamicObject(PositionBillConstant.NCKD_POSITION_KEY);
                if (positionDy == null) {
                    log.error("PositionBillEffectService.newAddPositionEffect positionDy is empty");
                } else {
                    long positionId = positionDy.getLong(PositionBillConstant.ID_KEY);
                    DynamicObject dbPositionDy = dbPositionMap.get(positionId);
                    if (dbPositionDy == null) {
                        log.error("PositionBillEffectService.newAddPositionEffect dbPositionDy is empty");
                    } else {
                        dbPositionDy.set(PositionBillConstant.BSED_KEY, effDate);
                        dbPositionDy.set(PositionBillConstant.ISSTANDARDPOS_KEY, "0");
                        addPositionDys.add(dbPositionDy);
                    }
                }
            }

            if (!addPositionDys.isEmpty()) {
                OperateOption operateOption = OperateOption.create();
                operateOption.setVariableValue(OperateOptionConst.ISHASRIGHT, "true");
                OperationServiceImpl opImpl = new OperationServiceImpl();
                operateOption.setVariableValue(OperateOptionConst.SKIPCHECKPERMISSION, "true");
                OperationResult submitResult = opImpl.localInvokeOperation(PositionBillConstant.SAVE_OP, addPositionDys.toArray(new DynamicObject[0]), operateOption);
                if (!submitResult.isSuccess()) {
                    StringBuilder errorMsg = new StringBuilder();

                    for(IOperateInfo operateInfo : submitResult.getAllErrorOrValidateInfo()) {
                        errorMsg.append(operateInfo.getMessage());
                    }

                    throw new KDBizException(errorMsg.toString());
                }
            }

        }
    }

    private Map<Long, DynamicObject> getDbDyMap(List<DynamicObject> entryDys) {
        Set<Long> positionIds = Sets.newHashSetWithExpectedSize(entryDys.size());

        for(DynamicObject entryOrg : entryDys) {
            long positionId = getDyBdPropId(entryOrg, PositionBillConstant.NCKD_POSITION_KEY);
            positionIds.add(positionId);
        }

        List<Long> boIds = Arrays.stream(positionHelper.queryOriginalArray(PositionBillConstant.BOID_KEY, new QFilter[]{new QFilter(PositionBillConstant.ID_KEY, QCP.in, positionIds)})).map((dy) -> dy.getLong(PositionBillConstant.BOID_KEY)).collect(Collectors.toList());
        DynamicObject[] dbPositionDys = positionHelper.loadDynamicObjectArray(new QFilter[]{new QFilter(PositionBillConstant.ID_KEY, QCP.in, boIds)});
        return Arrays.stream(dbPositionDys).collect(Collectors.toMap((dy) -> dy.getLong(PositionBillConstant.ID_KEY), Function.identity()));
    }

    // from: kd.hr.haos.business.util.PropertyGetUtils.getDyBdPropId
    private long getDyBdPropId(DynamicObject dy, String property) {
        DataEntityPropertyCollection properties = dy.getDataEntityType().getProperties();
        IDataEntityProperty propertyType = properties.get(property);
        if (propertyType == null) {
            if (property.endsWith(".id")) {
                property = property.substring(0, property.lastIndexOf("."));
                propertyType = properties.get(property);
                if (propertyType == null) {
                    return 0L;
                }
            } else {
                if (!property.endsWith("_id")) {
                    return 0L;
                }

                property = property.substring(0, property.lastIndexOf("_"));
                propertyType = properties.get(property);
                if (propertyType == null) {
                    return 0L;
                }
            }
        }

        Object propObj = dy.get(property);
        if (propObj instanceof Long) {
            return (Long) propObj;
        } else {
            return propObj instanceof DynamicObject ? ((DynamicObject) propObj).getLong("id") : 0L;
        }
    }

    private Map<String, List<DynamicObject>> getBillEntryPositionDyMap(Long billId) {
        HRBaseServiceHelper helper = new HRBaseServiceHelper(PositionBillConstant.NCKD_POSITIONBILLENTRY_ENTITY);
        QFilter filter = new QFilter(PositionBillConstant.NCKD_BILLID, QCP.equals, billId);
        DynamicObject[] entries = helper.loadDynamicObjectArray(new QFilter[]{filter});
        return Arrays.stream(entries).collect(Collectors.groupingBy((dy) -> dy.getString(String.join(".", PositionBillConstant.NCKD_CHANGETYPE, PositionBillConstant.NUMBER_KEY))));
    }

    private Map<Long, DynamicObject> getAllCurrentVersionParentDyMap(Map<String, List<DynamicObject>> entryValues) {
        List<Long> parentPositionBoIds = Lists.newArrayListWithExpectedSize(10);

        for(Map.Entry<String, List<DynamicObject>> entry : entryValues.entrySet()) {
            for(DynamicObject entryValue : entry.getValue()) {
                DynamicObject parentPositionDy = entryValue.getDynamicObject(PositionBillConstant.NCKD_PARENT);
                if (parentPositionDy != null) {
                    parentPositionBoIds.add(parentPositionDy.getLong(PositionBillConstant.BOID_KEY));
                }
            }
        }

        DynamicObject[] dbPositionDys = positionHelper.loadDynamicObjectArray(new QFilter[]{new QFilter(PositionBillConstant.ID_KEY, QCP.in, parentPositionBoIds)});
        return Arrays.stream(dbPositionDys).collect(Collectors.toMap((dy) -> dy.getLong(PositionBillConstant.ID_KEY), Function.identity()));
    }

    public void auditBill(long billId) {
        HRBaseServiceHelper serviceHelper = new HRBaseServiceHelper(PositionBillConstant.NCKD_POSITIONBILL_ENTITY);
        DynamicObject billDy = serviceHelper.loadOne(PositionBillConstant.BILL_STATUS_KEY, (new QFilter(PositionBillConstant.ID_KEY, QCP.equals, billId)).toArray());
        if (billDy != null) {
            billDy.set(PositionBillConstant.BILL_STATUS_KEY, RegBillStatusEnum.APPROVEPASSED.getCode());
            serviceHelper.updateOne(billDy);
        }

    }
}
