package com.yem.wm.im.datadictionary.report;

import com.yem.wm.utils.RptUtil;
import com.yem.wm.utils.YEM;
import kd.bos.algo.*;
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.entity.BillEntityType;
import kd.bos.entity.EntryType;
import kd.bos.entity.SubEntryType;
import kd.bos.entity.property.BasedataProp;
import kd.bos.entity.property.EntryProp;
import kd.bos.entity.property.LinkEntryProp;
import kd.bos.entity.report.*;
import kd.bos.orm.ORM;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 数据字典
 *
 * @author longh
 * @description 报表查询插件
 * @date 2023年6月26日
 */
public class DataDictionaryRptQuery extends AbstractReportListDataPlugin {
    private static final String algoKey = DataDictionaryRptQuery.class.getName();
    private static List<String> fieldKeys1 = new ArrayList<>();// 表单元数据
    private static List<String> fieldKeys2 = new ArrayList<>();// 表单字段
    private static List<String> noPropNames = new ArrayList<>();

    static {
        noPropNames.add("LongProp");
        noPropNames.add("LinkEntryProp");
        noPropNames.add("DynamicLocaleProperty");
    }

    public static DataSet queryDataBill(String entityKey) {
        Field[] formFields = getFormFields();
        Collection<Object[]> collection = getFormFieldsData(entityKey);
        return Algo.create(algoKey).createDataSet(collection, new RowMeta(formFields));
    }

    private static Collection<Object[]> getFormFieldsData(String entityKey) {
        Collection<Object[]> collection = new ArrayList<>();
        if (YEM.isNotEmpty(entityKey)) {
            initMetaData(collection, YEM.getDataEntityType(entityKey));
        }
        return collection;
    }

    private static void initMetaData(Collection<Object[]> collection, IDataEntityType entityType) {
        String localeName = getLocaleName(entityType.getDisplayName());
        String parentLocaleName = "";
        if (entityType instanceof BillEntityType) {
            parentLocaleName = localeName;
            localeName = "单据头";
        } else if (entityType instanceof EntryType) {
            parentLocaleName = getLocaleName(entityType.getParent().getDisplayName());
        }
        List<IDataEntityType> entryTypes = new ArrayList<>();
        for (IDataEntityProperty property : entityType.getProperties()) {
            String number = property.getName();
            String alias = property.getAlias();
            String classSimpleName = property.getClass().getSimpleName();
            if (property instanceof EntryProp && !(property instanceof LinkEntryProp)) {
                entryTypes.add(((EntryProp) property).getItemType());
            } else {
                boolean isId = "id".equals(number);
                if (!noPropNames.contains(classSimpleName) || isId) {
                    String displayName = isId ? "ID" : getLocaleName(property.getDisplayName());
                    String fullnumber = number;
                    String fullname = displayName;
                    IDataEntityType parent = property.getParent();
                    if (parent instanceof SubEntryType) {
                        IDataEntityType grandParent = parent.getParent();
                        fullnumber = String.format("%s.%s.%s", grandParent.getName(), parent.getName(), fullnumber);
                        fullname = String.format("%s.%s.%s", getLocaleName(grandParent.getDisplayName()),
                                getLocaleName(parent.getDisplayName()), fullname);
                    } else if (parent instanceof EntryType) {
                        fullnumber = String.format("%s.%s", parent.getName(), fullnumber);
                        fullname = String.format("%s.%s", getLocaleName(parent.getDisplayName()), fullname);
                    }
                    String baseEntity = "";
                    String baseEntityId;
                    String baseEntityName;
                    if (property instanceof BasedataProp) {
                        BasedataProp basedataProp = (BasedataProp) property;
                        baseEntityId = basedataProp.getBaseEntityId();
                        baseEntityName = getLocaleName(basedataProp.getComplexType().getDisplayName());
                        baseEntity = String.format("%s（%s）", baseEntityName, baseEntityId);
                    }
                    int i = 0;
                    Object[] row = new Object[fieldKeys2.size()];
                    row[i++] = parentLocaleName;
                    row[i++] = localeName;
                    row[i++] = number;
                    row[i++] = fullnumber;
                    row[i++] = alias;
                    row[i++] = displayName;
                    row[i++] = fullname;
                    row[i++] = classSimpleName;
                    row[i++] = classSimpleName;
                    row[i++] = baseEntity;
                    collection.add(row);
                }
            }
        }
        for (IDataEntityType entryType : entryTypes) {
            initMetaData(collection, entryType);
        }
    }

    private static String getLocaleName(LocaleString displayName) {
        return displayName == null ? "" : displayName.getLocaleValue();
    }

    private static Field[] getFormFields() {
        fieldKeys2.clear();
        fieldKeys2.add("yem_parent2");
        fieldKeys2.add("yem_entity2");
        fieldKeys2.add("yem_number2");
        fieldKeys2.add("yem_fullnumber2");
        fieldKeys2.add("yem_alias2");
        fieldKeys2.add("yem_name2");
        fieldKeys2.add("yem_fullname2");
        fieldKeys2.add("yem_datatype2");
        fieldKeys2.add("yem_aliastype2");
        fieldKeys2.add("yem_basedatakey2");

        List<Field> fields = new ArrayList<>();
        for (String key : fieldKeys2) {
            fields.add(new Field(key, DataType.StringType));
        }
        return fields.toArray(new Field[0]);
    }

    @Override
    public DataSet query(ReportQueryParam param, Object obj) throws Throwable {
        return query(param);
    }

    @Override
    public List<AbstractReportColumn> getColumns(List<AbstractReportColumn> columns) throws Throwable {
        FilterInfo filterInfo = this.getQueryParam().getFilter();
        String rptType = filterInfo.getString("yem_type");
        List<String> fieldKeys = "2".equals(rptType) ? fieldKeys2 : fieldKeys1;
        for (int i = 0; i < columns.size(); i++) {
            ReportColumn column = (ReportColumn) columns.get(i);
            String fieldKey = column.getFieldKey();
            if (!fieldKeys.contains(fieldKey)) {
                columns.remove(i--);
            }
        }
        return super.getColumns(columns);
    }

    private DataSet query(ReportQueryParam param) {
        FilterInfo filterInfo = param.getFilter();
        String rptType = filterInfo.getString("yem_type");
        if ("2".equals(rptType)) {// 表单字段
            DynamicObject yem_fentityobj = filterInfo.getDynamicObject("yem_fentityobj");
            String entityKey = yem_fentityobj == null ? "" : yem_fentityobj.getString("number");
            return queryDataBill(entityKey);
        } else {// 表单元数据
            DataSet formmeta = queryFormMeta();
            DataSet bizapp = queryBizApp();
            DataSet dataSet = formmeta.join(bizapp, JoinType.INNER).on("bizappid", "yem_appid")
                    .select(RptUtil.getDataSetFiledAlias(formmeta), RptUtil.getDataSetFiledAlias(bizapp)).finish();
            fieldKeys1 = RptUtil.getDataSetAliasList(dataSet);
            return dataSet.where(createWhereStr(param))
                    .orderBy(new String[]{"yem_bizcloud", "yem_appid", "yem_modeltype"});
        }
    }

    private DataSet queryFormMeta() {
        List<String> fields = new ArrayList<>();
        fields.add("id yem_entityid");
        fields.add("number yem_entitykey");
        fields.add("name yem_entityname");
        fields.add("bizappid");
        fields.add("modeltype yem_modeltype");
        fields.add("isv yem_isv");
        return ORM.create().queryDataSet(algoKey, "bos_formmeta", String.join(",", fields), null);
    }

    private DataSet queryBizApp() {
        List<String> fields = new ArrayList<>();
        fields.add("id yem_appid");
        fields.add("number yem_appkey");
        fields.add("name yem_appname");
        fields.add("bizcloud yem_bizcloud");
        fields.add("bizcloud.name yem_bizcloudname");
        fields.add("bizcloud.number yem_bizcloudkey");
        fields.add("dbroute yem_dbroute");
        return ORM.create().queryDataSet(algoKey, "bos_devportal_bizapp", String.join(",", fields), null);
    }

    private String createWhereStr(ReportQueryParam param) {
        FilterInfo filterInfo = param.getFilter();
        String whereFilter = "1 = 1";
        // 业务云
        String yem_fbizcloud = filterInfo.getString("yem_fbizcloud");
        if (YEM.isNotEmpty(yem_fbizcloud)) {
            whereFilter = String.format("%s and (yem_bizcloudkey like '%%%s%%' or yem_bizcloudname like '%%%s%%')",
                    whereFilter, yem_fbizcloud, yem_fbizcloud);
        }
        // 应用
        String yem_fapp = filterInfo.getString("yem_fapp");
        if (YEM.isNotEmpty(yem_fapp)) {
            whereFilter = String.format("%s and (yem_appkey like '%%%s%%' or yem_appname like '%%%s%%')", whereFilter,
                    yem_fapp, yem_fapp);
        }
        // 表单
        String yem_fentity = filterInfo.getString("yem_fentity");
        if (YEM.isNotEmpty(yem_fentity)) {
            whereFilter = String.format("%s and (yem_entitykey like '%%%s%%' or yem_entityname like '%%%s%%')",
                    whereFilter, yem_fentity, yem_fentity);
        }
        // 模型类型
        String yem_fmodeltype = filterInfo.getString("yem_fmodeltype");
        if (YEM.isNotEmpty(yem_fmodeltype)) {
            whereFilter = String.format("%s and yem_modeltype = '%s'", whereFilter, yem_fmodeltype);
        }
        // 开发商标识
        String yem_fisv = filterInfo.getString("yem_fisv");
        if (YEM.isNotEmpty(yem_fisv)) {
            whereFilter = String.format("%s and yem_isv = '%s'", whereFilter, yem_fisv);
        }
        // 二开类型
        String yem_fext = filterInfo.getString("yem_fext");
        if ("B".equals(yem_fext)) {// 非扩展
            whereFilter += " and yem_entitykey not like '%_ext'";
        } else if ("C".equals(yem_fext)) {// 仅扩展
            whereFilter += " and yem_entitykey like '%_ext'";
        }

        return whereFilter;
    }

}
