package com.persagy.labsl.utils

import com.persagy.dmp.basic.utils.JsonNodeUtils
import com.persagy.labsl.utils.AdmEntityTransferUtil
import cn.hutool.core.collection.CollUtil
import cn.hutool.core.util.ArrayUtil
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.node.ArrayNode
import com.fasterxml.jackson.databind.node.ObjectNode

/**
 * ADM通用查询条件
 * @author Charlie Yu
 * @date 2021-08-16
 */
object AdmEntityTransferUtil {
    /**
     * 转换为数据中台对象
     * @param objList
     * @return
     */
    fun toDmpMultiEntity(objList: List<*>?): ArrayNode {
        return JsonNodeUtils.toArrayNode(objList, "infos", null)
    }

    /**
     * 转换为数据中台对象
     * @param obj
     * @return
     */
    fun toDmpSingleEntity(obj: Any?): JsonNode {
        return JsonNodeUtils.toObjectNode(obj, "infos", null)
    }

    /**
     * 转换为数据中心对象
     * @param array 数据中台对象
     * @param clazz 数据中心对象class
     * @param <T>
     * @return
    </T> */
    fun <T> toAdmMultiEntity(array: List<*>?, projection: List<String?>?, clazz: Class<T>?): List<T>? {
        val dataNode = JsonNodeUtils.toArrayNode(array, null, null)
        return toAdmMultiEntity(dataNode, projection, clazz)
    }

    /**
     * 转换为数据中心对象
     * @param clazz
     * @param <T>
     * @return
     * @param array
    </T> */
    fun <T> toAdmMultiEntity(array: ArrayNode, projection: List<String?>?, clazz: Class<T>?): List<T>? {
        if (ArrayUtil.isEmpty(array)) {
            return null
        }
        // 转换属性名
        var i = 0
        val j = array.size()
        while (i < j) {
            val node = array[i]
            if (node != null && node.isObject) {
                resetAdmProperty(node as ObjectNode, projection)
            }
            i++
        }
        return JsonNodeUtils.toEntity(array, clazz, "infos")
    }

    /**
     * 转换为数据中心对象
     * @param node
     * @param clazz
     * @param <T>
     * @return
    </T> */
    fun <T> toAdmSingleEntity(node: ObjectNode, projection: List<String?>?, clazz: Class<T>?): T {
        resetAdmProperty(node, projection)
        return JsonNodeUtils.toEntity(node, clazz, "infos")
    }

    /**
     * 处理dmp转adm对象的属性名
     * @param node
     */
    private fun resetAdmProperty(node: ObjectNode, projection: List<String?>?) {
        // 转换属性名 TODO 目前只有创建时间和修改时间需要转换，后续有其他时通过建立映射在此转换即可
        copyProperty(node, "creationTime", "createTime")
        copyProperty(node, "modifiedTime", "lastUpdate")
        copyProperty(node, "objType", "objectType")
        removeProperty(node, projection)
    }

    /**
     * 拷贝属性
     * @param dmpData 数据中台对象
     * @param srcProp 数据中台属性名
     * @param desProp 对应的数据中心属性名
     */
    private fun copyProperty(dmpData: ObjectNode?, srcProp: String, desProp: String) {
        if (dmpData == null) {
            return
        }
        val value = dmpData[srcProp]
        if (value == null || value.isNull) {
            return
        }
        dmpData.set<JsonNode>(desProp, value)
        dmpData.remove(srcProp)
    }

    /**
     * 删除掉数据中心不需要的属性
     * @param dmpData
     */
    private fun removeProperty(dmpData: ObjectNode, projection: List<String?>?) {
        if (CollUtil.isNotEmpty(projection)) {
            // 转换为Set，提供遍历效率
            val fieldSet: Set<String?> = CollUtil.newHashSet(projection)
            val fields = dmpData.fieldNames()
            while (fields.hasNext()) {
                val field = fields.next()
                // 返回结果中包含的不处理
                if (fieldSet.contains(field)) {
                    continue
                }
                // 去掉不包含的属性
                fields.remove()
            }
        } else {
            // 返回全部时，去掉不需要属性
            val removeList: List<String> = CollUtil.newArrayList("creator", "valid", "createApp", "virtualCodes", "updateApp", "grouping", "modifier")
            for (removeField in removeList) {
                dmpData.remove(removeField)
            }
        }
    }
}