package nckd.jxccl.sit.hcsi.formplugin.web.coordination;

import kd.bos.dataentity.OperateOption;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.serialization.SerializationUtils;
import kd.bos.dataentity.utils.ObjectUtils;
import kd.bos.entity.EntityMetadataCache;
import kd.bos.entity.datamodel.IDataModel;
import kd.bos.entity.datamodel.RowDataEntity;
import kd.bos.entity.datamodel.events.AfterAddRowEventArgs;
import kd.bos.entity.datamodel.events.PropertyChangedArgs;
import kd.bos.entity.operate.result.OperationResult;
import kd.bos.form.control.EntryGrid;
import kd.bos.form.events.AfterDoOperationEventArgs;
import kd.bos.form.events.BeforeDoOperationEventArgs;
import kd.bos.form.field.BasedataEdit;
import kd.bos.form.field.FieldEdit;
import kd.bos.form.field.events.BeforeF7SelectEvent;
import kd.bos.form.field.events.BeforeF7SelectListener;
import kd.bos.form.operate.AbstractOperate;
import kd.bos.form.plugin.AbstractFormPlugin;
import kd.bos.org.utils.DynamicObjectUtils;
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 kd.sdk.plugin.Plugin;
import kd.sdk.sit.sitbp.business.helper.SITBPServiceHelper;
import kd.sdk.sit.sitbp.common.StdResultInfoDTO;
import nckd.jxccl.sit.hcsi.common.constant.SitConstant;
import nckd.jxccl.sit.hcsi.utils.SITCoordinationUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Tyx 2025-10-27
 * 变动核定单表单插件扩展【nckd_hpdi_empcoordbat_ext】
 */
public class SinSurEmpChgCoordBatchEditPluginEx extends AbstractFormPlugin implements Plugin, BeforeF7SelectListener {

    private static final HRBaseServiceHelper COORDBILL_HELPER = new HRBaseServiceHelper("hpdi_empcoordverifbill3");
    private static final List<String> defaultQueryFields = (List) Stream.of("id", "employeev", "assignment", "coordruleparam").collect(Collectors.toList());
    private static final Map<Long, StdResultInfoDTO> stdResultInfoDTOMap = new HashMap<Long, StdResultInfoDTO>();
    /**
     * 在标品加载完数据之后，再获取一下核定单分录的数据展示出来
     * @param e
     */
    @Override
    public void afterBindData(EventObject e) {
        super.afterBindData(e);
        List<String> queryFields = this.getQueryFields();
        HRBaseServiceHelper helper = new HRBaseServiceHelper(this.getEntityNumber());
        DynamicObject[] billCols = helper.load(String.join(",", queryFields), new QFilter[]{new QFilter("id", "in", this.getSelectIds())});
        showEntryData(billCols);
        setWelfareTypeInsuranceTypeAttrEnable();
    }

    @Override
    public void registerListener(EventObject e) {
        super.registerListener(e);
        BasedataEdit basedataEdit = this.getView().getControl("nckd_sinsurdimension");
        if (basedataEdit != null) {
            basedataEdit.addBeforeF7SelectListener(this);
        }
    }

    private void showEntryData(DynamicObject[] billCols) {
        Set<String> entryFields = this.getEntryFields();
        // 根据ID提取出来
        Map<Long, DynamicObject> billMap = (Map) Arrays.stream(billCols).collect(Collectors.toMap((dyx) -> {
            return dyx.getLong("id");
        }, (dyx) -> {
            return dyx;
        }, (key1, key2) -> {
            return key2;
        }));
        DynamicObjectCollection entryCols = this.getModel().getEntryEntity("entryentity");
        for(DynamicObject entry : entryCols) {
            Long billId = entry.getLong("id");
            DynamicObject bill = billMap.get(billId);
            DynamicObjectCollection billEntryCols = bill.getDynamicObjectCollection("nckd_entryentity");
            DynamicObjectCollection subEntryCols = entry.getDynamicObjectCollection("nckd_subentryentity");
            subEntryCols.clear();
            for(DynamicObject billEntry : billEntryCols) {
                DynamicObject subEntry = subEntryCols.addNew();
                for(String field : entryFields) {
                    subEntry.set(field, billEntry.get(field));
                }
            }
        }
        this.getView().updateView("nckd_subentryentity");
    }

    @Override
    public void propertyChanged(PropertyChangedArgs e) {
        super.propertyChanged(e);
        IDataModel model = this.getModel();
        String key = e.getProperty().getName();
        // 如果是 参保标准 / 险种 / 险种维度发生变化，需要去取参保标准中的标准维度值
        // 如果是 险种 / 险种维度发生变化，只需要修改当前子单据体的数据
        if(HRStringUtils.equalsAny(key, "nckd_welfaretype", "nckd_sinsurdimension")) {
            int rowIndex = model.getEntryCurrentRowIndex("entryentity");
            DynamicObject sinSurStd = (DynamicObject) model.getValue("sinsurstd_r31", rowIndex);
            if(ObjectUtils.isEmpty(sinSurStd))
                return;
            getStdInfoAndStdDimfromCache(sinSurStd);
            int subRowIndex = model.getEntryCurrentRowIndex("nckd_subentryentity");
            DynamicObject welfaretype = (DynamicObject) model.getValue("nckd_welfaretype", subRowIndex);
            DynamicObject sinSurDimension = (DynamicObject) model.getValue("nckd_sinsurdimension", subRowIndex);
            getDimensionValue(sinSurStd, welfaretype, sinSurDimension, rowIndex, subRowIndex);
            setWelfareTypeInsuranceTypeAttrEnable();

            // 如果是险种，新旧值不一样的情况下，把个人基数跟单位基数清除掉
            if(HRStringUtils.equalsAny(key, "nckd_welfaretype")) {
                if(e.getChangeSet()[0].getNewValue() != e.getChangeSet()[0].getOldValue()) {
                    model.setValue(SitConstant.PAY_BASE_OF_EMPLOYEE_KEY, null, subRowIndex, rowIndex);
                    model.setValue(SitConstant.PAY_BASE_OF_COMPANY_KEY, null, subRowIndex, rowIndex);
                    this.getView().updateView("nckd_subentryentity");
                }
            }

        }
        // 如果是 参保标准发生变化，当前单据体下的子单据体都需要更新
        else if (HRStringUtils.equals(key, "sinsurstd_r31")) {
            Object newValue = e.getChangeSet()[0].getNewValue();
            if(!ObjectUtils.isEmpty(newValue)) {
                getStdInfoAndStdDimfromCache((DynamicObject) newValue);
                int rowIndex = model.getEntryCurrentRowIndex("entryentity");
                // 因为险种维度会根据参保标准+险种进行过滤，这里把子单据体的险种维度清空
                clearSubEntryDimension(rowIndex);
                getDimensionValue((DynamicObject) newValue, rowIndex);
            }
        }
    }

    public void clearSubEntryDimension (int rowIndex) {
        this.getModel().setEntryCurrentRowIndex("entryentity", rowIndex);
        int rowCount = this.getModel().getEntryRowCount("nckd_subentryentity");
        for (int i = 0; i < rowCount; i++) {
            this.getModel().setValue("nckd_sinsurdimension", null, i, rowIndex);
        }
    }

    /**
     * 从缓存中获取参保标准的信息，如果没有缓存则生成缓存
     * @param sinSurStd
     * @return
     */
    public void getStdInfoAndStdDimfromCache (DynamicObject sinSurStd) {
        Long cacheKey = sinSurStd.getLong("id");
        StdResultInfoDTO stdResultInfoDTO = stdResultInfoDTOMap.get(cacheKey);
        if(stdResultInfoDTO == null) {
            stdResultInfoDTO = SITBPServiceHelper.getStdInfoAndStdDim(Arrays.asList(sinSurStd.getLong("id"))).get(sinSurStd.getLong("id"));
            stdResultInfoDTOMap.put(cacheKey, stdResultInfoDTO);
        }
    }

    /**
     * 参保标准修改的情况下，把当前单据体下的子单据体的数据改一下
     * @param sinSurStd
     * @param rowIndex
     */
    public void getDimensionValue(DynamicObject sinSurStd, int rowIndex) {
        DynamicObject entry = this.getModel().getEntryRowEntity("entryentity", rowIndex);
        DynamicObjectCollection subEntryCols = entry.getDynamicObjectCollection("nckd_subentryentity");
        for(int i = 0 ; i < subEntryCols.size(); i++) {
            DynamicObject subEntry = subEntryCols.get(i);
            DynamicObject welfaretype = subEntry.getDynamicObject("nckd_welfaretype");
            DynamicObject sinSurDimension = subEntry.getDynamicObject("nckd_sinsurdimension");
            getDimensionValue(sinSurStd, welfaretype, sinSurDimension, rowIndex, i);
        }
    }

    /**
     * 子单据体获取并设置维度值
     * @param sinSurStd
     * @param welfaretype
     * @param sinSurDimension
     * @param subRowIndex
     */
    public void getDimensionValue(DynamicObject sinSurStd, DynamicObject welfaretype, DynamicObject sinSurDimension, int rowIndex, int subRowIndex) {
        IDataModel model = this.getModel();
        Long cacheKey = sinSurStd.getLong("id");
        StdResultInfoDTO stdResultInfoDTO = stdResultInfoDTOMap.get(cacheKey);

        if(welfaretype == null)
            return;

        SITCoordinationUtils SITCoordinationUtils = new SITCoordinationUtils();
        Map result = SITCoordinationUtils.dealStdResult(stdResultInfoDTO, sinSurStd, welfaretype, sinSurDimension);

        Set<Long> keySet = SitConstant.INSURANCE_PAY_BASE_CONSTANTS.keySet();
        for (Long key : keySet) {
            if(result.get(key) == null) {
                model.setValue(SitConstant.INSURANCE_PAY_BASE_CONSTANTS.get(key), null, subRowIndex, rowIndex);
            }
            else {
                model.setValue(SitConstant.INSURANCE_PAY_BASE_CONSTANTS.get(key), result.get(key), subRowIndex, rowIndex);
            }
        }
    }


    @Override
    public void beforeDoOperation(BeforeDoOperationEventArgs args) {
        super.beforeDoOperation(args);
        IDataModel model = this.getModel();
        AbstractOperate op = (AbstractOperate)args.getSource();
        String operateKey = op.getOperateKey();
        // 批量设置前校验，查询当前选中的单据体的子单据体是否有数据
        if(HRStringUtils.equals(operateKey, "batchsetting")){
            int row = model.getEntryCurrentRowIndex("entryentity");
            model.setEntryCurrentRowIndex("entryentity", row);
            int rowCount = model.getEntryRowCount("nckd_subentryentity");
            if(rowCount == 0) {
                args.setCancel(true);
                this.getView().showTipNotification("请先维护险种基数！");
            }
        }
        else if(HRStringUtils.equals(operateKey, "donothing_split")) {

        }


    }

    @Override
    public void afterDoOperation(AfterDoOperationEventArgs afterDoOperationEventArgs) {
        super.afterDoOperation(afterDoOperationEventArgs);
        AbstractOperate op = (AbstractOperate)afterDoOperationEventArgs.getSource();
        String operateKey = op.getOperateKey();
        if ((HRStringUtils.equals(operateKey, "save") || HRStringUtils.equals(operateKey, "confirmeffect"))) {
            doSaveSubEntry();
        }
        else if(HRStringUtils.equals(operateKey, "batchsetting")){
            doBatchSetting();
        }
        else if(HRStringUtils.equals(operateKey, "donothing_split")) {
            doSplit();
        }
    }

    /**
     * 拆分
     */
    private void doSplit() {
        List<Long> selectIds = this.getSelectIds();
        List<String> queryFields = this.getQueryFields();
        HRBaseServiceHelper helper = new HRBaseServiceHelper(this.getEntityNumber());
        DynamicObject[] billCols = helper.load(String.join(",", queryFields), new QFilter[]{new QFilter("id", "in", this.getSelectIds())});
        OperationResult result = OperationServiceHelper.executeOperate("donothing_split", this.getEntityNumber(), billCols, OperateOption.create());
    }

    /**
     * 批量设置其余子分录的险种信息
     */
    public void doBatchSetting() {
        IDataModel model = this.getModel();
        DynamicObject bill = model.getDataEntity(true);
        DynamicObjectCollection entryCols = bill.getDynamicObjectCollection("entryentity");
        // 当前选中行
        int row = model.getEntryCurrentRowIndex("entryentity");
        // 2025-12-08 单据体中实际/理论参保单位也需要批量设置
        DynamicObject payerA = (DynamicObject) model.getValue("welfarepayertheory_r31", row);
        DynamicObject payerB = (DynamicObject) model.getValue("welfarepayer_r31", row);
        // 当前选中行的子单据体数据
        DynamicObjectCollection subCols = entryCols.get(row).getDynamicObjectCollection("nckd_subentryentity");

        for(int i = 0; i < entryCols.size(); i++) {
            if(i == row)
                continue;
            // 设置实际/理论参保单位
            entryCols.get(i).set("welfarepayertheory_r31", payerA);
            entryCols.get(i).set("welfarepayer_r31", payerB);
            // 获取本次要执行覆盖的子单据体
            DynamicObjectCollection otherSubCols = entryCols.get(i).getDynamicObjectCollection("nckd_subentryentity");
            // 清除数据
            otherSubCols.clear();
            // 从subCols copy 过来
            for(DynamicObject subEntry : subCols) {
                DynamicObject otherSubEntry = otherSubCols.addNew();
                DynamicObjectUtils.copy(subEntry, otherSubEntry);
            }
        }
        this.getView().updateView("entryentity");
        this.getView().updateView("nckd_subentryentity");
    }

    public void checkSubEntryData() {
        IDataModel model = this.getModel();
        DynamicObject dyn = model.getDataEntity(true);
        DynamicObjectCollection entryCols = dyn.getDynamicObjectCollection("entryentity");
    }

    /**
     * 执行保存，把当前页面的子单据体保存到核定单上；
     */
    public void doSaveSubEntry () {
        DynamicObject bill = this.getModel().getDataEntity(true);
        DynamicObjectCollection entryCols = bill.getDynamicObjectCollection("entryentity");
        DynamicObjectCollection saveCols = new DynamicObjectCollection();
        Set<String> subEntryFields = getEntryFields();
        for (DynamicObject entry : entryCols) {
            // 获取到核定单ID
            Long coordBillId = entry.getLong("id");
            // 获取到核定单Dyn
            DynamicObject coordBill = COORDBILL_HELPER.loadOne(coordBillId);
            // 获取当前页面子单据体的信息
            DynamicObjectCollection subEntryCols = entry.getDynamicObjectCollection("nckd_subentryentity");
            // 保存核定单的分录
            DynamicObjectCollection coordBillEntryCols = coordBill.getDynamicObjectCollection("nckd_entryentity");
            // 清空核定单的分录
            coordBillEntryCols.clear();
            // 根据当前页面子单据体信息->核定单分录数据
            for (DynamicObject subEntry : subEntryCols) {
                DynamicObject billEntry = coordBillEntryCols.addNew();
                for(String field : subEntryFields) {
                    billEntry.set(field, subEntry.get(field));
                }
            }
            saveCols.add(coordBill);
        }
        if(saveCols.size() > 0) {
            COORDBILL_HELPER.save(saveCols);
        }
    }

    /**
     * 获取子单据体字段
     * @return
     */
    public Set<String> getEntryFields() {
        Set<String> subEntryFields = EntityMetadataCache.getDataEntityType("hpdi_empcoordbatchedit3").getAllEntities().get("nckd_subentryentity").getFields().keySet();
        return subEntryFields;
    }

    /**
     * 获取核定单ID
     * @return
     */
    protected List<Long> getSelectIds() {
        String selectIdStr = (String)this.getView().getFormShowParameter().getCustomParam("selectIds");
        return (List<Long>) SerializationUtils.fromJsonStringToList(selectIdStr, Long.class);
    }

    /**
     * 获取实体标识
     * @return
     */
    protected String getEntityNumber() {
        return (String)this.getView().getFormShowParameter().getCustomParam("entityNumber");
    }

    /**
     * 构建查询字段
     * @return
     */
    protected List<String> getQueryFields() {
        EntryGrid entryGrid = (EntryGrid)this.getView().getControl("entryentity");
        List<FieldEdit> entryFields = entryGrid.getFieldEdits();
        Set<String> queryFields = (Set)entryFields.stream().map(FieldEdit::getFieldKey).collect(Collectors.toSet());
        queryFields.remove("adminorg");
        queryFields.remove("position");
        queryFields.addAll(defaultQueryFields);
        queryFields.add("nckd_issplit");
        queryFields.add("nckd_sourcebillid");
        Set<String> fields = this.getEntryFields();
        queryFields.addAll(fields.stream().map(field -> "nckd_entryentity." + field).collect(Collectors.toList()));
        return new ArrayList(queryFields);
    }

    @Override
    public void beforeF7Select(BeforeF7SelectEvent e) {
        String fieldKey = e.getProperty().getName();
        IDataModel model = this.getModel();
        if(HRStringUtils.equals(fieldKey, "nckd_sinsurdimension")) {
            // 单据体行号
            int rowIndex = model.getEntryCurrentRowIndex("entryentity");
            // 子单据体行号
            int subRowIndex = e.getRow();
            // 过滤前判断 参保标准和险种有没有选择
            DynamicObject sinSurStd = (DynamicObject) model.getValue("sinsurstd_r31", rowIndex);
            DynamicObject welfareType = (DynamicObject) model.getValue("nckd_welfaretype", subRowIndex, rowIndex);
            if(ObjectUtils.isEmpty(sinSurStd)) {
                this.getView().showTipNotification("请先选择“参保标准”");
                e.setCancel(true);
                return;
            }
            else if (ObjectUtils.isEmpty(welfareType)) {
                this.getView().showTipNotification("请先选择“险种”");
                e.setCancel(true);
                return;
            }

            // 按照参保标准+险种 查询可选择的险种维度
            QFilter filter = new QFilter("id", QCP.in, getDimensionValueForFilter(sinSurStd, welfareType));
            e.getCustomQFilters().add(filter);
        }
    }

    public List<Long> getDimensionValueForFilter (DynamicObject sinSurStd, DynamicObject welfaretype) {
        Long sinSurStdId = sinSurStd.getLong("id");
        Long welfaretypeId = welfaretype.getLong("id");
        SITCoordinationUtils SITCoordinationUtils = new SITCoordinationUtils();
        return SITCoordinationUtils.queryDimensionValue(sinSurStdId, welfaretypeId);
    }

    /**
     * 获取当前子单据体的所有险种
     * @return
     */
    private Set<Long> getWelfareTypeIds() {
        DynamicObjectCollection entryEntity = this.getModel().getEntryEntity("entryentity");
        Set<Long> welfareTypeIds = new HashSet<>();
        for (DynamicObject dynamicObject : entryEntity) {
            DynamicObjectCollection subEntryEntity = dynamicObject.getDynamicObjectCollection("nckd_subentryentity");
            welfareTypeIds.addAll(subEntryEntity.stream().map(subEntry -> subEntry.getLong("nckd_welfaretype.id")).collect(Collectors.toSet()));
        }
        return welfareTypeIds;
    }

    /**
     * 设置险种对应的险种属性是否可用
     */
    private void setWelfareTypeInsuranceTypeAttrEnable() {
        DynamicObjectCollection entryEntity = this.getModel().getEntryEntity("entryentity");
        Set<Long> welfareTypeIds = this.getWelfareTypeIds();
        Map<Long, Map<Long, Boolean>> welfareTypeInsuranceTypeAttrMap = SITCoordinationUtils.queryInsuranceTypeAttrSetting(welfareTypeIds, Arrays.asList(SitConstant.PAY_BASE_OF_EMPLOYEE_ID, SitConstant.PAY_BASE_OF_COMPANY_ID));
        for (int index = 0; index < entryEntity.size(); index++) {
            DynamicObject entry = entryEntity.get(index);
            DynamicObjectCollection subEntryEntity = entry.getDynamicObjectCollection("nckd_subentryentity");
            for (int subIndex = 0; subIndex < subEntryEntity.size(); subIndex++) {
                DynamicObject dynamicObject = subEntryEntity.get(subIndex);
                if (dynamicObject.getBoolean("nckd_insured")) {
                    long welfareTypeId = dynamicObject.getLong("nckd_welfaretype.id");
                    Map<Long, Boolean> insuranceTypeAttrMap = (Map) welfareTypeInsuranceTypeAttrMap.get(welfareTypeId);
                    if ((Boolean) insuranceTypeAttrMap.get(SitConstant.PAY_BASE_OF_EMPLOYEE_ID)) {
                        this.getView().setEnable(Boolean.TRUE, index, new String[]{SitConstant.PAY_BASE_OF_EMPLOYEE_KEY});
                    } else {
                        this.getView().setEnable(Boolean.FALSE, index, new String[]{SitConstant.PAY_BASE_OF_EMPLOYEE_KEY});
                        dynamicObject.set(SitConstant.PAY_BASE_OF_EMPLOYEE_KEY, (Object) null);
                    }

                    if ((Boolean) insuranceTypeAttrMap.get(SitConstant.PAY_BASE_OF_COMPANY_ID)) {
                        this.getView().setEnable(Boolean.TRUE, index, new String[]{SitConstant.PAY_BASE_OF_COMPANY_KEY});
                    } else {
                        this.getView().setEnable(Boolean.FALSE, index, new String[]{SitConstant.PAY_BASE_OF_COMPANY_KEY});
                        dynamicObject.set(SitConstant.PAY_BASE_OF_COMPANY_KEY, (Object) null);
                    }
                } else {
                    dynamicObject.set(SitConstant.PAY_BASE_OF_EMPLOYEE_KEY, (Object) null);
                    dynamicObject.set(SitConstant.PAY_BASE_OF_COMPANY_KEY, (Object) null);
                    this.getView().setEnable(Boolean.FALSE, index, new String[]{SitConstant.PAY_BASE_OF_EMPLOYEE_KEY});
                    this.getView().setEnable(Boolean.FALSE, index, new String[]{SitConstant.PAY_BASE_OF_COMPANY_KEY});
                }
            }
        }
    }

    /**
     * 新增分录的时候：
     * 如果变动大类是非调动的情况则携带表头的理论/实际参保单位
     * @param e
     */
    @Override
    public void afterAddRow(AfterAddRowEventArgs e) {
        super.afterAddRow(e);
        IDataModel model = this.getModel();
        DynamicObject dyn = model.getDataEntity();
        String entryName = e.getEntryProp().getName();
        if(entryName.equals("nckd_subentryentity")) {
            RowDataEntity[] rowDatas = e.getRowDataEntities();
            int rowIndex = model.getEntryCurrentRowIndex("entryentity");
            String chgNumber = ((DynamicObject) model.getValue("coordruleparam", rowIndex)).getString("chgevent_z.number");
            if(!chgNumber.equals("1020_S")) {
                for (RowDataEntity rowData : rowDatas) {
                    model.setValue("nckd_welfarepayertheory", model.getValue("welfarepayertheory_r31"),  rowData.getRowIndex(), rowIndex);
                    model.setValue("nckd_welfarepayer", model.getValue("welfarepayer_r31"), rowData.getRowIndex(), rowIndex);
                }
            }
        }
    }
}