package com.persagy.proxy.adm.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.persagy.dmp.basic.utils.JsonNodeUtils;
import com.persagy.dmp.common.exception.BusinessException;
import com.persagy.dmp.common.helper.SpringHelper;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * ADM通用查询条件
 * @author Charlie Yu
 * @date 2021-08-16
 */
public class AdmEntityTransferUtil {

    /**
     * 转换为数据中台对象
     * @param objList
     * @return
     */
    public static ArrayNode toDmpMultiEntity(List objList) {
        ArrayNode arrayNode = JsonNodeUtils.toArrayNode(objList, "infos", null);
        if(arrayNode == null) {
            return arrayNode;
        }
        // outline特殊处理
        for(int i = 0;i < arrayNode.size();i++) {
            ObjectNode jsonNode = (ObjectNode) arrayNode.get(i);
            JsonNode outLine = jsonNode.get("outline");
            if(outLine != null && !outLine.isTextual()) {
                jsonNode.remove("outline");
                jsonNode.put("outline", outLine.toString());
            }
            JsonNode nullNode = jsonNode.get("nullList");
            if(nullNode == null || !nullNode.isArray()) {
                continue;
            }
            ArrayNode nullList = (ArrayNode) nullNode;
            ArrayNode removeNode = jsonNode.putArray("$remove");
            for(int k=0; k < nullList.size(); k++){
                String node = nullList.get(k).textValue();
                if(StrUtil.isBlank(node)) {
                    continue;
                }
                if(node.startsWith("infos.")){
                    node = node.replace("infos.","");
                }
                jsonNode.remove(node);
                removeNode.add(node);
            }
            jsonNode.remove("nullList");
        }
        return arrayNode;
    }

    /**
     * 转换为数据中台对象
     * @param obj
     * @return
     */
    public static JsonNode toDmpSingleEntity(Object obj) {
        return JsonNodeUtils.toObjectNode(obj, "infos", null);
    }

    /**
     * 转换为数据中心对象
     * @param array 数据中台对象
     * @param clazz 数据中心对象class
     * @param <T>
     * @return
     */
    public static <T> List<T> toAdmMultiEntity(List array, List<String> projection, Class<T> clazz) {
        ArrayNode dataNode = JsonNodeUtils.toArrayNode(array, "infos", null);
        return toAdmMultiEntity(dataNode, projection, clazz);
    }
    
    public static <T> List<T> toAdmMultiEntityExtra(List array, List<String> projection, Class<T> clazz) {
        ArrayNode dataNode = JsonNodeUtils.toArrayNode(array, null, null);
        return toAdmMultiEntityExtra(dataNode, projection, clazz);
    }

    /**
     * 转换为数据中心对象
     * @param array
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> List<T> toAdmMultiEntity(ArrayNode array, List<String> projection, Class<T> clazz) {
        if(ArrayUtil.isEmpty(array)) {
            return null;
        }
        // 转换属性名
        for(int i = 0, j = array.size();i < j;i++) {
            JsonNode node = array.get(i);
            if(node != null && node.isObject()) {
                resetAdmProperty((ObjectNode) node, projection);
            }
        }
        return JsonNodeUtils.toEntity(array, clazz, "infos");
        /*try {
			return JSONEntityUtil.toEntity(array, clazz, "infos");
		} catch (IOException e) {
			e.printStackTrace();
		}
        return null;*/
    }
    
    public static <T> List<T> toAdmMultiEntityExtra(ArrayNode array, List<String> projection, Class<T> clazz) {
        if(ArrayUtil.isEmpty(array)) {
            return null;
        }
        // 转换属性名
        for(int i = 0, j = array.size();i < j;i++) {
            JsonNode node = array.get(i);
            if(node != null && node.isObject()) {
                resetAdmProperty((ObjectNode) node, projection);
            }
        }
        try {
			return JSONEntityUtil.toEntity(array, clazz, "infos");
		} catch (IOException e) {
			e.printStackTrace();
		}
        return null;
    }

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

    /**
     * 处理dmp转adm对象的属性名
     * @param node
     */
    private static void resetAdmProperty(ObjectNode node, List<String> projection) {
        // 转换属性名 TODO 目前只有创建时间和修改时间需要转换，后续有其他时通过建立映射在此转换即可
        copyProperty(node, "creationTime", "createTime");
        copyProperty(node, "modifiedTime", "lastUpdate");
        copyProperty(node, "objType", "objectType");
        // outline特殊处理
        JsonNode outLine = node.get("outline");
        if(outLine != null && outLine.isTextual()) {
            node.remove("outline");
            ArrayNode arrayNode = toSingleEntityQuietly(outLine.textValue(), ArrayNode.class);
            node.set("outline", arrayNode);
        }
        removeProperty(node, projection);
    }

    /**
     * 转换为指定对象
     * @param jsonStr
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T toSingleEntityQuietly(String jsonStr, Class<T> clazz) {
        try {
            return SpringHelper.getBean(ObjectMapper.class).readValue(jsonStr, clazz);
        } catch (IOException e) {
            throw new BusinessException("outline格式解析失败");
        }
    }

    /**
     * 拷贝属性
     * @param dmpData 数据中台对象
     * @param srcProp 数据中台属性名
     * @param desProp 对应的数据中心属性名
     */
    private static void copyProperty(ObjectNode dmpData, String srcProp, String desProp) {
        if(dmpData == null) {
            return;
        }
        JsonNode value = dmpData.get(srcProp);
        if(value == null || value.isNull()) {
            return;
        }
        dmpData.set(desProp, value);
        dmpData.remove(srcProp);
    }

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