package com.qmth.themis.business.util;

import com.qmth.themis.business.constant.SystemConstant;
import com.qmth.themis.common.exception.BusinessException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicInteger;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @Description: redis util
 * @Param:
 * @return:
 * @Author: wangliang
 * @Date: 2020/4/15
 */
@Component
public class RedisUtil {

    @Resource
    RedisTemplate<String, Object> redisTemplate;

    /**
     * 获取用户会话信息
     *
     * @param sessionId
     * @return
     */
    public Object getUserSession(String sessionId) {
        return redisTemplate.opsForValue().get(SystemConstant.SESSION + sessionId);
    }

    /**
     * 删除用户会话缓存
     *
     * @param sessionId
     */
    public void deleteUserSession(String sessionId) {
        redisTemplate.delete(SystemConstant.SESSION + sessionId);
    }

    /**
     * 设置用户session信息
     *
     * @param sessionId
     * @param o
     * @param time
     */
    public void setUserSession(String sessionId, Object o, long time) {
        redisTemplate.opsForValue().set(SystemConstant.SESSION + sessionId, o, time, TimeUnit.SECONDS);
    }

    /**
     * 批量获取key的value
     *
     * @param keys
     * @return
     */
    public List<?> multiGet(Set keys) {
        return redisTemplate.opsForValue().multiGet(keys);
    }

    /**
     * 获取key like
     *
     * @param key
     * @return
     */
    public Set<?> getKeyPatterns(String key) {
        if (null != key) {
            return redisTemplate.keys(key);
        } else {
            return null;
        }
    }

    /**
     * 设置hash
     *
     * @param key
     * @param hashKey
     * @param hashValue
     */
    public void set(String key, String hashKey, Object hashValue) {
        redisTemplate.opsForHash().put(key, hashKey, hashValue);
    }

    /**
     * 设置zset
     *
     * @param key
     * @param hashValue
     * @param score
     */
    public void setZset(String key, Object hashValue, double score) {
        redisTemplate.opsForZSet().add(key, hashValue, score);
        this.expire(key, 1, TimeUnit.HOURS);
    }

    /**
     * 获取zset
     *
     * @param key
     * @param hashValue
     */
    public Double getZset(String key, Object hashValue) {
        return redisTemplate.opsForZSet().score(key, hashValue);
    }

    /**
     * 获取zset大小
     *
     * @param key
     */
    public Long getZsetSize(String key) {
        return redisTemplate.opsForZSet().size(key);
    }


    /**
     * 设置hash
     *
     * @param key
     * @param hashKey
     * @param count
     */
    public void setInc(String key, String hashKey, Long count) {
        redisTemplate.opsForHash().increment(key, hashKey, count);
    }

    /**
     * 获取hash
     *
     * @param key
     * @param hashKey
     * @return
     */
    public Object get(String key, String hashKey) {
        return redisTemplate.opsForHash().get(key, hashKey);
    }

    /**
     * hash删除
     *
     * @param key
     * @param hashKey
     */
    public void delete(String key, String hashKey) {
        redisTemplate.opsForHash().delete(key, hashKey);
    }

    /**
     * 获取hash大小
     *
     * @param key
     * @return
     */
    public Long getHashSize(String key) {
        return redisTemplate.opsForHash().size(key);
    }

    /**
     * 获取hash map
     *
     * @param key
     * @return
     */
    public Map getHashEntries(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 获取hash map
     *
     * @param key
     * @return
     */
    public Set getHashKeys(String key) {
        return redisTemplate.opsForHash().keys(key);
    }

    /**
     * 获取hash map
     *
     * @param key
     * @return
     */
    public List getHashValues(String key) {
        return redisTemplate.opsForHash().values(key);
    }


    /**
     * 分布式锁，尝试上锁一定次数，失败后抛出异常
     *
     * @param key
     * @param timeout
     * @return
     */
    public void waitLock(String key, long timeout) {
        for (int i = 0; i < SystemConstant.MAX_EXAM_STATUS_COUNT; i++) {
            if (lock(key, timeout)) {
                return;
            }
        }
        throw new BusinessException("重复尝试上锁失败:" + key);
    }

    /**
     * 分布式锁
     *
     * @param key
     * @param timeout SECONDS
     * @return
     */
    public boolean lock(String key, long timeout) {
        long expireAt = System.currentTimeMillis() + (timeout * 1000) + 1;
        return redisTemplate.opsForValue().setIfAbsent(key, expireAt, timeout, TimeUnit.SECONDS);
    }

    /**
     * 删除锁
     *
     * @param key
     * @return
     */
    public void releaseLock(String key) {
        redisTemplate.expire(key, 100, TimeUnit.MILLISECONDS);
    }

    /**
     * 累加操作
     *
     * @param key
     * @return
     */
    public Long increment(String key) {
        return redisTemplate.opsForValue().increment(key);
    }

    /**
     * 累减操作
     *
     * @param key
     * @return
     */
    public Long decrement(String key) {
        return redisTemplate.opsForValue().decrement(key);
    }

    /**
     * 设置缓存
     *
     * @param key
     * @param o
     */
    public void set(String key, Object o) {
        redisTemplate.opsForValue().set(key, o);
    }

    /**
     * 设置缓存
     *
     * @param key
     * @param o
     */
    public void addSet(String key, Object o) {
        redisTemplate.opsForSet().add(key, o);
    }

    /**
     * 获取缓存
     *
     * @param key
     */
    public Set getSet(String key) {
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * 删除缓存
     *
     * @param key
     */
    public void removeSet(String key, Object o) {
        redisTemplate.opsForSet().remove(key, o);
    }

    /**
     * 设置list缓存
     *
     * @param key
     * @param o
     */
    public void setList(String key, Object o) {
        redisTemplate.opsForList().leftPush(key, o);
    }

    /**
     * 查找list缓存
     *
     * @param key
     */
    public void rangeList(String key) {
        redisTemplate.opsForList().range(key, 0, -1);
    }

    /**
     * 删除list缓存
     *
     * @param key
     * @param o
     */
    public void removeList(String key, Object o) {
        redisTemplate.opsForList().remove(key, 0, o);
    }


    /**
     * 设置缓存
     *
     * @param key
     * @param o
     * @param time
     * @param timeUnit
     */
    public void set(String key, Object o, long time, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, o, time, timeUnit);
    }

    /**
     * 设置缓存
     *
     * @param key
     * @param o
     * @param time SECONDS
     */
    public void set(String key, Object o, long time) {
        set(key, o, time, TimeUnit.SECONDS);
    }

    /**
     * 获取缓存
     *
     * @param key
     * @return
     */
    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 删除缓存
     *
     * @param key
     * @return
     */
    public void delete(String key) {
        redisTemplate.expire(key, 0, TimeUnit.SECONDS);
    }

    /**
     * 保存hash结构
     *
     * @param key
     * @param map
     */
    public void setForHash(String key, Map<String, Object> map) {
        redisTemplate.opsForHash().putAll(key, map);
    }

    /**
     * 设置过期时间（秒）
     *
     * @param key
     * @param timeOutSecond
     */
    public void expire(String key, int timeOutSecond) {
        redisTemplate.expire(key, timeOutSecond, TimeUnit.SECONDS);
    }

    /**
     * 设置过期时间
     *
     * @param key
     * @param timeOut
     */
    public void expire(String key, long timeOut, TimeUnit timeUnit) {
        redisTemplate.expire(key, timeOut, timeUnit);
    }

    //    /**
    //     * 获取redis序列
    //     *
    //     * @return
    //     */
    //    public Integer getRedisSequence() {
    //        RedisAtomicInteger entityIdCounter = new RedisAtomicInteger(SystemConstant.REDIS_MONITOR_SEQUENCE, redisTemplate.getConnectionFactory());
    //        return entityIdCounter.incrementAndGet();
    //    }

    /**
     * 获取redis activity code序列
     *
     * @param key
     * @return
     */
    public Integer getRedisActivityCodeSequence(Long key) {
        RedisAtomicInteger entityIdCounter = new RedisAtomicInteger(SystemConstant.REDIS_ACTIVITY_CODE_SEQUENCE + key,
                redisTemplate.getConnectionFactory());
        return entityIdCounter.incrementAndGet();
    }

    /**
     * 获取redis activity code序列
     *
     * @param key
     * @return
     */
    public Integer getRedisActivityCodeSequenceValue(Long key) {
        RedisAtomicInteger entityIdCounter = new RedisAtomicInteger(SystemConstant.REDIS_ACTIVITY_CODE_SEQUENCE + key,
                redisTemplate.getConnectionFactory());
        return entityIdCounter.get();
    }

    /**
     * 设置redis activity code序列
     *
     * @param key
     * @param initialValue
     * @return
     */
    public Integer setRedisActivityCodeSequence(Long key, int initialValue) {
        RedisAtomicInteger entityIdCounter = new RedisAtomicInteger(SystemConstant.REDIS_ACTIVITY_CODE_SEQUENCE + key,
                redisTemplate.getConnectionFactory(), initialValue);
        return entityIdCounter.get();
    }

    /**
     * 删除redis activity code序列
     *
     * @param key
     */
    public void deleteRedisActivityCodeSequence(Long key) {
        this.delete(SystemConstant.REDIS_ACTIVITY_CODE_SEQUENCE + key);
    }
}