package com.sonic.common.utils;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.MapFunction;

/**
 * Helper类方便从集合或者bean对象过滤属性和聚合数据
 * 支持指定jsonpath去聚合数目. 通常使用在BFF的controller层.
 * https://github.com/json-path/JsonPath
 * @author code
 */
public class DataAssembleHelper {

    /**
     * 一个Immutable的jsonarray, 防止内容被修改
     */
    private final static JSONArray EMPTY_JSON_ARRAY = new JSONArray(Collections.emptyList());

    /**
     * 给定一个对象集合, 过滤集合中每个对象的属性.
     * @param data 对象集合
     * @param includeFields 仅仅包含的属性名称
     * @return 过滤了对象属性的集合
     */
    public static JSONArray filterCollection(Collection data, Set<String> includeFields) {
        if (data == null || data.isEmpty()) {
            return EMPTY_JSON_ARRAY;
        }

        JSONArray jsonList = (JSONArray)JSONObject.toJSON(data);
        List collect = IntStream.range(0, jsonList.size()).mapToObj(i -> jsonList.getJSONObject(i))
                .map(e -> {
                    return new JSONObject(Maps.filterEntries(e, entry -> includeFields.contains(entry.getKey())));
                }).collect(Collectors.toList());
        return new JSONArray(collect);
    }

    /**
     * 过滤指定bean对象的
     * @param bean
     * @param includeFields
     * @return jsonobject, 内容是过滤后的bean对象的属性和属性值.
     */
    public static JSONObject filterBean(Object bean, Set<String> includeFields) {
        Preconditions.checkArgument(!(bean instanceof Collection));

        if (bean == null) {
            return null;
        }

        JSONObject json = (JSONObject)JSONObject.toJSON(bean);
        return new JSONObject(Maps.filterEntries(json, entry -> includeFields.contains(entry.getKey())));
    }

    /**
     * 对bean对象, 根据指定jsonpath中的节点, 替换成mapper中返回的值
     * @param jsonPath 节点路径. 参看 https://github.com/json-path/JsonPath
     * @param bean
     * @param mapper
     * @return 内容是替换后的bean对象的属性和属性值.
     */
    public static JSONObject mapBean(String jsonPath, Object bean, Function<Object, Object> mapper) {
        Preconditions.checkArgument(!(bean instanceof Collection));

        if (bean == null) {
            return null;
        }

        JSONObject json = (JSONObject)JSONObject.toJSON(bean);
        MapFunction f = (target, conf) -> {
          return mapper.apply(target);
        };
        return JsonPath.compile(jsonPath).map(json, f, Configuration.defaultConfiguration());
    }

    /**
     * 对bean对象集合, 根据指定jsonpath中的节点, 替换成mapper中返回的值
     * @param jsonPath 节点路径. 参看 https://github.com/json-path/JsonPath
     * @param beans
     * @param mapper
     * @return 内容是替换后的集合列表.
     */
    public static JSONArray mapBeans(String jsonPath, Collection beans, Function<Object, Object> mapper) {
        if (beans == null || beans.isEmpty()) {
            return EMPTY_JSON_ARRAY;
        }

        JSONArray json = (JSONArray)JSONObject.toJSON(beans);
        MapFunction f = (target, conf) -> {
          return mapper.apply(target);
        };
        return JsonPath.compile(jsonPath).map(json, f, Configuration.defaultConfiguration());
    }
}
