package com.persagy.proxy.object.service.impl;

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 com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.databind.JavaType;
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.constant.ResponseCode;
import com.persagy.dmp.common.exception.BusinessException;
import com.persagy.dmp.common.helper.SpringHelper;
import com.persagy.proxy.object.model.AdmFloor;

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

public class TestServiceImpl {
    public static void main(String[] args) throws IOException {
        String str = "[{\"id\":\"Fl5001120003a1a40359bf5b48aaabfbcec525d242b9\",\"valid\":1,\"creationTime\":1635924326000,\"creator\":\"0\",\"modifiedTime\":1635924326000,\"modifier\":\"0\",\"projectId\":\"Pj5001120003\",\"name\":\"楼层-W11ZX\",\"localId\":\"F1\",\"localName\":\"F1\",\"objType\":\"floor\",\"classCode\":\"floor\",\"groupCode\":\"XG\",\"infos\":{\"modelId\":\"1\",\"floorLocateType\":\"99\",\"dataSync\":\"1\",\"floorElevation\":1,\"floorType\":\"99\",\"netHeight\":1,\"floorMapShift\":\"1\",\"outline\":\"[{\\\"x\\\":363.1741071428571,\\\"y\\\":224.99107142857144},{\\\"x\\\":524.6026785714284,\\\"y\\\":232.05357142857144}]\",\"floorMapRatio\":1,\"permanentPeopleNum\":1,\"leaseArea\":1,\"height\":1,\"area\":1,\"bimLocation\":\"1\",\"floorMap\":\"1\",\"modelFile\":\"1\",\"floorSequenceID\":1,\"count\":\"1\",\"buildingId\":\"Bd500112000336f7fd4998fc4cb393ff3b3d44eee1b2\",\"floorFuncType\":\"1\",\"bimIdPre\":\"1\",\"practicalArea\":1,\"properties\":\"1\"}}]";
        ObjectMapper objectMapper = new ObjectMapper();
        ArrayNode arrayNode = objectMapper.readValue(str, ArrayNode.class);
        List<AdmFloor> admFloors = toEntity(arrayNode, AdmFloor.class, "infos");
    }

    /**
     * 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 = new ObjectMapper();
        try {
            JavaType javaType = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, clazz);
            //return objectMapper.readValue(array.toString(), javaType);
            return objectMapper.readValue(objectMapper.writeValueAsString(array), 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();
        }
    }

}
