package cn.com.countrygarden.bi.main.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.context.annotation.PropertySource;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.function.Function;

@PropertySource("classpath:/application.properties")
public class RedisCacheUtils {

    private static String runtimeEnvironment;
    private static String preffix;


    /**
     * 模拟 Laravel 优雅的 Cache 方法：Cache::remember
     *
     * @param key      redis key
     * @param ttl      存活时间，单位，秒
     * @param param    传入 lambda 的参数
     * @param function lambda callback
     * @return
     */
    public static Map<String, Object> rememberMap(
            String key,
            int ttl,
            Map<String, String> param,
            Function<Map<String, String>,
                    Map<String, Object>> function
    ) {
        String data;
        Map<String, Object> map;

        String preffix = getRuneTimeEnvironment();
        if (preffix != null && preffix.equals("dev")) {
            key = preffix.concat(":" + key);
        }
        StringBuffer sb = new StringBuffer(key);
        sb.append(paramToKey(param));

        data = RedisUtils.get(sb.toString());
        if (data == null || data.equals(null) || data.equals("")) {
            map = function.apply(param);
            if (!map.isEmpty()) {
                RedisUtils.put(sb.toString(), JSON.toJSONString(map), ttl);
            }
        } else {
            map = JSON.parseObject(data, new TypeReference<Map<String, Object>>() {
            });
        }

        return map;
    }

    public static void removeCacheByKey(String key, Map<String, String> param){
        String preffix = getRuneTimeEnvironment();
        if (preffix != null && preffix.equals("dev")) {
            key = preffix.concat(":" + key);
        }
        StringBuffer sb = new StringBuffer(key);
        sb.append(paramToKey(param));
        RedisUtils.del(sb.toString());

    }

    public static String paramToKey(Map<String, String> param){
        if(param==null || param.size()==0){
            return "";
        }
        StringBuffer sb = new StringBuffer(":pa:");
        for(Map.Entry<String,String> entry : param.entrySet()){
            sb.append(entry.getKey());
            sb.append(":");
            sb.append(entry.getValue());
        }
        return  sb.toString();
    }

    /**
     * 模拟 Laravel 优雅的 Cache 方法：Cache::remember
     *
     * @param key      redis key
     * @param ttl      存活时间，单位，秒
     * @param param    传入 lambda 的参数
     * @param function lambda callback
     * @return
     */
    public static List<Map<String, String>> rememberList(
            String key,
            int ttl,
            Map<String, String> param,
            Function<Map<String, String>,
                    List<Map<String, String>>> function
    ) {
        String data;
        List<Map<String, String>> list;

        String preffix = getRuneTimeEnvironment();
        if (preffix != null && preffix.equals("dev")) {
            key = preffix.concat(":" + key);
        }
        StringBuffer sb = new StringBuffer(key);
        sb.append(paramToKey(param));
        data = RedisUtils.get(sb.toString());
        if (data == null || data.equals(null) || data.equals("")) {
            list = function.apply(param);
            if (!list.isEmpty()) {
                RedisUtils.put(sb.toString(), JSON.toJSONString(list), ttl);
            }
        } else {
            list = JSON.parseObject(data, new TypeReference<List<Map<String, String>>>() {
            });
        }

        return list;
    }

    public static<T> List<T> remeberList(String key,int ttl, Map<String, String> param,Class<T> clazz,
                                         Function<Map<String, String>,List<T>> function){
        String data;
        String preffix = getRuneTimeEnvironment();
        if (preffix != null && preffix.equals("dev")) {
            key = preffix.concat(":" + key);
        }
        StringBuffer sb = new StringBuffer(key);
        sb.append(paramToKey(param));
        data = RedisUtils.get(sb.toString());
        if(StringUtils.isEmpty(data)){
            List<T> result = function.apply(param);
            if(result!=null){
                RedisUtils.put(sb.toString(), JSON.toJSONString(result), ttl);
            }
            return result;
        } else {

            List<T> result = JSON.parseArray(data,clazz);
            return result;
        }
    }

    public static<T> Object remeber(String key,int ttl, Map<String, String> param,Class<T> clazz,
                                    Function<Map<String, String>,T> function){
        String data;
        String preffix = getRuneTimeEnvironment();
        if (preffix != null && preffix.equals("dev")) {
            key = preffix.concat(":" + key);
        }
        StringBuffer sb = new StringBuffer(key);
        sb.append(paramToKey(param));
        data = RedisUtils.get(sb.toString());
        if(StringUtils.isEmpty(data)){
            T result = function.apply(param);
            if(result!=null){
                RedisUtils.put(sb.toString(), JSON.toJSONString(result), ttl);
            }
            return result;
        } else {

            Object result = JSON.parseObject(data,clazz);
            return result;
        }
    }

    public static String getRuneTimeEnvironment() {
        if (runtimeEnvironment != null && !runtimeEnvironment.equals("")) {
            return runtimeEnvironment;
        }
        Properties prop = new Properties();

        try {
            InputStream inputStream = RedisCacheUtils.class.getClassLoader().getResourceAsStream("application.properties");

            prop.load(inputStream);

            runtimeEnvironment = prop.getProperty("runtime.redis.prefix");
        } catch (IOException e) {
            e.printStackTrace();
        }

        return runtimeEnvironment;
    }
}
