package com.ag.redis;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.ag.base.IRedisService;
import com.ag.util.ResourceUtil;
import com.ag.util.StrUtil;
import com.ag.util.UniqueObjectList;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wb.common.KvBean;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;
import java.util.stream.Collectors;

/**
 * redis管理开放工具类
 * 逻辑处理在本类处理
 * Created by yangxh on 2021/3/18.
 */
@Service
public class RedisServiceImpl implements IRedisService {

    private Logger logger = Logger.getLogger(RedisServiceImpl.class);
    private final String TENANCY_ID = "default";
    private static String redisPrefix = "";

    static {
        ResourceBundle resource = ResourceUtil.getResourceBundle("system");
        if (resource.containsKey("redisPrefix")){
            redisPrefix = resource.getString("redisPrefix");
        }
        redisPrefix = StrUtil.join(redisPrefix, ".sys.");
    }

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private CodeSetTemplate codeSetTemplate;

    private String joinKey(String key){
        return StrUtil.join(redisPrefix, "_", key);
    }

    private String getTenancyId(String tenancyId){
        if (StrUtil.isEmpty(tenancyId)){
            tenancyId = TENANCY_ID;
        }
        return tenancyId;
    }

    /**
     * 缓存key规则：项目_租户_keyName
     * 租户为空表示通用租户。
     * 其他租户不等于默认租户，返回数据=租户数据+默认租户数据
     */
    @Override
    public void redisLoad() {
        List<KvBean> kvBeans = codeSetTemplate.getKvBean();
        //查询继承默认租户数据的表名
        List<String> defaultTabs = codeSetTemplate.getDefaultTabNames();
        //空租户的所有数据
        List<KvBean> emptyTenancyBeans = CollectionUtil.newArrayList();
        Iterator<KvBean> iter = kvBeans.iterator();
        while (iter.hasNext()){
            KvBean kvBean = iter.next();
            if (StrUtil.isEmpty(kvBean.getTenancyId())){
                emptyTenancyBeans.add(kvBean);
                iter.remove();
            }
        }
        //空租户的数据分组
        Map<String, List<KvBean>> emptyTenancyTabNames =
                emptyTenancyBeans.stream().collect(Collectors.groupingBy(KvBean::getKeyName));
        //空租户的数据存储
        for (Map.Entry<String, List<KvBean>> entry : emptyTenancyTabNames.entrySet()){
            JSONArray array = kvBeanToArray(entry.getValue());
            redisUtil.set(joinKey(entry.getKey()), array);
        }

        //kvBeans只含有租户的数据
        Map<String, List<KvBean>> tabNames =
                kvBeans.stream().collect(Collectors.groupingBy(x->x.getTenancyId()+"_"+x.getKeyName()));
        //存储默认(集团)租户的数据
        Map<String, List<KvBean>> defaultMap = new HashMap<>();
        for (String defaultTab : defaultTabs){
            String defaultKey = TENANCY_ID + "_" + defaultTab;
            for (Map.Entry<String, List<KvBean>> entry : tabNames.entrySet()){
                if (ObjectUtil.equal(defaultKey, entry.getKey())){
                    defaultMap.put(defaultKey, entry.getValue());
                    break;
                }
            }
        }
        for (Map.Entry<String, List<KvBean>> entry : tabNames.entrySet()){
            String defaultKey = TENANCY_ID + "_" + entry.getKey().substring(entry.getKey().indexOf("_") + 1);
            if (defaultMap.containsKey(defaultKey)){
                //其他租户加入默认租户数据
                List<KvBean> targets = new UniqueObjectList<>();
                targets.addAll(entry.getValue());
                targets.addAll(defaultMap.get(defaultKey));
                tabNames.put(entry.getKey(), targets);
            }
        }

        logger.info("++++++++++++++++ Redis ready ++++++++++++++++");
        logger.info("             _._ \n" +
                "           _.-``__ ''-._\n" +
                "      _.-``    `.  `_.  ''-._\n" +
                "  .-`` .-```.  ```\\/    _.,_ ''-._\n" +
                " (    '      ,       .-`  | `,    )\n" +
                " |`-._`-...-` __...-.``-._|'` _.-'|\n" +
                " |    `-._   `._    /     _.-'    |\n" +
                "  `-._    `-._  `-./  _.-'    _.-' \n" +
                " |`-._`-._    `-.__.-'    _.-'_.-'|\n" +
                " |    `-._`-._        _.-'_.-'    |\n" +
                "  `-._    `-._`-.__.-'_.-'    _.-' \n"  +
                " |`-._`-._    `-.__.-'    _.-'_.-'|\n" +
                " |    `-._`-._        _.-'_.-'    |\n" +
                "  `-._    `-._`-.__.-'_.-'    _.-' \n" +
                "      `-._    `-.__.-'    _.-'\n" +
                "          `-._        _.-'\n" +
                "              `-.__.-'\n");
        for (Map.Entry<String, List<KvBean>> entry : tabNames.entrySet()){
            JSONArray array = kvBeanToArray(entry.getValue());
            redisUtil.set(joinKey(entry.getKey()), array);
        }
        logger.info("++++++++++++++++ Redis load success ++++++++++++++++");

    }


    /**
     * 按表名重新加载
     * @param dictName
     */
    @Override
    public void refreshByDictName(String dictName) {
        List<KvBean> kvBeans = codeSetTemplate.getKvBeanByTableName(dictName);
        //Assert.notNull(kvBeans, "刷新redis遇到非法的请求参数："+dictName);
        Assert.notEmpty(kvBeans, "查询结果数据为空，请检查："+dictName);
        boolean isDefault = false;
        if (!StrUtil.isEmpty(kvBeans.get(0).getTenancyId())) {
            isDefault = codeSetTemplate.isContainsDefault(dictName);
        }
        //kvBeans.forEach(x->{if(StrUtil.isEmpty(x.getTenancyId())){x.setTenancyId(TENANCY_ID);}});
        Map<String, List<KvBean>> tabMaps = new HashMap<>();
        Map<String, List<KvBean>> emptyTenancyMaps = new HashMap<>();
        if (StrUtil.isEmpty(kvBeans.get(0).getTenancyId())){
            emptyTenancyMaps = kvBeans.stream().collect(Collectors.groupingBy(KvBean::getKeyName));
        }else {
            //按租户+名称分组
            tabMaps = kvBeans.stream().collect(Collectors.groupingBy(x -> x.getTenancyId() + "_" + x.getKeyName()));
        }
        logger.info(" Redis reload ++++++++++++++++ " + dictName);
        //如果使用集团租户并且租户数量大于0
        //获取默认租户
        if (isDefault && tabMaps.size() > 0) {
            String defaultKey = TENANCY_ID + "_" + dictName;
            List<KvBean> defaultList = tabMaps.get(defaultKey);
            for (Map.Entry<String, List<KvBean>> entry : tabMaps.entrySet()) {
                if (ObjectUtil.notEqual(entry.getKey(), defaultKey)){
                    //自定义租户加入默认租户数据
                    List<KvBean> targets = new UniqueObjectList<>();
                    targets.addAll(entry.getValue());
                    targets.addAll(defaultList);
                    tabMaps.put(entry.getKey(), targets);
                }
            }
        }
        for (Map.Entry<String, List<KvBean>> entry : tabMaps.entrySet()) {
            JSONArray array = kvBeanToArray(entry.getValue());
            redisUtil.set(joinKey(entry.getKey()), array);
        }
        for (Map.Entry<String, List<KvBean>> entry : emptyTenancyMaps.entrySet()) {
            JSONArray array = kvBeanToArray(entry.getValue());
            redisUtil.set(joinKey(entry.getKey()), array);
        }
        logger.info(" Redis load success ++++++++++++++++ " + dictName);
    }

    /**
     * 获取表名所有key/value
     * @param dictName
     * @return
     */
    @Override
    public List<KvBean> getAllByKey(String dictName) {
        return getAllByKey(dictName, null);
    }

    @Override
    public List<KvBean> getAllByKey(String dictName, String tenancyId) {
        String result;
        if (redisUtil.hasKey(joinKey(dictName))){
            result = Convert.toStr(redisUtil.get(joinKey(dictName)));
        }else {
            result = Convert.toStr(redisUtil.get(joinKey(getTenancyId(tenancyId)+"_"+dictName)));
        }
        return strToKvBean(dictName, result);
    }


    /**
     * 分页+模糊查询（不指定分页按20条数据返回，支持null）
     * @param dictName
     * @param key
     * @return
     */
    @Override
    public List<KvBean> likeByKey(String dictName, String key){
        return likeByKey(dictName, key, null);
    }
    @Override
    public List<KvBean> likeByKey(String dictName, String key, String tenancyId){
        return likeByKey(dictName, key, tenancyId, 0, 20);
    }
    @Override
    public List<KvBean> likeByKey(String dictName, String key, Integer begIndex, Integer length){
        return likeByKey(dictName, key, null, begIndex, length);
    }
    @Override
    public List<KvBean> likeByKey(String dictName, String key, String tenancyId, Integer begIndex, Integer length) {
        if (StrUtil.isEmpty(key)){
            key = "";
        }
        String result;
        if (redisUtil.hasKey(joinKey(dictName))){
            result = Convert.toStr(redisUtil.like(joinKey(dictName), key, begIndex, length));
        }else {
            result = Convert.toStr(redisUtil.like(joinKey(getTenancyId(tenancyId) + "_" + dictName), key, begIndex, length));
        }
        return strToKvBean(dictName, result);
    }



    @Override
    public String getTargetName(String dictName, String key) {
        return getTargetName(dictName, key, null);
    }

    @Override
    public List<KvBean> findByMultKeys(String dictName, String keys) {
        return findByMultKeys(dictName, keys, null);
    }

    @Override
    public String getTargetName(String dictName, String key, String tenancyId) {
        List<KvBean> kvBeans = findByMultKeys(dictName, key, tenancyId);
        if (CollectionUtil.isEmpty(kvBeans)){
            return null;
        }
        return kvBeans.get(0).getV();
    }


    @Override
    public List<KvBean> findByMultKeys(String dictName, String keys, String tenancyId) {
        String result;
        if (redisUtil.hasKey(joinKey(dictName))){
            result = Convert.toStr(redisUtil.accurateKey(joinKey(dictName), keys));
        }else {
            result = Convert.toStr(redisUtil.accurateKey(joinKey(getTenancyId(tenancyId)+"_"+dictName), keys));
        }
        return strToKvBean(dictName, result);
    }


    @Override
    public void putCustomizeKey(String key, String obj) {
        redisUtil.set(key, obj);
    }
    @Override
    public String getCustomizeKey(String key) {
        String str = Convert.toStr(redisUtil.get(key));
        if (str == null){
            str = "{}";
        }
        return str.replace("\\\"", "\"");
    }

    @Override
    public void delKey(String key){
        redisUtil.delete(key);
    }












    private List<KvBean> strToKvBean(String dictName, String result){
        if (ObjectUtil.equal(result, "{}") || StrUtil.isEmpty(result)){
            return CollUtil.list(false);
        }
        JSONArray array = JSON.parseArray(result);
        List<KvBean> kvBeans = new ArrayList<>(array.size());
        for (int i=0; i<array.size(); i++){
            KvBean kvBean = new KvBean();
            kvBean.setKeyName(dictName);
            kvBean.setK(array.getJSONObject(i).getString("K"));
            kvBean.setV(array.getJSONObject(i).getString("V"));
            kvBean.setComv(array.getJSONObject(i).getString("COMV"));
            kvBean.setComv2(array.getJSONObject(i).getString("COMV2"));
            kvBeans.add(kvBean);
        }
        return kvBeans;
    }

    private JSONArray kvBeanToArray(List<KvBean> kvBeans){
        JSONArray array = new JSONArray(kvBeans.size());
        for (KvBean val : kvBeans){
            JSONObject map = new JSONObject();
            map.put("K", val.getK());
            map.put("V", val.getV());
            map.put("COMV", val.getComv());
            map.put("COMV2", val.getComv2());
            array.add(map);
        }
        return array;
    }
}
