package com.persagy.dmp.basic.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Filter;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.databind.JavaType;
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.common.constant.ResponseCode;
import com.persagy.dmp.common.exception.BusinessException;
import com.persagy.dmp.common.helper.SpringHelper;
import org.apache.poi.ss.formula.functions.FactDouble;
import org.apache.poi.ss.formula.functions.T;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;

/**
 * JsonNode 工具
 * @author Charlie Yu
 * @date 2021-06-25
 */
public class JsonNodeUtils {

    /**
     * 将对象转换为Json对象，自动扩充扩展列
     * @param vo 对象
     * @param extraColumn 扩展列名
     * @param extraColumns 扩展属性中包含的列。为空表示所有非对象的列
     * @return Json对象
     */
    public static ObjectNode toObjectNode(Object vo, String extraColumn, Set<String> extraColumns) {
        if(vo == null) {
            return null;
        }
        // 将vo转换为ObjectNode
        ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
        ObjectNode node = null;
        try {
            String voJson = objectMapper.writeValueAsString(vo);
            node = objectMapper.readValue(voJson, ObjectNode.class);
        } catch (IOException e) {
            throw new BusinessException(ResponseCode.A0427.getCode(), ResponseCode.A0427.getDesc());
        }
        ensureExtras(node, extraColumn, extraColumns);
        return node;
    }

    /**
     * 将对象转换为Json对象，自动扩充扩展列
     * @param voList List对象
     * @param extraColumn 扩展列名
     * @param extraColumns 扩展属性中包含的列。为空表示所有非对象的列
     * @return Json对象
     */
    public static List<ObjectNode> toListNode(List voList, String extraColumn, Set<String> extraColumns) {
        if(CollUtil.isEmpty(voList)) {
            return null;
        }
        // 将vo转换为ObjectNode
        ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
        List<ObjectNode> array = null;
        try {
            String voJson = objectMapper.writeValueAsString(voList);
            JavaType javaType = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, ObjectNode.class);
            array = objectMapper.readValue(voJson, javaType);
        } catch (IOException e) {
            throw new BusinessException(ResponseCode.A0427.getCode(), ResponseCode.A0427.getDesc());
        }
        for(int i = 0;i < array.size();i++) {
            ObjectNode node = (ObjectNode) array.get(i);
            ensureExtras(node, extraColumn, extraColumns);
        }
        return array;
    }

    /**
     * 将对象转换为Json对象，自动扩充扩展列
     * @param voList List对象
     * @param extraColumn 扩展列名
     * @param extraColumns 扩展属性中包含的列。为空表示所有非对象的列
     * @return Json对象
     */
    public static ArrayNode toArrayNode(List voList, String extraColumn, Set<String> extraColumns) {
        if(CollUtil.isEmpty(voList)) {
            return null;
        }
        // 将vo转换为ObjectNode
        ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
        ArrayNode array = null;
        try {
            String voJson = objectMapper.writeValueAsString(voList);
            array = objectMapper.readValue(voJson, ArrayNode.class);
        } catch (IOException e) {
            throw new BusinessException(ResponseCode.A0427.getCode(), ResponseCode.A0427.getDesc());
        }
        for(int i = 0;i < array.size();i++) {
            ObjectNode node = (ObjectNode) array.get(i);
            ensureExtras(node, extraColumn, extraColumns);
        }
        return array;
    }

    /**
     * 在Json对象中扩充扩展列
     * @param node json对象
     * @param extraColumn 扩展列名
     * @param extraColumns 扩展属性中包含的列。为空表示所有非对象的列
     */
    private static void ensureExtras(ObjectNode node, String extraColumn, Set<String> extraColumns) {
        // 没有扩展列不用处理
        if(StrUtil.isBlank(extraColumn)) {
            return;
        }
        JsonNode extraNode = node.get(extraColumn);
        // 如果扩展列的值为空或不是对象，直接返回
        if(extraNode == null || extraNode.isNull() || !extraNode.isObject()) {
            return;
        }
        Iterator<String> extraKeys = extraNode.fieldNames();
        while (extraKeys.hasNext()) {
            String extraKey = extraKeys.next();
            // 外部已有的属性，不再赋值
            if (node.has(extraKey)) {
                continue;
            }
            // 如果有设置过滤列，且不在过滤列范围内，则不移出
            if(CollUtil.isNotEmpty(extraColumns) && !extraColumns.contains(extraKey)) {
                continue;
            }
            // 将extra移到外部
            node.set(extraKey, extraNode.get(extraKey));
        }
        // 删除extra
        node.remove(extraColumn);
    }

    /**
     * json转换为Clazz,为扩展属性赋值
     * @param node json对象
     * @param clazz 类
     * @param extraColumn 扩展属性名
     * @param <T>
     * @return
     */
    public static <T> T toEntity(ObjectNode node, Class<T> clazz, String extraColumn) {
        // 检查clazz包含的属性
        Map<String, Field> fieldMap = getFieldMap(clazz);
        Set<String> fieldSet = fieldMap.keySet();
        // 转换node
        collectExtras(node, extraColumn, fieldSet, null);
        // 转换为对象
        ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
        try {
            return objectMapper.readValue(node.toString(), clazz);
        } catch (IOException e) {
            throw new BusinessException(ResponseCode.A0427.getCode(), ResponseCode.A0427.getDesc());
        }
    }

    /**
     * json转换为Clazz,为扩展属性赋值
     * @param array json对象
     * @param clazz 类
     * @param extraColumn 扩展属性名
     * @param <T>
     * @return
     */
    public static <T> List<T> toEntity(ArrayNode array, Class<T> clazz, String extraColumn) {
        // 检查clazz包含的属性
        Map<String, Field> fieldMap = getFieldMap(clazz);
        Set<String> fieldSet = fieldMap.keySet();
        // 转换node
        for(int i = 0;i < array.size();i++) {
            ObjectNode node = (ObjectNode) array.get(i);
            collectExtras(node, extraColumn, fieldSet, null);
        }
        // 转换为对象List
        ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
        try {
            JavaType javaType = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, clazz);
            return objectMapper.readValue(array.toString(), javaType);
        } catch (IOException e) {
            throw new BusinessException(ResponseCode.A0427.getCode(), ResponseCode.A0427.getDesc());
        }
    }
    /***
     * Description: 根据字段映射过滤掉字段带有false的字段
     * @param clazz : 对象类型
     * @return : java.util.Map<java.lang.String,java.lang.reflect.Field>  
     * @author : lijie
     * @date :2021/10/20 18:13
     * Update By lijie 2021/10/20 18:13
     */
    public static <T> Map<String,Field> getFieldMap(Class<T> clazz){
        Map<String, Field> fieldMap = ReflectUtil.getFieldMap(clazz);
        return MapUtil.filter(fieldMap, (Filter<Map.Entry<String, Field>>) entry -> {
            Field field = entry.getValue();
            TableField tableField = field.getAnnotation(TableField.class);
            if (null != tableField && !tableField.exist()) {
                return false;
            }
            return true;
        });
    }

    /**
     * 收集扩展属性
     * @param node json对象
     * @param extraColumn 扩展列名
     * @param classColumns 对象包含的列
     * @param extraColumns 扩展属性中包含的列。为空表示所有非对象的列
     */
    private static void collectExtras(ObjectNode node, String extraColumn, Set<String> classColumns, Set<String> extraColumns) {
        ObjectNode extraNode = node.putObject(extraColumn);
        Iterator<String> nodeKeys = node.fieldNames();
        while (nodeKeys.hasNext()) {
            String nodeKey = nodeKeys.next();
            // clazz有的属性不用处理
            if (classColumns.contains(nodeKey)) {
                continue;
            }

            // 扩展列为空，或在扩展列范围内
            if(CollUtil.isEmpty(extraColumns) || extraColumns.contains(nodeKey)) {
                // clazz没有的属性添加到扩展属性中
                extraNode.set(nodeKey, node.get(nodeKey));
            }
            // 移除node中此属性
            nodeKeys.remove();
        }
    }

    /**
     * 获取Node值
     * @param node 值节点
     * @return
     */
    public static Object getNodeValue(JsonNode node) {
        if(node == null || node.isContainerNode() || node.isNull()) {
            return null;
        }
        if(node.isBigDecimal()) {
            return node.decimalValue();
        }
        if(node.isBigInteger()) {
            return node.bigIntegerValue();
        }
        if(node.isBoolean()) {
            return node.booleanValue();
        }
        if(node.isBinary()) {
            try {
                return node.binaryValue();
            } catch (IOException e) {
                return null;
            }
        }
        if(node.isDouble()) {
            return node.doubleValue();
        }
        if(node.isFloat()) {
            return node.floatValue();
        }
        if(node.isInt()) {
            return node.intValue();
        }
        if(node.isLong()) {
            return node.longValue();
        }
        if(node.isNumber()) {
            return node.numberValue();
        }
        if(node.isShort()) {
            return node.shortValue();
        }
        if(node.isTextual()) {
            return node.textValue();
        }
        return null;
    }

    /**
     * 获取列表值
     * @param node 列表值类型节点
     * @return
     */
    public static List getListValue(JsonNode node) {
        if(!node.isArray()) {
            return null;
        }
        List values = new ArrayList<>(node.size());
        Iterator<JsonNode> elements = node.elements();
        while (elements.hasNext()) {
            values.add(getNodeValue(elements.next()));
        }
        return values;
    }
}
