package yem.wm.bd.createbasedata.form;

import kd.bos.bill.AbstractBillPlugIn;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.LocaleString;
import kd.bos.dataentity.metadata.IDataEntityProperty;
import kd.bos.dataentity.metadata.IDataEntityType;
import kd.bos.dataentity.metadata.dynamicobject.DynamicProperty;
import kd.bos.dataentity.serialization.SerializationUtils;
import kd.bos.dataentity.utils.StringUtils;
import kd.bos.designer.botp.BillTreeBuildParameter;
import kd.bos.designer.botp.EntityParseHelper;
import kd.bos.designer.query.QueryEntityParseHelper;
import kd.bos.designer.query.QueryEntityTreeBuildParameter;
import kd.bos.entity.EntityType;
import kd.bos.entity.MainEntityType;
import kd.bos.entity.botp.CRFormula;
import kd.bos.entity.botp.plugin.args.LoadFuncTypesEventArgs;
import kd.bos.entity.botp.runtime.ConvertFuncLoader;
import kd.bos.entity.datamodel.events.ChangeData;
import kd.bos.entity.datamodel.events.PropertyChangedArgs;
import kd.bos.entity.function.FunctionTypes;
import kd.bos.entity.property.AttachmentProp;
import kd.bos.entity.property.IFieldHandle;
import kd.bos.entity.tree.TreeNode;
import kd.bos.form.CloseCallBack;
import kd.bos.form.FormShowParameter;
import kd.bos.form.ShowType;
import kd.bos.form.control.Control;
import kd.bos.form.events.ClosedCallBackEvent;
import kd.bos.servicehelper.MetadataServiceHelper;
import yem.base.common.utils.YEM;

import java.util.ArrayList;
import java.util.EventObject;
import java.util.List;

/**
 * @Description 字段映射配置-表单插件
 * 1、选择【目标实体】自动带出【目标实体】中的所有字段
 * 2、值改变清空【源单字段】、【计算公式】，自动清空与之对应的隐藏字段
 * 3、点击【源单字段】之后，跳转《选择单据字段》，然后在《选择单据字段》中点击确定之后，携带信息到表单上
 * 4、点击【计算公式】之后，跳转《表达式》，然后在《表达式》中点击确定之后，携带信息到单据上
 * @Author: zhangh
 * @CreateTime: 2025-02-13  14:19
 */
public class FieldMapBillPlugin extends AbstractBillPlugIn {

    @Override
    public void propertyChanged(PropertyChangedArgs e) {
        String name = e.getProperty().getName();
        ChangeData[] changeSet = e.getChangeSet();
        Object newValue = changeSet[0].getNewValue();
        int rowIndex = changeSet[0].getRowIndex();
        switch (name) {
            case "yem_targetentity"://目标实体
                setTargetVAlue();//选择【目标实体】，自动带出【目标实体】对应的所有字段
                break;
            case "yem_sourcefield":
                if (YEM.isEmpty(newValue)) {
                    this.getModel().setValue("yem_sourcekey", "", rowIndex);//清空【源单字段】，清空隐藏的【源单字段标识】
                }
                break;
            case "yem_formulas":
                if (YEM.isEmpty(newValue)) {
                    this.getModel().setValue("yem_math", "", rowIndex);//清空【计算公式】，清空隐藏的【公式】
                }
                break;
            default:
                break;
        }
    }

    /**
     * @return void
     * @Description: 选择【目标实体】，自动带出【目标实体】对应的所有字段
     * @function
     * @purposes
     */
    public void setTargetVAlue() {
        this.getModel().deleteEntryData("yem_fieldcontrast_e");//先清楚{字段对照}单据体所有数据
        DynamicObject targetentity = (DynamicObject) this.getModel().getValue("yem_targetentity");//获取【目标实体】
        if (targetentity == null) return;
        MainEntityType dataEntityType = MetadataServiceHelper.getDataEntityType(targetentity.getString("number"));//获取元数据模型，主要用于读取字段类型和字段模型相关。

        for (EntityType entityType : dataEntityType.getAllEntities().values()) {//遍历字段类型
            for (IDataEntityProperty property : entityType.getFields().values()) {
                if (!(property instanceof IFieldHandle)) continue;
                int rowIndex = this.getModel().createNewEntryRow("yem_fieldcontrast_e");//{字段对照}添加行
                DynamicProperty field = (DynamicProperty) property;
                String targetFieldKey = field.getName();//获取字段标识
                String targetFieldName = buildPropFullCaption(property);//获取字段名称
                this.getModel().setValue("yem_targetkey", targetFieldKey, rowIndex);
                this.getModel().setValue("yem_targetfield", targetFieldName, rowIndex);
            }
        }
    }

    /**
     * @Description: 获取字段的名称
     * @function 功能
     * @purposes 用途
     * @param property 字段实体属性
     * @return String  返回字段名称(包含单据体名称)
     */
    public String buildPropFullCaption(IDataEntityProperty property) {
        List<String> captions = new ArrayList();
        IDataEntityType parentType = property.getParent(); //获取字段的上级控件
        LocaleString displayCaption;
        if (parentType instanceof MainEntityType) {//判断上级控件是实体
            captions.add("单据头");
        } else if (parentType instanceof EntityType) {//判断上级控件是单据体
            displayCaption = (parentType).getDisplayName();//获取单据体的名称
            captions.add(displayCaption == null ? "" : displayCaption.toString());
        }

        if (property instanceof DynamicProperty) {
            displayCaption = property.getDisplayName();
            captions.add(displayCaption == null ? property.getName() : displayCaption.toString());
        } else {
            captions.add(property.getName());
        }

        return StringUtils.join(captions.toArray(), ".");
    }

    @Override
    public void registerListener(EventObject e) {
        this.addClickListeners("yem_sourcefield", "yem_formulas");
    }

    @Override
    public void click(EventObject evt) {
        String key = ((Control) evt.getSource()).getKey();
        switch (key) {
            case "yem_sourcefield"://【源单字段】
                showSourceField();//点击【源单字段】，跳转《选择单据字段》
                break;
            case "yem_formulas"://【计算公式】
                showFormula();//点击【计算公式】，跳转《表达式》
                break;
        }
    }

    /**
     * @Description: 跳转《表达式》
     * @function 创建树形结构，然后跳转《选择单据字段》携带参数
     * @purposes
     * @return void
     */

    public void showFormula() {
        DynamicObject sourceentity = (DynamicObject) this.getModel().getValue("yem_sourceentity");//获取【源单实体】
        if (sourceentity == null) {
            this.getView().showErrorNotification("请先填写源单实体。");
            return;
        }

        DynamicObject targetentity = (DynamicObject) this.getModel().getValue("yem_targetentity");//获取【目标单实体】
        MainEntityType targeEntityType = MetadataServiceHelper.getDataEntityType(targetentity.getString("number"));//获取元数据模型，主要用于读取字段类型和字段模型相关。
        int row = this.getModel().getEntryCurrentRowIndex("yem_fieldcontrast_e");
        String targetPropName = (String) this.getModel().getValue("yem_targetkey", row);
        IDataEntityProperty targetProperty = targeEntityType.findProperty(targetPropName);
        if (targetProperty == null || (targetProperty instanceof AttachmentProp)) return;

        MainEntityType sourceMainType = MetadataServiceHelper.getDataEntityType(sourceentity.getString("number"));//获取元数据模型，主要用于读取字段类型和字段模型相关。

        BillTreeBuildParameter parameter = new BillTreeBuildParameter(sourceMainType);//创建树性结构的参数
        parameter.setIncludePKField(true);//是否包含单据id
        TreeNode billTreeNode = EntityParseHelper.buildBillTreeNodes(parameter);//创建树性结构
        String billNodeJson = SerializationUtils.toJsonString(billTreeNode);//序列化树形结构

        String formula = (String) this.getModel().getValue("yem_math", row);//获取【计算公式】
        if (StringUtils.isBlank(formula)) {
            CRFormula crFormula = new CRFormula();
            formula = SerializationUtils.toJsonString(crFormula);//序列话计算公式
        }

        FunctionTypes functionTypes = FunctionTypes.getCommonFuncs();//输出预置的公共函数
        FunctionTypes cloudFunc = ConvertFuncLoader.loadBizCloudFuncTypes();
        functionTypes.getFunctionGroups().addAll(cloudFunc.getFunctionGroups());//添加函数分组集合
        functionTypes.getFunctionTypes().addAll(cloudFunc.getFunctionTypes());//添加函数定义集合
        LoadFuncTypesEventArgs args = new LoadFuncTypesEventArgs(functionTypes);
        String funcsXML = FunctionTypes.serializeToXML(args.getFuncTypes());//对预置的函数进行序列化

        FormShowParameter showParameter = new FormShowParameter();
        showParameter.setFormId("botp_formula");//跳转《表达式》
        showParameter.getCustomParams().put("formula", formula);//传参，计算公式的参数
        showParameter.getCustomParams().put("entitynumber", sourceentity.getString("number"));//传参， 单据标识
        showParameter.getCustomParams().put("treenodes", billNodeJson);//传参，序列化的树形结构

        showParameter.getCustomParams().put("functiontypes", funcsXML);//传参，序列化的预置函数
        showParameter.setCloseCallBack(new CloseCallBack(this, "yem_formulas"));
        showParameter.getOpenStyle().setShowType(ShowType.Modal);
        this.getView().showForm(showParameter);
    }

    /**
     * @Description: 跳转《选择单据字段》
     * @function 创建树形结构，然后跳转《选择单据字段》携带参数
     * @purposes 用途
     * @return void
     */
    public void showSourceField() {
        DynamicObject sourceentity = (DynamicObject) this.getModel().getValue("yem_sourceentity");//获取【源单实体】
        if (sourceentity == null) {
            this.getView().showErrorNotification("请先填写源单实体。");
            return;
        }

        DynamicObject targetentity = (DynamicObject) this.getModel().getValue("yem_targetentity");//获取【目标单实体】
        MainEntityType targeEntityType = MetadataServiceHelper.getDataEntityType(targetentity.getString("number"));//获取元数据模型，主要用于读取字段类型和字段模型相关。

        int row = this.getModel().getEntryCurrentRowIndex("yem_fieldcontrast_e");//获取当前焦点行
        String targetFieldValue = (String) this.getModel().getValue("yem_targetkey", row);//获取【目标字段】的标识

        IDataEntityProperty targetProperty = targeEntityType.findProperty(targetFieldValue);///需要过滤显示的字段类型，根据【目标字段】进行过滤
        if (targetProperty == null) return;

        MainEntityType sourceMainType = MetadataServiceHelper.getDataEntityType(sourceentity.getString("number"));//获取元数据模型，主要用于读取字段类型和字段模型相关。
        BillTreeBuildParameter parameter = new BillTreeBuildParameter(sourceMainType, null, targetProperty);//创建树性结构的参数，树形结构显示的字段类型和【目标字段】一致
        parameter.setIncludePKField(true);//是否包含单据id
        TreeNode billTreeNode = EntityParseHelper.buildBillTreeNodes(parameter);//创建树性结构

        FormShowParameter showParameter = new FormShowParameter();
        showParameter.setFormId("botp_selectfield");
        String nodesJson = SerializationUtils.toJsonString(billTreeNode);//序列化
        showParameter.getCustomParams().put("treenodes", nodesJson);//传参
        showParameter.setCloseCallBack(new CloseCallBack(this, "yem_sourcefield"));
        showParameter.getOpenStyle().setShowType(ShowType.Modal);
        this.getView().showForm(showParameter);
    }

    @Override
    public void closedCallBack(ClosedCallBackEvent e) {
        String actionId = e.getActionId();
        Object returnData = e.getReturnData();
        switch (actionId) {
            case "yem_sourcefield"://【源单字段】
                setSourceInfor((String) returnData);//《选择单据字段》点击确定之后，将信息返回到单据上
                break;
            case "yem_formulas":
                setForMulas((String) returnData);
                break;
        }
    }

    /**
     * @Description: 《表达式》点击确定之后，将信息返回到单据上
     * @function 功能
     * @purposes 用途
     * @param returnData   《表达式》的返回值(序列化后的计算表达式)
     * @return void
     */
    public void setForMulas(String returnData) {
        if (StringUtils.isNotBlank(returnData)) {
            CRFormula formula = SerializationUtils.fromJsonString(returnData, CRFormula.class);//将返回值转换成计算公式
            int row = this.getModel().getEntryCurrentRowIndex("yem_fieldcontrast_e");//获取选中的焦点行
            this.getModel().setValue("yem_math", returnData, row);//计算公式序列话后的数据
            this.getModel().setValue("yem_formulas", formula.getExprDesc(), row);//输出合并后的计算公式描述
        }
    }

    /**
     * @Description: 《选择单据字段》点击确定之后，将信息返回到单据上
     * @function 功能
     * @purposes 用途
     * @param returnData   《选择单据字段》的返回值(字段标识)
     * @return void
     */
    public void setSourceInfor(String returnData) {
        DynamicObject sourceentity = (DynamicObject) this.getModel().getValue("yem_sourceentity");//获取【源单实体】
        MainEntityType sourceMainType = MetadataServiceHelper.getDataEntityType(sourceentity.getString("number"));//获取元数据模型，主要用于读取字段类型和字段模型相关。
        IDataEntityProperty property = null;
        for (EntityType entityType : sourceMainType.getAllEntities().values()) {
            if (!entityType.getFields().containsKey(returnData)) continue;//判断返回的字段标识是否存在
            property = entityType.getFields().get(returnData);
        }
        if (property == null) return;
        int rowIndex = this.getModel().getEntryCurrentRowIndex("yem_fieldcontrast_e");//获取选中的焦点行
        this.getModel().setValue("yem_sourcekey", returnData, rowIndex);//【源单字段标识】
        this.getModel().setValue("yem_sourcefield", buildPropFullCaption(property), rowIndex);//【源单字段】
    }
}
