package com.wecloud.im.ws.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author hewei123@163.com
 * @Description redis 通用工具类
 * @createTime 2020年04月14日 16:07:00
 */
@Slf4j
@Component
public class RedisUtils {

    @Autowired
    private StringRedisTemplate redisTemplate;

    public final static String SPLIT = ":";


    public StringRedisTemplate redisTemplate() {
        return redisTemplate;
    }


    /**
     * 添加Key:value
     *
     * @param key
     * @param value
     * @param timeout 超时
     */
    public void addKey(String key, String value, Duration timeout) {
        redisTemplate.opsForValue().set(key, value, timeout);
    }


    /**
     * 递增
     *
     * @param key 键
     * @delta 要增加几(大于0)
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 删除Key
     *
     * @param key 如果传入hash类型的key，则把整个hash中所有field删除
     */
    public boolean delKey(String key) {
        return redisTemplate.delete(key);
    }

    /**
     * 获取Key
     *
     * @param key
     */
    public String getKey(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 模糊查询
     *
     * @param key
     * @return
     */
    public Set<String> keys(String key) {
        return redisTemplate.keys(key);
    }


    /**
     * 获取hash中field对应的值
     *
     * @param key
     * @param field
     * @return
     */
    public String hashget(String key, String field) {
        Object val = redisTemplate.opsForHash().get(key, field);
        return val == null ? null : val.toString();
    }

    /**
     * 添加or更新hash的值
     *
     * @param key
     * @param field
     * @param value
     */
    public void hashset(String key, String field, String value, long timeout, TimeUnit timeUnit) {
        redisTemplate.execute(new SessionCallback<List<Object>>() {
            @Override
            public List<Object> execute(RedisOperations redisOperations) throws DataAccessException {
                redisOperations.multi();
                redisOperations.opsForHash().put(key, field, value);
                redisOperations.expire(key, timeout, timeUnit);
                return redisOperations.exec();
            }
        });
    }

    /**
     * 删除hash中field这一对kv
     *
     * @param key
     * @param field
     */
    public void hashdel(String key, String field) {
        redisTemplate.opsForHash().delete(key, field);
    }


    /**
     * 删除key
     *
     * @param key 如果传入hash类型的key，则把整个hash中所有field删除
     */
    public void keydel(String key) {
        redisTemplate.delete(key);
    }

    /**
     * 取hash类型 该key所有参数
     *
     * @param key
     * @return
     */
    public Map<String, String> hashgetll(String key) {
        return redisTemplate.execute((RedisCallback<Map<String, String>>) con -> {
            Map<byte[], byte[]> result = con.hGetAll(key.getBytes());
            if (CollectionUtils.isEmpty(result)) {
                return new HashMap<>(0);
            }

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

    /**
     * 取该hash的key中指定多个参数
     *
     * @param key
     * @param fields
     * @return
     */
    public Map<String, String> hashmget(String key, List<String> fields) {
        List<String> result = redisTemplate.<String, String>opsForHash().multiGet(key, fields);
        Map<String, String> ans = new HashMap<>(fields.size());
        int index = 0;
        for (String field : fields) {
            if (result.get(index) == null) {
                continue;
            }
            ans.put(field, result.get(index));
        }
        return ans;
    }

    /**
     * 向指定key中存放set<String>集合
     *
     * @param key
     * @param value
     */
    public void addForSet(String key, String value, long timeout, TimeUnit timeUnit) {
        redisTemplate.execute(new SessionCallback<List<Object>>() {
            @Override
            public List<Object> execute(RedisOperations redisOperations) throws DataAccessException {
                redisOperations.multi();
                redisOperations.opsForSet().add(key, value);
                redisOperations.expire(key, timeout, timeUnit);
                return redisOperations.exec();
            }
        });
    }

    /**
     * 移除指定key中et<String>集合的某值
     *
     * @param key
     */
    public void removeForSet(String key, String value) {
        log.info("清redis key： {}  value {}", key, value);
        redisTemplate.opsForSet().remove(key, value);
    }

    /**
     * 获取指定key中存放的set<String>的集合
     *
     * @param key
     */
    public Set<String> getForSetMembers(String key) {
        return redisTemplate.opsForSet().members(key);
    }

}
