package nckd.jxccl.hrmp.hbpm.plugin.form.hr;

import kd.bos.common.enums.EnableEnum;
import kd.bos.context.RequestContext;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.metadata.IDataEntityProperty;
import kd.bos.dataentity.metadata.IDataEntityType;
import kd.bos.dataentity.metadata.clr.DataEntityPropertyCollection;
import kd.bos.dataentity.metadata.dynamicobject.DynamicProperty;
import kd.bos.dataentity.serialization.SerializationUtils;
import kd.bos.entity.MainEntityType;
import kd.bos.entity.datamodel.events.PropertyChangedArgs;
import kd.bos.entity.operate.result.OperationResult;
import kd.bos.entity.property.BasedataProp;
import kd.bos.entity.property.EntryProp;
import kd.bos.entity.property.LongProp;
import kd.bos.entity.property.MulBasedataProp;
import kd.bos.form.ConfirmCallBackListener;
import kd.bos.form.ConfirmTypes;
import kd.bos.form.MessageBoxOptions;
import kd.bos.form.MessageBoxResult;
import kd.bos.form.events.AfterDoOperationEventArgs;
import kd.bos.form.events.BeforeDoOperationEventArgs;
import kd.bos.form.events.MessageBoxClosedEvent;
import kd.bos.form.field.BasedataEdit;
import kd.bos.form.field.events.BeforeF7SelectEvent;
import kd.bos.form.field.events.BeforeF7SelectListener;
import kd.bos.form.plugin.AbstractFormPlugin;
import kd.bos.list.ListShowParameter;
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.permission.api.HasPermOrgResult;
import kd.bos.servicehelper.permission.PermissionServiceHelper;
import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
import kd.hr.hbp.common.model.AuthorizedOrgResult;
import kd.hr.hbp.common.util.HRDateTimeUtils;
import kd.hr.hbp.common.util.HRDynamicObjectUtils;
import kd.hr.hbp.common.util.HRStringUtils;
import nckd.jxccl.hrmp.hbpm.business.hr.service.impl.PosBillEntryFastChgHelper;
import nckd.jxccl.hrmp.hbpm.business.hr.service.impl.PositionBillServiceHelper;
import nckd.jxccl.base.common.utils.PatternUtil;
import nckd.jxccl.hrmp.hbpm.common.hr.PositionBillConstant;
import org.apache.commons.lang3.time.DateUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.EventObject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 岗位申请单分录修改插件
 * @from: kd.hr.homs.formplugin.web.orgbatch.AdminOrgBatchDetailUpdatePlugin
 * @author: jtd
 * @date: 2025/12/28 15:48
 */
public class PosBillEntryUpdatePlugin extends AbstractFormPlugin implements BeforeF7SelectListener {
    private static final Log LOG = LogFactory.getLog(PosBillEntryUpdatePlugin.class);
    public static String suffix;
    public static String lineSuffix;

    @Override
    public void afterBindData(EventObject e) {
        super.afterBindData(e);
        getModel().setDataChanged(false);
    }

    @Override
    public void beforeBindData(EventObject e) {
        super.beforeBindData(e);
        Long billId = getView().getFormShowParameter().getCustomParam(PositionBillConstant.CP_BILLID);
        Object positionBsed = getView().getFormShowParameter().getCustomParam(PositionBillConstant.CP_POSITION_BSED);
        long positionBsedTime = positionBsed != null ? Long.parseLong(String.valueOf(positionBsed)) : HRDateTimeUtils.getNowDate().getTime();
        long id = getModel().getDataEntity().getLong(PositionBillConstant.ID_KEY);
        if (id == 0L) {
            Object idStr = getView().getFormShowParameter().getCustomParam(PositionBillConstant.ID_KEY);
            if (idStr != null) {
                getModel().setValue(PositionBillConstant.ID_KEY, Long.valueOf(String.valueOf(idStr)));
            }
        }

        getModel().setValue(PositionBillConstant.NCKD_BILLID, billId);
        getModel().setValue(PositionBillConstant.ENABLE, EnableEnum.YES.getCode());

        DynamicObject orgDy = getModel().getDataEntity().getDynamicObject(PositionBillConstant.NCKD_ORG_KEY);
        getPageCache().put(PositionBillConstant.PC_MASTERORG, orgDy != null ? String.valueOf(orgDy.getLong(PositionBillConstant.ID_KEY)) : EnableEnum.NO.getCode());
        getModel().setValue(PositionBillConstant.NCKD_BSED, new Date(positionBsedTime));
        Object positionIdStr = getView().getFormShowParameter().getCustomParam(PositionBillConstant.CP_POSITIONID);
        if (positionIdStr != null) {
            Long positionId = Long.valueOf(String.valueOf(positionIdStr));
            setInfoFromDb(positionId, false);
        }

        getModel().beginInit();
        setInfoFromEntry();
        getModel().endInit();
        getModel().setDataChanged(false);
    }

    public void registerListener(EventObject e) {
        super.registerListener(e);
        BasedataEdit position = getView().getControl(PositionBillConstant.NCKD_POSITION_KEY);
        position.addBeforeF7SelectListener(this);

        for(String registerBeforeF7Listener : getRegisterBeforeF7ListenerControlList()) {
            BasedataEdit basedataEdit = getControl(registerBeforeF7Listener);
            if (basedataEdit != null) {
                basedataEdit.setF7BatchFill(false);
                basedataEdit.addBeforeF7SelectListener(this);
            }
        }

    }

    private List<String> getRegisterBeforeF7ListenerControlList() {
        //return Arrays.asList(PositionBillConstant.NCKD_PARENT, PositionBillConstant.NCKD_ORG_KEY);
        return Collections.singletonList(PositionBillConstant.NCKD_ORG_KEY);
    }

    @Override
    public void beforeF7Select(BeforeF7SelectEvent beforeF7SelectEvent) {
        String fieldKey = beforeF7SelectEvent.getProperty().getName();
        if (PositionBillConstant.NCKD_POSITION_KEY.equals(fieldKey)) {
            AuthorizedOrgResult authorizedOrgResult = PositionBillServiceHelper.getOrgAuth(getView());
            if (!authorizedOrgResult.isHasAllOrgPerm()) {
                List<Long> hasPermOrgList = authorizedOrgResult.getHasPermOrgs();
                beforeF7SelectEvent.getCustomQFilters().add(new QFilter(String.join(".", PositionBillConstant.ADMINORG, PositionBillConstant.BOID_KEY), QCP.in, hasPermOrgList));
            }
            PositionBillServiceHelper.filterF7Org(getView().getParentView(), beforeF7SelectEvent, null);

            if (getModel().getValue(PositionBillConstant.NCKD_ORG_KEY) != null) {
                List<Long> orgIdList = Collections.singletonList(((DynamicObject) getModel().getValue(PositionBillConstant.NCKD_ORG_KEY)).getLong(PositionBillConstant.ID_KEY));
                if (CollectionUtils.isEmpty(orgIdList)) {
                    beforeF7SelectEvent.getCustomQFilters().add(new QFilter("1", QCP.not_equals, 1));
                } else {
                    beforeF7SelectEvent.getCustomQFilters().add(new QFilter(PositionBillConstant.ORG_KEY, QCP.in, orgIdList));
                }
            }

            beforeF7SelectEvent.getFormShowParameter().setCustomParam(PositionBillConstant.CP_SEARCHDATE, new Date());
            getPageCache().put(PositionBillConstant.PC_ISCHANGEPOSITION, Boolean.TRUE.toString());
        } else if (PositionBillConstant.NCKD_PARENT.equals(fieldKey)) {
            Long positionId = getModel().getDataEntity().getLong(PositionBillConstant.NCKD_POSITIONID_KEY);
            // 使用岗位BOID查下级岗位，岗位的上级岗位存储的是BOID
            Long positionBoId = getModel().getDataEntity().getDynamicObject(PositionBillConstant.NCKD_POSITION_KEY).getLong(PositionBillConstant.BOID_KEY);
            Date positionBsed = getModel().getDataEntity().getDate(PositionBillConstant.NCKD_BSED);
            List<Long> positionIds = PositionBillServiceHelper.getPositionAndChildren(positionBoId, positionBsed);
            // 固定过滤岗位
            positionIds.add(positionId);
            beforeF7SelectEvent.getCustomQFilters().add(new QFilter(PositionBillConstant.ID_KEY, QCP.not_in, positionIds));

            ListShowParameter showParameter = (ListShowParameter) beforeF7SelectEvent.getFormShowParameter();
            Date date = DateUtils.truncate(new Date(), 5);
            showParameter.getCustomParams().put(PositionBillConstant.CP_SEARCHDATE, date);
        } else if (PositionBillConstant.NCKD_ORG_KEY.equals(fieldKey)) {
            HasPermOrgResult permOrgResult = PermissionServiceHelper.getUserHasPermOrgs(RequestContext.get().getCurrUserId(), false);
            if (!permOrgResult.hasAllOrgPerm()) {
                List<Long> hasPermOrgs = permOrgResult.getHasPermOrgs();
                beforeF7SelectEvent.getCustomQFilters().add(new QFilter(PositionBillConstant.ID_KEY, QCP.in, hasPermOrgs));
            }
        }
    }

    @Override
    public void propertyChanged(PropertyChangedArgs changedArgs) {
        String fieldKey = changedArgs.getProperty().getName();
        switch (fieldKey) {
            case PositionBillConstant.NCKD_POSITION_KEY:
                positionChanged(changedArgs);
                break;
            case PositionBillConstant.NCKD_ORG_KEY:
                PosBillEntryFastChgHelper.orgPropertyChanged(changedArgs, getView(), this);
        }

    }

    private void positionChanged(PropertyChangedArgs changedArgs) {
        if (Boolean.TRUE.toString().equals(getPageCache().get(PositionBillConstant.PC_ISCHANGEPOSITION))) {
            getPageCache().put(PositionBillConstant.PC_ISCHANGEPOSITION, Boolean.FALSE.toString());
            if (changedArgs.getChangeSet()[0].getNewValue() == null) {
                getModel().setValue(PositionBillConstant.NCKD_POSITION_KEY, changedArgs.getChangeSet()[0].getOldValue());
                return;
            }

            DynamicObject position = (DynamicObject) changedArgs.getChangeSet()[0].getOldValue();
            DynamicObject newPosition = (DynamicObject) changedArgs.getChangeSet()[0].getNewValue();
            Long positionIdOld = position != null ? position.getLong(PositionBillConstant.ID_KEY) : null;
            Long positionIdNew = newPosition != null ? newPosition.getLong(PositionBillConstant.ID_KEY) : null;
            if (newPosition != null) {
                ConfirmCallBackListener confirmCallBackListener = new ConfirmCallBackListener(PositionBillConstant.NCKD_POSITION_KEY, this);
                getView().showConfirm("切换岗位后，当前已修改的内容将会丢失，是否继续？", "", MessageBoxOptions.OKCancel, ConfirmTypes.Default, confirmCallBackListener, null, positionIdOld + "#" + positionIdNew);
            }
        }

    }

    @Override
    public void confirmCallBack(MessageBoxClosedEvent event) {
        super.confirmCallBack(event);
        int result = event.getResult().getValue();
        getView().getFormShowParameter();
        switch (event.getCallBackId()) {
            case PositionBillConstant.NCKD_POSITION_KEY:
                if (result == MessageBoxResult.Yes.getValue()) {
                    String positionIdNew = event.getCustomVaule().split("#")[1];
                    setInfoFromDb(Long.parseLong(positionIdNew), true);
                } else {
                    String positionIdOld = event.getCustomVaule().split("#")[0];
                    getModel().setValue(PositionBillConstant.NCKD_POSITION_KEY, "null".equals(positionIdOld) ? null : positionIdOld);
                }
            case PositionBillConstant.CB_CHG_ORG:
                if (event.getResult().getValue() == MessageBoxResult.Yes.getValue()) {
                    getView().getPageCache().put(PositionBillConstant.PC_MASTERORG, String.valueOf(getModel().getDataEntity().getLong(String.join(".", PositionBillConstant.NCKD_ORG_KEY, PositionBillConstant.ID_KEY))));
                    getModel().beginInit();
                    PosBillEntryFastChgHelper.cleanOrgBaseInfo(getModel().getDataEntity().getLong(String.join(".", PositionBillConstant.NCKD_ORG_KEY, PositionBillConstant.ID_KEY)), getView());
                    getModel().endInit();
                } else {
                    Long masterOrgId = Long.valueOf(getPageCache().get(PositionBillConstant.PC_MASTERORG));
                    getModel().beginInit();
                    getModel().setValue(PositionBillConstant.NCKD_ORG_KEY, masterOrgId.equals(0L) ? null : masterOrgId);
                    getView().updateView(PositionBillConstant.NCKD_ORG_KEY);
                    getModel().endInit();
                }
            default:
        }
    }

    protected void setInfoFromEntry() {
        Object selectObject = getView().getFormShowParameter().getCustomParam(PositionBillConstant.CP_SELECTOBJECT);
        if (selectObject != null) {
            Map<String, Object> map = SerializationUtils.fromJsonString(selectObject.toString(), Map.class);
            Map<String, Object> noSuffixMap = map.entrySet().stream().collect(HashMap::new, (m, v) -> m.put(PositionBillServiceHelper.getNoLineSuffixProp(v.getKey(), lineSuffix), v.getValue()), HashMap::putAll);
            List<String> props = new ArrayList();

            for(String prop : noSuffixMap.keySet()) {
                if (PatternUtil.isExProperty(prop)) {
                    props.add(prop);
                }
            }

            // 获取分录要转换的键值，将单据分录字段转换转成分录页面字段
            Map<String, String> transKeyMap = PositionBillServiceHelper.getPosBillEntryTransKeyMap();
            transKeyMap.forEach((key, value) -> {
                noSuffixMap.put(value, noSuffixMap.get(key));
                noSuffixMap.remove(key);
                props.add(value);
                props.remove(key);
            });

            Stream<String> fields = Stream.of(props.toArray(new String[0]));
            fields.forEach((s) -> setValue(s, noSuffixMap.get(s)));

            setValue(PositionBillConstant.NCKD_BILLID, getView().getFormShowParameter().getCustomParam(PositionBillConstant.CP_BILLID));
        }

    }

    protected void setInfoFromDb(Long positionId, boolean positionChange) {
        Object positionBsed = getView().getFormShowParameter().getCustomParam(PositionBillConstant.CP_POSITION_BSED);
        long positionBsedTime = positionBsed != null ? Long.parseLong(String.valueOf(positionBsed)) : HRDateTimeUtils.getNowDate().getTime();
        if (positionId != 0L) {
            Object entryId = getView().getFormShowParameter().getCustomParam(PositionBillConstant.ID_KEY);
            HRBaseServiceHelper positionBillEntryDAO = new HRBaseServiceHelper(PositionBillConstant.NCKD_POSITIONBILLENTRY_ENTITY);
            boolean entryIdExists = positionBillEntryDAO.isExists(entryId);
            DynamicObject positionMasterInfo = PositionBillServiceHelper.getPositionDyById(positionId);
            if (!positionChange && entryIdExists) {
            } else {
                long orgBoId = positionMasterInfo.getDynamicObject(PositionBillConstant.ADMINORG).getLong(PositionBillConstant.BOID_KEY);
                getModel().setValue(PositionBillConstant.NCKD_ADMINORGBOID_KEY, orgBoId);
                getModel().setValue(PositionBillConstant.NCKD_POSITION_KEY, positionId);
                getModel().setValue(PositionBillConstant.NCKD_POSITIONID_KEY, positionId);
                if (lineSuffix.endsWith("_"+PositionBillConstant.CHANGE_TAG)) {
                    getModel().setValue(PositionBillConstant.NCKD_PARENT, null);
                } else {
                    getModel().setValue(PositionBillConstant.NCKD_PARENT, PositionBillServiceHelper.getHisId(positionMasterInfo.getLong(String.join(".", PositionBillConstant.NCKD_PARENT, PositionBillConstant.ID_KEY))));
                }

                Object orgParam = getView().getFormShowParameter().getCustomParam(PositionBillConstant.ORG_KEY);
                if (orgParam != null) {
                    getModel().beginInit();
                    getModel().setValue(PositionBillConstant.NCKD_ORG_KEY, orgParam);
                    getModel().endInit();
                    getView().updateView(PositionBillConstant.NCKD_ORG_KEY);
                }

                MainEntityType dataEntityType = getModel().getDataEntityType();
                DataEntityPropertyCollection properties = dataEntityType.getProperties();
                Map<String, IDataEntityProperty> allFields = ((MainEntityType) positionMasterInfo.getDataEntityType()).getAllFields();

                // 获取分录要转换的键值
                Map<String, String> posBillEntryTransKeyMap = PositionBillServiceHelper.getPosBillEntryTransKeyMap();
                // 获取岗位要转换的键值
                Map<String, String> positionTransKeyMap = PositionBillServiceHelper.getPositionTransKeyMap();
                // 获取分录属性
                Map<String, IDataEntityProperty> entryPropMap = new HashMap<String, IDataEntityProperty>();
                for(IDataEntityProperty property : properties) {
                    String propName = property.getName();
                    if (property instanceof EntryProp) {
                        getModel().deleteEntryData(propName);
                        entryPropMap.put(positionTransKeyMap.getOrDefault(propName, propName), property);
                        continue;
                    }

                    if (positionTransKeyMap.containsKey(propName) && allFields.containsKey(positionTransKeyMap.getOrDefault(propName, ""))) {
                        getModel().setValue(propName, positionMasterInfo.get(positionTransKeyMap.getOrDefault(propName, "")));
                    } else if ((PatternUtil.isExProperty(propName) || posBillEntryTransKeyMap.containsValue(propName)) && allFields.containsKey(propName)) {
                        getModel().setValue(propName, positionMasterInfo.get(propName));
                    }
                }

                // 处理分录数据
                DataEntityPropertyCollection positionProperties = positionMasterInfo.getDataEntityType().getProperties();
                Map<String, IDataEntityProperty> dataEntryPropMap = positionProperties.stream().filter(property -> entryPropMap.containsKey(property.getName())).collect(Collectors.toMap(property -> entryPropMap.get(property.getName()).getName(), Function.identity()));

                for (Map.Entry<String, IDataEntityProperty> dataEntryProp : dataEntryPropMap.entrySet()) {
                    DynamicObjectCollection fromCollection = positionMasterInfo.getDynamicObjectCollection(dataEntryProp.getValue());
                    DynamicObjectCollection toCollection = getModel().getDataEntity().getDynamicObjectCollection(dataEntryProp.getKey());
                    if (fromCollection == null || fromCollection.isEmpty()) {
                        continue;
                    }

                    for (DynamicObject fromObj : fromCollection) {
                        HRDynamicObjectUtils.copy(fromObj, toCollection.addNew());
                    }
                }

                getModel().setDataChanged(false);
                // 生效日期特殊处理
                getModel().setValue(PositionBillConstant.NCKD_BSED, new Date(positionBsedTime));
                // 原上级岗位特殊处理
                getModel().setValue(PositionBillConstant.NCKD_ORIPARENT_KEY, getModel().getValue(PositionBillConstant.NCKD_PARENT));
            }
        }
    }

    private void setValue(String key, Object value) {
        if (getModel().getProperty(key) != null) {
            Class<?> propertyType = getModel().getDataEntityType().getProperty(key).getPropertyType();
            DynamicProperty dynamicProperty = getModel().getDataEntityType().getProperty(key);
            if (value != null) {
                if (propertyType.equals(DynamicObject.class) && dynamicProperty instanceof BasedataProp) {
                    Object id = ((Map) value).get(PositionBillConstant.ID_KEY);
                    if (id != null && !HRStringUtils.equals(value.toString(), "0")) {
                        getModel().setValue(key, id);
                    }
                } else if (propertyType.equals(DynamicObject.class) && dynamicProperty instanceof MulBasedataProp && value instanceof List) {
                    MulBasedataProp property = (MulBasedataProp) getModel().getDataEntityType().getProperty(key);
                    DynamicObjectCollection dynamicObjectCollection = new DynamicObjectCollection();
                    HRBaseServiceHelper serviceHelper = new HRBaseServiceHelper(property.getBaseEntityId());
                    LOG.info("set MulBasedataProp value [{}]", value);
                    ((List) value).forEach((map) -> {
                        DynamicObject dy = new DynamicObject(property.getDynamicCollectionItemPropertyType());
                        if (((Map) map).get(PositionBillConstant.FBASEDATAID_ID_KEY) != null) {
                            dy.set(PositionBillConstant.FBASEDATAID_ID_KEY, ((Map) map).get(PositionBillConstant.FBASEDATAID_ID_KEY));
                            DynamicObject emptyDynamicObject = serviceHelper.generateEmptyDynamicObject();
                            emptyDynamicObject.set(PositionBillConstant.ID_KEY, ((Map) map).get(PositionBillConstant.FBASEDATAID_ID_KEY));
                            dy.set(PositionBillConstant.FBASEDATAID_KEY, emptyDynamicObject);
                            dynamicObjectCollection.add(dy);
                        } else {
                            Object fbasedataid = ((Map) map).get(PositionBillConstant.FBASEDATAID_KEY);
                            if (fbasedataid instanceof Map && ((Map) fbasedataid).get(PositionBillConstant.ID_KEY) instanceof Long) {
                                Long id = (Long) ((Map) fbasedataid).get(PositionBillConstant.ID_KEY);
                                dy.set(PositionBillConstant.FBASEDATAID_ID_KEY, id);
                                DynamicObject emptyDynamicObject = serviceHelper.generateEmptyDynamicObject();
                                emptyDynamicObject.set(PositionBillConstant.ID_KEY, id);
                                dy.set(PositionBillConstant.FBASEDATAID_KEY, emptyDynamicObject);
                                dynamicObjectCollection.add(dy);
                            }
                        }

                    });
                    getModel().setValue(key, dynamicObjectCollection.size() != 0 ? dynamicObjectCollection : null);
                } else {
                    getModel().setValue(key, value);
                }

            }
        }
    }

    @Override
    public void beforeDoOperation(BeforeDoOperationEventArgs args) {
        super.beforeDoOperation(args);

        PositionBillServiceHelper.setChangeDes(Collections.singletonList(getModel().getDataEntity()));
    }

    public void afterDoOperation(AfterDoOperationEventArgs afterDoOperationEventArgs) {
        super.afterDoOperation(afterDoOperationEventArgs);
        String key = afterDoOperationEventArgs.getOperateKey();
        OperationResult result = afterDoOperationEventArgs.getOperationResult();
        if (result != null && HRStringUtils.equals(key, PositionBillConstant.SAVE_OP) && result.isSuccess()) {
            DynamicObject data = getModel().getDataEntity();
            Map<String, Object> map = new HashMap(1);
            DynamicObject dataEntity = getModel().getDataEntity(true);
            IDataEntityType dataEntityType = dataEntity.getDataEntityType();

            for(IDataEntityProperty property : dataEntityType.getProperties()) {
                String propName = property.getName();
                if (PatternUtil.isExProperty(propName) && !(property instanceof LongProp)) {
                    map.put(propName, data.get(propName));
                }
            }

            // 获取分录要转换的键值
            Map<String, String> posBillEntryTransKeyMap = PositionBillServiceHelper.getPosBillEntryTransKeyMap();
            posBillEntryTransKeyMap.forEach((k, v) -> {
                if (map.containsKey(v)) {
                    map.put(k, map.get(v));
                    map.remove(k);
                } else {
                    map.put(k, data.get(v));
                }
            });

            Map<String, Object> suffixMap = map.entrySet().stream().collect(HashMap::new, (m, v) -> m.put(v.getKey()+lineSuffix, v.getValue()), HashMap::putAll);
            suffixMap.put(PositionBillConstant.ID_KEY, data.getLong(PositionBillConstant.ID_KEY));
            getView().returnDataToParent(suffixMap);
            getView().close();
        }

    }

}
