package com.gyee.generation.util.redis;

import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisConnectionUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service("redisService")
public class RedisServiceImpl implements RedisService {
    @Resource
    private RedisTemplate<String, ?> redisTemplate;

    @Override
    public boolean set(final String key, final String value) {;


        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
                connection.set(serializer.serialize(key), serializer.serialize(value));
                return true;
            }
        });
        return result;
    }


    @Override
    public String get(final String key) {

        String result = redisTemplate.execute(new RedisCallback<String>() {
            @Override
            public String doInRedis(RedisConnection connection) throws DataAccessException {
                RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
                byte[] value = connection.get(serializer.serialize(key));
                return serializer.deserialize(value);
            }
        });
        return result;
    }



    @Override
    public boolean expire(final String key, long expire) {


        return redisTemplate.expire(key, expire, TimeUnit.SECONDS);
    }

    @Override
    public boolean remove(final String key) {

        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
                connection.del(key.getBytes());
                return true;
            }
        });
        return result;
    }

    @Override
    public boolean hasKey(final String key) {

        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    @Override
    public boolean hasKey(String key,String value){

        try {
            return redisTemplate.opsForHash().hasKey(key,value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    @Override
    public void setObject(Object obj) {
        Field[] fields = obj.getClass().getDeclaredFields();
        for(int i = 0 , len = fields.length; i < len; i++) {
            // 对于每个属性，获取属性名
            String varName = fields[i].getName();
            try {
                // 获取原来的访问控制权限
                boolean accessFlag = fields[i].isAccessible();
                // 修改访问控制权限
                fields[i].setAccessible(true);
                // 获取在对象f中属性fields[i]对应的对象中的变量
                Object o;
                try {
                    o = fields[i].get(obj);
                    if (o!=null){
                        set(varName, String.valueOf(o));
                    }else {
                        set(varName,"");
                    }

                    //System.err.println("传入的对象中包含一个如下的变量：" + varName + " = " + o);
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                // 恢复访问控制权限
                fields[i].setAccessible(accessFlag);
            } catch (IllegalArgumentException ex) {
                ex.printStackTrace();
            }
        }

    }

    public void select(Integer dbIndex) {

        if (dbIndex == null || dbIndex > 15 || dbIndex < 0) {
            dbIndex = 0;
        }
        LettuceConnectionFactory jedisConnectionFactory = (LettuceConnectionFactory) redisTemplate
                .getConnectionFactory();
        jedisConnectionFactory.setDatabase(dbIndex);
        redisTemplate.setConnectionFactory(jedisConnectionFactory);
        jedisConnectionFactory.afterPropertiesSet();
        jedisConnectionFactory.resetConnection();

    }


    public Set<String> keys(Integer dbIndex) {
        select(dbIndex);
        return redisTemplate.keys("*");

    }


    public Object getHashObj(final String key,String value) {


        Object result = redisTemplate.opsForHash().get(key,value);
        return result;
    }

    public Map<Object,Object> getHashEntries(final String key) {


        Map<Object,Object> result = redisTemplate.opsForHash().entries(key);
        return result;
    }

    public void putHashAllObj(final String key,final Map<String,Object> value)
    {

        redisTemplate.opsForHash().putAll(key,value);
    }

    public void putHashAllPipeObj(final Map<String,Map<String,Object> >map)
    {
        RedisSerializer keySerializer = redisTemplate.getHashKeySerializer();
        RedisSerializer valueSerializer = redisTemplate.getHashValueSerializer();
        redisTemplate.executePipelined((RedisCallback) connection -> {
            map.forEach((k, v) -> {
                Map<byte[], byte[]> byteMap =new HashMap<>();
                v.forEach((k2, v2) -> {
                    byteMap.put(valueSerializer.serialize(k2),valueSerializer.serialize(v2));
                });

                connection.hMSet(keySerializer.serialize( k), byteMap);
            });
            return null;
        });
    }

    /**
     * 批量取hash数据
     *
     * @param hashKeys
     * @return
     */
    public List<Object> hashGetBatch(List<String> hashKeys) {

        List list = redisTemplate.executePipelined(new RedisCallback<String>() {
            @Override
            public String doInRedis(RedisConnection connection) throws DataAccessException {
                for (String hashKey : hashKeys) {
                    Map<byte[], byte[]> map= connection.hGetAll(hashKey.getBytes());
                }
                return null;
            }
        });
        return list;
    }

    public Map<String,Map<String,String>> hgetall(Map<Integer,List<String>> pointmap) {

        Map<String,Map<String,String> >map=new LinkedHashMap<>();

        for(Map.Entry<Integer,List<String>> entry:pointmap.entrySet()){


            select(entry.getKey());

            redisTemplate.execute((RedisCallback<Map<String,Map<String,String>>>) con -> {



                for(String key:entry.getValue())
                {
                    Map<byte[], byte[]> result = con.hGetAll(key.getBytes());
                    if (result.isEmpty()) {
                        return new HashMap<>(0);
                    }

                    Map<String, String> ans = new HashMap<>(result.size());
                    for (Map.Entry<byte[], byte[]> entry2 : result.entrySet()) {
                        ans.put(new String(entry2.getKey()), new String(entry2.getValue()));
                    }
                    map.put(key,ans);
                }



                return map;
            });


        };

        return map;
    }

    public void unbindConnection() {


        RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
    }
}
