package com.persagy.proxy.adm.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
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.core.JsonParseException;
import com.fasterxml.jackson.databind.*;
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.proxy.object.model.AdmSpace;

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

/**
 * 
 * @version 1.0.0
 * @company persagy 
 * @author zhangqiankun
 * @date 2021年10月23日 下午5:52:21
 */
public class JSONEntityUtil {
	
	private static ObjectMapper objectMapper = new ObjectMapper();
	static {
		objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
	}
	
	//private static ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
	
	public static void main(String[] args) throws IOException {
		String temp = "{\"id\":\"Sp120901020301e9cc2ebdb24afeb89e3048153342d0\",\"projectId\":\"Pj1209010203\",\"name\":\"空间-M8Z77\",\"localId\":\"45343555\",\"localName\":\"12.11.43413.\",\"classCode\":\"DomesticWaterSupplyZone\",\"groupCode\":\"QKZZ\",\"infos\":{\"floorId\":\"Fl1209010203008c60dd3fcf45d5bc361d46989f1dab\",\"zoneType\":\"DomesticWaterSupplyZone\",\"buildingId\":\"Bd120901020324de2bf7c9b4442d907c6f5400945894\",\"height\":1.0},\"createTime\":1634983298000,\"objectType\":\"space\"}";
		
		JsonNode readTree = objectMapper.readTree(temp);
		ObjectNode objectNode = (ObjectNode)readTree;
		AdmSpace entity = toEntity(objectNode, AdmSpace.class, CollUtil.newHashSet("infos"), null);
		System.out.println(entity.getBuildingId());
		
		temp = "[{\"id\":\"Sp120901020301e9cc2ebdb24afeb89e3048153342d0\",\"projectId\":\"Pj1209010203\",\"name\":\"空间-M8Z77\",\"localId\":\"45343555\",\"localName\":\"12.11.43413.\",\"classCode\":\"DomesticWaterSupplyZone\",\"groupCode\":\"QKZZ\",\"infos\":{\"floorId\":\"Fl1209010203008c60dd3fcf45d5bc361d46989f1dab\",\"zoneType\":\"DomesticWaterSupplyZone\",\"buildingId\":\"Bd120901020324de2bf7c9b4442d907c6f5400945894\",\"height\":1.0},\"createTime\":1634983298000,\"objectType\":\"space\"}]";
		readTree = objectMapper.readTree(temp);
		ArrayNode arrayNode = (ArrayNode)readTree;
		List<AdmSpace> list = toEntity(arrayNode, AdmSpace.class, CollUtil.newHashSet("infos"));
		System.out.println(list.get(0).getBuildingId());
	}
	
	/**
	 * json转换为Clazz，为扩展属性赋值，目前扩展字段属性value，仅支持object，不支持array
	 * 假若最外层node已经存在对应属性，将不再赋值
	 * 
	 * @param <T>
	 * @param outerNode
	 * @param clazz
	 * @param extraColumns
	 * @param excludeColumns
	 * @return
	 * @throws JsonParseException
	 * @throws JsonMappingException
	 * @throws IOException
	 */
    public static <T> T toEntity(ObjectNode outerNode, Class<T> clazz, Set<String> extraColumns, Set<String> excludeColumns) throws JsonParseException, JsonMappingException, IOException {
        // 检查clazz包含的属性
        Map<String, Field> fieldMap = getFieldMap(clazz);
        Set<String> clazzField = fieldMap.keySet();
        // 转换node
        for (String extraColumn : extraColumns) {
        	collectExtras(outerNode, null, clazzField, extraColumn);
        	if (CollectionUtil.isNotEmpty(excludeColumns)) {
        		for (String excludeColumn : excludeColumns) {
            		outerNode.remove(excludeColumn);
    			}
			}
		}
        // 转换为对象List
        try {
            return objectMapper.readValue(outerNode.toString(), clazz);
        } catch (IOException e) {
            throw new BusinessException(ResponseCode.A0427.getCode(), ResponseCode.A0427.getDesc());
        }
    }
    
    /**
	 * json转换为Clazz，为扩展属性赋值，目前扩展字段属性value，仅支持object，不支持array
	 * 假若最外层node已经存在对应属性，将不再赋值
     * 
     * @param <T>
     * @param array
     * @param clazz
     * @param extraColumn
     * @return
     * @throws JsonParseException
     * @throws JsonMappingException
     * @throws IOException
     */
    public static <T> List<T> toEntity(ArrayNode array, Class<T> clazz, String extraColumn) throws JsonParseException, JsonMappingException, IOException {
        return toEntity(array, clazz, CollUtil.newHashSet(extraColumn));
    }
    
	/**
	 * json转换为Clazz，为扩展属性赋值，目前扩展字段属性value，仅支持object嵌套，不支持array嵌套
	 * 假若最外层node已经存在对应属性，将不再赋值
	 * 
	 * @param <T>
	 * @param array
	 * @param clazz
	 * @param extraColumns
	 * @return
	 * @throws JsonParseException
	 * @throws JsonMappingException
	 * @throws IOException
	 */
    public static <T> List<T> toEntity(ArrayNode array, Class<T> clazz, Set<String> extraColumns) throws JsonParseException, JsonMappingException, IOException {
        // 检查clazz包含的属性
        Map<String, Field> fieldMap = getFieldMap(clazz);
        Set<String> clazzField = fieldMap.keySet();
        // 转换node
        for(int i = 0;i < array.size();i++) {
            ObjectNode outerNode = (ObjectNode) array.get(i);
            for (String extraColumn : extraColumns) {
            	collectExtras(outerNode, null, clazzField, extraColumn);
			}
        }
        // 转换为对象List
        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());
        }
    }
	
	/**
	 * json转换为Clazz，为扩展属性赋值，目前扩展字段属性value，仅支持object，不支持array
	 * 假若最外层node已经存在对应属性，将不再赋值
	 * 
	 * @param outerNode
	 * @param innerNode
	 * @param clazzField
	 * @param extraColumn
	 * @throws JsonParseException
	 * @throws JsonMappingException
	 * @throws IOException
	 */
    public static void collectExtras(ObjectNode outerNode, ObjectNode innerNode, Set<String> clazzField, String extraColumn) throws JsonParseException, JsonMappingException, IOException {
    	if (innerNode == null && outerNode.has(extraColumn)) {
    		String extraValue = outerNode.get(extraColumn).toString();
    		if (StrUtil.isBlank(extraValue) || !extraValue.startsWith("{")) {
    			return;
    		}
		}
    	
    	if (innerNode == null || !outerNode.has(extraColumn)) {
    		innerNode = innerNode == null ? outerNode : innerNode;
    		if (innerNode.has(extraColumn)) {
    			String extraValue = innerNode.get(extraColumn).toString();
        		if (StrUtil.isNotBlank(extraValue) && extraValue.startsWith("{")) {
    				ObjectNode readValue = objectMapper.readValue(extraValue, ObjectNode.class);
    				if (readValue != null) {
    					Iterator<String> fieldNames = readValue.fieldNames();
    					while (fieldNames.hasNext()) {
    						String extraKey = (String) fieldNames.next();
    						collectExtras(outerNode, readValue, clazzField, extraKey);
    					}
    				}
    			} else if (clazzField.contains(extraColumn)) {
    				outerNode.putPOJO(extraColumn, innerNode.get(extraColumn));
				}
			}
		}
    	
    }
    
    /***
     * 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;
        });
    }

}
