package com.kingdee.eas.custom.dataconfig.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.kingdee.bos.Context;
import com.kingdee.bos.metadata.data.ColumnInfo;
import com.kingdee.bos.metadata.entity.*;
import com.kingdee.eas.custom.entryconfig.DataConfigSelectFieldEntryCollection;
import com.kingdee.eas.custom.entryconfig.DataConfigSelectFieldEntryInfo;
import com.kingdee.shr.base.syssetting.util.MetaDataUtil;

/**
 * SQL工具类，提供实体信息获取、SQL语句构建（关联表JOIN）以及查询字段信息JSON生成等功能
 */
public class SqlUtils {
    /**
     * 根据实体名称获取实体对象信息
     * @param name 实体名称
     * @param context 上下文对象（此处未实际使用，保留参数可能为扩展用）
     * @return 实体对象信息EntityObjectInfo
     */
    public EntityObjectInfo getEntryInfo(String name, Context context) {
        // 调用MetaDataUtil工具类根据实体名称获取实体对象信息
        return MetaDataUtil.getEntityObjectByEntityName(name);
    }

    /**
     * 构建SQL语句中的表连接部分（包括主表和关联表的LEFT JOIN）
     * @param sql 用于拼接SQL的StringBuilder对象
     * @param entityObjectInfo 实体对象信息，用于获取表名和属性信息
     * @param alias 表的别名，如果为null或空则使用实体真实名称作为别名
     * @param context 上下文对象（此处未实际使用，保留参数可能为扩展用）
     * @param isHead 是否为主表（头部表），主表不需要ON条件
     * @param on 连接条件，当isHead为false时使用
     */
    public void getSql(StringBuilder sql, EntityObjectInfo entityObjectInfo, String alias
            , Context context, Boolean isHead, String on) {
        // 如果别名为空或空字符串，则使用实体的真实名称作为别名
        if (alias == null || alias.equals("")) {
            String realName = entityObjectInfo.getRealName();
            alias = realName;
        }
        // 获取实体对应的数据库表名
        String name = entityObjectInfo.getTable().getName();
        // 拼接表名和别名到SQL中（如：table_name as "alias"）
        sql.append(name + " as ").append("\"" + alias + "\"").append("\n");
        // 如果不是主表，则拼接ON条件
        if (!isHead) {
            sql.append("on " + on).append("\n");
        }
        // 获取实体所有非重复的继承属性集合
        PropertyCollection properties = entityObjectInfo.getInheritedNoDuplicatedProperties();
        // 遍历属性集合
        for (int i = 0; i < properties.size(); i++) {
            PropertyInfo propertyInfo = properties.get(i);

            // 判断当前属性是否为关联属性（LinkPropertyInfo）
            if (propertyInfo instanceof LinkPropertyInfo) {

                // 生成关联表的别名（当前属性名 + 主表别名）
                String name1 = propertyInfo.getName() + alias;

                // 获取关联属性对应的映射字段（数据库列）
                ColumnInfo mappingField = propertyInfo.getMappingField();
                // 如果映射字段为空，则跳过当前属性
                if (mappingField == null) {
                    continue;
                }
                // 获取映射字段的名称（数据库列名）
                String mappingFieldName = mappingField.getName();
                // 获取关联属性指向的目标实体对应的表名
                String tableName = ((LinkPropertyInfo) propertyInfo).getRelationship().getSupplierObject().getTable().getName();
                // 强制转换为LinkPropertyInfo以便获取关联关系
                LinkPropertyInfo linkPropertyInfo = ((LinkPropertyInfo) propertyInfo);
                RelationshipInfo r = linkPropertyInfo.getRelationship();
                // 获取目标实体的全限定名
                String fullName = r.getSupplierObject().getFullName();
                // 拼接LEFT JOIN语句，关联目标表（如：left join target_table as "name1"）
                sql.append("left join ").append(tableName).append(" as ").append("\"" + name1 + "\"").append("\n");
                // 拼接关联条件（主表别名.映射列名 = 关联表别名.FID）
                sql.append("on \"" + alias + "\".\"" + mappingFieldName + "\" = " + " \"" + name1 + "\".\"FID" + "\" ").append("\n");
                // 根据目标实体全限定名获取其实体对象信息
                EntityObjectInfo entryInfo = this.getEntryInfo(fullName, context);
                // 获取目标实体的所有非重复继承属性集合
                PropertyCollection propertiesChildren = entryInfo.getInheritedNoDuplicatedProperties();

                // 遍历目标实体的属性集合（处理二级关联）
                for (int j = 0; j < propertiesChildren.size(); j++) {
                    PropertyInfo propertyChildren = propertiesChildren.get(j);
                    // 判断二级属性是否为关联属性
                    if (propertyChildren instanceof LinkPropertyInfo) {
                        // 生成二级关联表的别名（一级关联表别名.二级属性名）
                        String asTableChildren = name1 + "." + propertyChildren.getName();
                        // 获取二级关联属性的映射字段
                        ColumnInfo mappingFieldChildren = propertyChildren.getMappingField();
                        // 如果映射字段为空，则跳过当前二级属性
                        if (mappingFieldChildren == null) {
                            continue;
                        }
                        // 获取二级关联属性指向的目标表名
                        String tableChildren = ((LinkPropertyInfo) propertyChildren).getRelationship().getSupplierObject().getTable().getName();
                        // 获取二级映射字段的名称（数据库列名）
                        String mappingFieldNameChildren = mappingFieldChildren.getName();
                        // 拼接二级LEFT JOIN语句（如：left join child_table as "asTableChildren"）
                        sql.append("left join ").append(tableChildren).append(" as ").append("\"" + asTableChildren + "\"").append("\n");
                        // 拼接二级关联条件（一级关联表别名.二级映射列名 = 二级关联表别名.FID）
                        sql.append("on \"" + name1 + "\".\"" + mappingFieldNameChildren + "\" = " + " \"" + asTableChildren + "\".\"FID" + "\" ").append("\n");

                    }

                }
            }

        }

    }

    /**
     * 生成查询字段的信息JSON数组，包含字段名、别名、数据类型、映射关系等
     * @param entityObjectInfo 实体对象信息，用于获取属性信息
     * @param alias 表别名，用于构建字段映射路径
     * @param context 上下文对象（用于获取关联实体信息）
     * @return 包含字段信息的JSONArray
     */
    public JSONArray getSelectField(EntityObjectInfo entityObjectInfo, String alias, Context context) {
        // 如果别名为空或空白，则默认使用实体的真实名称作为别名
        if (alias == null || alias.trim().isEmpty()) {
            alias = entityObjectInfo.getRealName();
        }

        // 获取实体所有非重复的继承属性集合
        PropertyCollection properties = entityObjectInfo.getInheritedNoDuplicatedProperties();
        JSONArray resultArray = new JSONArray(); // 用于存储返回的字段信息JSON数组

        // 遍历实体属性集合
        for (int i = 0; i < properties.size(); i++) {
            PropertyInfo propertyInfo = properties.get(i);
            JSONObject currentJson = new JSONObject(); // 存储当前属性的信息JSON对象

            // 判断当前属性是否为关联属性（LinkPropertyInfo）
            if (propertyInfo instanceof LinkPropertyInfo) {
                // 强制转换为LinkPropertyInfo
                LinkPropertyInfo linkProperty = (LinkPropertyInfo) propertyInfo;
                String fieldName = linkProperty.getName(); // 属性名称
                String fieldAlias = linkProperty.getAlias(); // 属性别名

                // 设置当前关联属性的基础信息
                currentJson.put("field", alias+"."+fieldName);
                currentJson.put("name", fieldAlias);
                currentJson.put("dataType", DataType.OBJECTVALUE.getName());

                // 获取关联属性的映射字段（数据库列）
                ColumnInfo mappingField = linkProperty.getMappingField();
                if (mappingField == null) {
                    continue; // 若映射字段为空，则跳过当前属性
                }
                // 获取关联关系信息
                RelationshipInfo relationship = linkProperty.getRelationship();
                // 获取关联目标实体的全限定名（作为枚举来源）
                String enumSource = relationship.getSupplierObject().getFullName();
                currentJson.put("enumSource", enumSource);

                // 根据目标实体全限定名获取其实体对象信息
                EntityObjectInfo relatedEntity = this.getEntryInfo(enumSource, context);
                // 获取目标实体的所有非重复继承属性集合（子属性）
                PropertyCollection childProperties = relatedEntity.getInheritedNoDuplicatedProperties();
                JSONArray childrenArray = new JSONArray(); // 存储子属性信息的JSON数组
                String realName = relatedEntity.getRealName();
                // 遍历目标实体的子属性
                for (int j = 0; j < childProperties.size(); j++) {
                    PropertyInfo childProperty = childProperties.get(j);
                    JSONObject childJson = new JSONObject(); // 存储当前子属性的信息JSON对象

                    // 设置子属性的基础信息
                    childJson.put("field", alias+"."+realName+"."+childProperty.getName());
                    childJson.put("name", childProperty.getAlias());
                    childJson.put("dataType", DataType.OBJECTVALUE.getName());

                    // 判断子属性是否为关联属性（二级关联）
                    if (childProperty instanceof LinkPropertyInfo) {
                        // 强制转换为LinkPropertyInfo
                        LinkPropertyInfo childLink = (LinkPropertyInfo) childProperty;
                        // 获取二级关联属性的映射字段
                        ColumnInfo childMappingField = childLink.getMappingField();
                        if (childMappingField == null) {
                            continue; // 若映射字段为空，则跳过当前子属性
                        }

                        // 获取二级关联关系信息
                        RelationshipInfo childRelationship = childLink.getRelationship();
                        // 获取二级关联目标实体的全限定名
                        String childEnumSource = childRelationship.getSupplierObject().getFullName();
                        // 避免循环关联（若二级关联目标与一级关联目标相同，则跳过）
                        if (childEnumSource.equals(enumSource)) {
                            continue;
                        }
                        childJson.put("enumSource", childEnumSource);

                        // 根据二级关联目标实体全限定名获取其实体对象信息
                        EntityObjectInfo grandChildEntity = this.getEntryInfo(childEnumSource, context);
                        // 获取二级目标实体的所有非重复继承属性集合（孙属性）
                        PropertyCollection grandChildProperties = grandChildEntity.getInheritedNoDuplicatedProperties();
                        JSONArray grandChildArray = new JSONArray(); // 存储孙属性信息的JSON数组

                        // 遍历孙属性
                        for (int k = 0; k < grandChildProperties.size(); k++) {
                            PropertyInfo grandChildProperty = grandChildProperties.get(k);
                            // 只处理自有属性（OwnPropertyInfo），跳过关联属性
                            if (!(grandChildProperty instanceof OwnPropertyInfo)) {
                                continue;
                            }
                            // 强制转换为OwnPropertyInfo
                            OwnPropertyInfo ownGrandChild = (OwnPropertyInfo) grandChildProperty;
                            JSONObject grandChildJson = new JSONObject();

                            // 设置孙属性的基础信息
                            grandChildJson.put("field",  alias+"."+realName+"."+childProperty.getName()+"."+ownGrandChild.getName());
                            grandChildJson.put("name", ownGrandChild.getAlias());
                            grandChildJson.put("dataType", ownGrandChild.getDataType().getName());

                            // 若孙属性为枚举类型，设置枚举来源
                            if (ownGrandChild.getDataType().getName().equals("Enum")) {
                                grandChildJson.put("enumSource", ownGrandChild.getEnumType().getFullName());
                                grandChildJson.put("enumData",  ownGrandChild.getEnumType().getEnumValue());
                            }

                            // 处理孙属性的数据库字段映射（考虑多语言）
                            boolean isMultilingual = ownGrandChild.getMappingField().isMultilingual();
                            // 构建父字段路径（一级关联别名.二级属性名）
                            String parentFieldPath = fieldName + alias + "." + childProperty.getName();
                            // 获取孙属性对应的数据库列名
                            String dbFieldName = ownGrandChild.getMappingField().getName();
                            String mappingFieldVal; // 数据库字段引用（如："alias.field"."dbColumn"）
                            String asMappingFieldVal; // 字段别名（如："alias.field.dbColumn"）

                            // 多语言字段拼接_l2后缀（可能为特定语言标识）
                            if (isMultilingual) {
                                mappingFieldVal = "\"" + parentFieldPath + "\"." + dbFieldName + "_l2";
                                asMappingFieldVal = "\"" + parentFieldPath + "." + dbFieldName + "_l2\"";
                            } else {
                                mappingFieldVal = "\"" + parentFieldPath + "\"." + dbFieldName;
                                asMappingFieldVal = "\"" + parentFieldPath + "." + dbFieldName + "\"";
                            }
                            grandChildJson.put("mappingField", mappingFieldVal);
                            grandChildJson.put("asMappingField", asMappingFieldVal);

                            // 将孙属性信息添加到孙属性数组
                            grandChildArray.add(grandChildJson);
                        }
                        // 将孙属性数组添加到当前子属性的JSON中
                        childJson.put("children", grandChildArray);

                    } else if (childProperty instanceof OwnPropertyInfo) {
                        // 子属性为自有属性（OwnPropertyInfo）
                        OwnPropertyInfo ownChild = (OwnPropertyInfo) childProperty;
                        // 设置子属性的数据类型
                        childJson.put("dataType", ownChild.getDataType().getName());

                        // 若子属性为枚举类型，设置枚举来源
                        if (ownChild.getDataType().getName().equals("Enum")) {
                            childJson.put("enumSource", ownChild.getEnumType().getFullName());
                            childJson.put("enumData",  ownChild.getEnumType().getEnumValue());
                        }

                        // 处理子属性的数据库字段映射（考虑多语言）
                        boolean isMultilingual = ownChild.getMappingField().isMultilingual();
                        // 获取子属性对应的数据库列名
                        String dbFieldName = ownChild.getMappingField().getName();
                        String mappingFieldVal; // 数据库字段引用
                        String asMappingFieldVal; // 字段别名

                        // 多语言字段拼接_l2后缀
                        if (isMultilingual) {
                            mappingFieldVal = "\"" + fieldName + alias + "\"." + dbFieldName + "_l2";
                            asMappingFieldVal = "\"" + fieldName + alias + "." + dbFieldName + "_l2\"";
                        } else {
                            mappingFieldVal = "\"" + fieldName + alias + "\"." + dbFieldName;
                            asMappingFieldVal = "\"" + fieldName + alias + "." + dbFieldName + "\"";
                        }
                        childJson.put("mappingField", mappingFieldVal);
                        childJson.put("asMappingField", asMappingFieldVal);
                    }

                    // 将子属性信息添加到子属性数组
                    childrenArray.add(childJson);
                }

                // 将子属性数组添加到当前关联属性的JSON中
                currentJson.put("children", childrenArray);
                // 将当前关联属性信息添加到结果数组
                resultArray.add(currentJson);

            } else if (propertyInfo instanceof OwnPropertyInfo) {
                // 当前属性为自有属性（OwnPropertyInfo）
                OwnPropertyInfo ownProperty = (OwnPropertyInfo) propertyInfo;
                String fieldName = ownProperty.getName(); // 属性名称
                String dbFieldName = ownProperty.getMappingField().getName(); // 对应的数据库列名

                // 设置自有属性的基础信息
                currentJson.put("field", alias+"."+fieldName);
                currentJson.put("name", ownProperty.getAlias());
                currentJson.put("dataType", ownProperty.getDataType().getName());

                // 若自有属性为枚举类型，设置枚举来源
                if (ownProperty.getDataType().getName().equals("Enum")) {
                    currentJson.put("enumSource", ownProperty.getEnumType().getFullName());
                    currentJson.put("enumData",  ownProperty.getEnumType().getEnumValue());
                }

                // 处理自有属性的数据库字段映射（考虑多语言）
                boolean isMultilingual = ownProperty.getMappingField().isMultilingual();
                String mappingFieldVal; // 数据库字段引用
                String asMappingFieldVal; // 字段别名

                // 多语言字段拼接_l2后缀
                if (isMultilingual) {
                    mappingFieldVal = "\"" + alias + "\"." + dbFieldName + "_l2";
                    asMappingFieldVal = "\"" + alias + "." + dbFieldName + "_l2\"";
                } else {
                    mappingFieldVal = "\"" + alias + "\"." + dbFieldName;
                    asMappingFieldVal = "\"" + alias + "." + dbFieldName + "\"";
                }
                currentJson.put("mappingField", mappingFieldVal);
                currentJson.put("asMappingField", asMappingFieldVal);

                // 将当前自有属性信息添加到结果数组
                resultArray.add(currentJson);
            }
        }
        // 返回包含所有字段信息的JSON数组
        return resultArray;
    }
    public StringBuilder getSelectField(DataConfigSelectFieldEntryCollection fieldEntry,StringBuilder sql){
        for (int i = 0; i < fieldEntry.size(); i++) {
            DataConfigSelectFieldEntryInfo entryInfo = fieldEntry.get(i);
            String databaseName = entryInfo.getDatabaseName();
            String mappingKey = entryInfo.getMappingKey();
            sql.append(databaseName).append(" as ").append(mappingKey);
            if (i==fieldEntry.size()-1){
                sql.append("\n");
            }else {
                sql.append(" , ").append("\n");
            }
        }
        return sql;
    }

}