package com.ag.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * Created by yangxh on 2020/12/2.
 */
public class WbStoreJson {
    private Boolean success;
    private Integer total;
    private JSONObject metaData = new JSONObject();
    private JSONArray rows = new JSONArray();
    private final String FIELDS = "fields";

    public WbStoreJson(){
        setSuccess(true);
        JSONArray fields = new JSONArray();
        getMetaData().put(FIELDS, fields);
    }

    public String getJsonStr(WbStoreJson json){
        return JSON.toJSONString(json, SerializerFeature.WriteNullStringAsEmpty);
    }


    public void generate(List<Map<String, Object>> list){
        if (list == null){
            list = new ArrayList<>();
        }
        setTotal(list.size());
    }

    /**
     * 1.取出class所有的属性，构建fields中的name和type
     * 2."get"+属性首字符大写获取list中对象的值，row属性为key，value=对象的值
     * 3.遍历fields和rows，
     *   fields->key="name" value（驼峰命名法）转为全小写+下划线格式
     *   rows->新建array，新key替换旧key，新array赋值给rows
     * @param list
     * @param clz
     */
    public void generate(List list, Class clz){
        if (list == null){
            list = new ArrayList();
        }
        setTotal(list.size());

        Map<String, Class> classMap = getColNameOrClass(clz);
        for (Map.Entry<String, Class> entry : classMap.entrySet()) {
            JSONObject json = new JSONObject();
            json.put("name", entry.getKey());
            json.put("type", getColType(entry.getValue()));
            getFields().add(json);
        }
        for (Object data : list) {
            JSONObject json = new JSONObject();
            getRows().add(json);
            for (Map.Entry<String, Class> entry : classMap.entrySet()) {
                String key = entry.getKey();
                if (StrUtil.equalsIgnoreCase(key, "serialVersionUID")){
                    continue;
                }
                Object val = getValueByMethodStr(data, key);
                json.put(key, val);
            }
        }

        for (int i=0; i<getFields().size(); i++){
            JSONObject json = getFields().getJSONObject(i);
            String oldVal = json.getString("name");
            String newVal = StrUtil.toUpperCol(oldVal);
            json.put("name", newVal);
        }

        JSONArray rows = new JSONArray();
        for (int i=0; i<getRows().size(); i++){
            JSONObject json = getRows().getJSONObject(i);
            JSONObject target = new JSONObject();
            rows.add(target);
            for (Map.Entry<String, Object> entry : json.entrySet()){
                String oldKey = entry.getKey();
                Object oldVal = entry.getValue();
                //驼峰命名法转为全小写+下划线格式
                String newKey = StrUtil.toUpperCol(oldKey);
                target.put(newKey, oldVal);
            }
        }
        setRows(rows);

    }



    /*private void replaceArray(JSONArray source, JSONArray target){
        for (int i=0; i<source.size(); i++){
            JSONObject oldJson = source.getJSONObject(i);
            JSONObject newJson = new JSONObject();
            target.add(newJson);
            for (Map.Entry<String, Object> entry : oldJson.entrySet()){
                String oldKey = entry.getKey();
                Object oldVal = entry.getValue();
                //驼峰命名法转为全小写+下划线格式
                String newKey = toLower(oldKey).toUpperCase();
                newJson.put(newKey, oldVal);
            }
        }
    }*/

    public Boolean getSuccess() {
        return success;
    }

    public void setSuccess(Boolean success) {
        this.success = success;
    }

    public Integer getTotal() {
        return total;
    }

    public void setTotal(Integer total) {
        this.total = total;
    }

    public JSONObject getMetaData() {
        return metaData;
    }

    public void setMetaData(JSONObject metaData) {
        this.metaData = metaData;
    }

    public JSONArray getRows() {
        return rows;
    }

    public void setRows(JSONArray rows) {
        this.rows = rows;
    }


    /**
     * 获取对象的所有属性值
     */
    private Map<String, Class> getColNameOrClass(Class clazz) {
        //map=列名：类型
        Map<String, Class> map = new HashMap<>();
        try {
            //根据Class对象获得属性 私有的也可以获得
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                /*//首字符小写
                String colName = firstToLower(field.getName());
                //驼峰命名法转为全小写+下划线格式
                colName = toLower(colName).toUpperCase();*/
                String colName = field.getName();
                map.put(colName, field.getType());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    private String getColType(Class value) {
        if (String.class.isAssignableFrom(value)){
            return "string";
        }
        if (Number.class.isAssignableFrom(value)){
            return "number";
        }
        if (Date.class.isAssignableFrom(value)){
            return "timestamp";
        }
        return "string";
    }

    private Object getValueByMethodStr(Object o, String colName) {
        try {
            String firstLetter = colName.substring(0, 1).toUpperCase();
            String getter = StrUtil.join("get", firstLetter, colName.substring(1));
            Method method = ReflectionUtils.findMethod(o.getClass(), getter);
            return ReflectionUtils.invokeMethod(method, o);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    private JSONArray getFields() {
        return getMetaData().getJSONArray(FIELDS);
    }

    public static class RedisJsonStr{
        private String id;
        private String cname;
        private String ename;
        private String wname;
        private String tenancyId;
        private String keyName;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getCname() {
            return cname;
        }

        public void setCname(String cname) {
            this.cname = cname;
        }

        public String getEname() {
            return ename;
        }

        public void setEname(String ename) {
            this.ename = ename;
        }

        public String getWname() {
            return wname;
        }

        public void setWname(String wname) {
            this.wname = wname;
        }

        public String getTenancyId() {
            return tenancyId;
        }

        public void setTenancyId(String tenancyId) {
            this.tenancyId = tenancyId;
        }

        public String getKeyName() {
            return keyName;
        }

        public void setKeyName(String keyName) {
            this.keyName = keyName;
        }
    }

}
