package com.zcxk.core.utils;

import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * REDIS缓存实现类
 * @author Andy
 * @date 2021-07-22 11:03
 */
@Service
public class BaseRedisCacheImpl extends AbstractBaseRedis implements CacheClient {

    /**
     * 设置缓存值
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T> boolean setWithTtl(String realKey, T t, Long timeout) {
        redisTemplate.opsForValue().set(realKey, t, timeout, TimeUnit.SECONDS);
        return true;
    }


    /**
     * 获取缓存值
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T> T get(String realKey) {
        if (realKey == null || "".equals(realKey)) {
            return null;
        }
        return (T) redisTemplate.opsForValue().get(realKey);
    }


    @Override
    @SuppressWarnings("unchecked")
    public void delete(String... realKey) {
        if (null == realKey || realKey.length <= 0) {
            return;
        }

        if (realKey.length == 1) {
            redisTemplate.delete(realKey[0]);
        } else {
            redisTemplate.delete(CollectionUtils.arrayToList(realKey));
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public void hSetWithTtl(String realKey, Object hashKey, Object value, Long timeout) {
        if (null != value) {
            this.hSet(realKey, hashKey, value);
            if (null != timeout && timeout.intValue() > 0) {
                redisTemplate.expire(realKey, timeout, TimeUnit.SECONDS);
            }
        }
    }

    @Override
    public void hincrbyWithTtl(String key, Object hashKey, Long increment, Long timeout) {
        if (null != increment) {
            redisTemplate.opsForHash().increment(key,hashKey,increment);
            if (null != timeout && timeout.intValue() > 0) {
                redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
            }
        }
    }


    private void hSet(String realKey, Object hashKey, Object value) {
        redisTemplate.opsForHash().put(realKey, hashKey, value);
    }

    @Override
    public void setWithTtlByKey(String key, Long timeout) {
        redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 指定前缀key,保存map数据
     */
    @SuppressWarnings("unchecked")
    @Override
    public void hmSetWithTtl(String key, Map<? extends Object, ? extends Object> map,
                             Long expireTime) {
        this.hmSet(key, map);
        if (null != expireTime && expireTime.intValue() > 0) {
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
        }
    }

    private void hmSet(String key, Map<? extends Object, ? extends Object> map) {
        redisTemplate.opsForHash().putAll(key, map);
    }

    /**
     * 获取map保存entries的key的value值
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T> T hGet(String key, Object hashKey) {
        return (T) redisTemplate.opsForHash().get(key, hashKey);
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> List<T> hMultiGet(String key, List<Object> hashKeys) {
        return redisTemplate.opsForHash().multiGet(key, hashKeys);
    }

    /**
     * 获取key数据
     */
    @SuppressWarnings("unchecked")
    @Override
    public Map<Object, Object> hGetAll(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    @Override
    public boolean isExistKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /***
     * 原子递增操作
     *
     */
    @SuppressWarnings("unchecked")
    @Override
    public Long incrementWithTtl(String key, long delta, Long timeout) {
        Long incr = redisTemplate.opsForValue().increment(key, delta);
        if (null != timeout && timeout.intValue() > 0) {
            redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
        }
        return incr;
    }

    @SuppressWarnings("unchecked")
    @Override
    public void hdel(String key, Object... item) {
        redisTemplate.opsForHash().delete(key, item);
    }

    private void addList(String key, List list) {
        redisTemplate.opsForList().rightPushAll(key, list);
    }

    @Override
    public void addListWithTtl(String key, List list, Long timeout) {
        this.addList(key, list);
        if (null != timeout && timeout.intValue() > 0) {
            redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
        }
    }

    @Override
    public void lPushWithTtl(String key, Object value, Long timeout) {
        redisTemplate.opsForList().leftPush(key, value);
        if (null != timeout && timeout.intValue() > 0) {
            redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
        }
    }

    @Override
    public void rPushWithTtl(String key, Object value, Long timeout) {
        redisTemplate.opsForList().rightPush(key, value);
        if (null != timeout && timeout.intValue() > 0) {
            redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
        }
    }

    @Override
    public void lTrim(String key, long start, long end) {
        redisTemplate.opsForList().trim(key, start, end);
    }

    @Override
    public <T> List<T> getListPage(String key, long start, long end) {
        return redisTemplate.opsForList().range(key, start, end);
    }

    @Override
    public Long lLen(String key) {
        return redisTemplate.opsForList().size(key);
    }

    @Override
    public void zIncrbyWithTtl(String key, String value, double score, Long timeout) {
        redisTemplate.opsForZSet().incrementScore(key, value, score);
        if (null != timeout && timeout.intValue() > 0) {
            redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
        }
    }

    @Override
    public void zAddWithTtl(String key, String vale, double score, Long timeout) {
        this.zAdd(key, vale, score);
        if (null != timeout && timeout.intValue() > 0) {
            redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
        }
    }

    private void zAdd(String key, String vale, double score) {
        redisTemplate.opsForZSet().add(key, vale, score);
    }

    @Override
    public <T> Set<T> zRevrange(String key, long start, long end) {
        return redisTemplate.opsForZSet().range(key, start, end);
    }

    @Override
    public <T> Set<TypedTuple<T>> zRevrangeWithScores(String key, long start, long end) {
        return redisTemplate.opsForZSet().rangeByScoreWithScores(key, start, end);
    }

    @Override
    public Long zRemove(String key, String... value) {
        return redisTemplate.opsForZSet().remove(key, value);
    }

    @Override
    public Double zScore(String key, Object val) {
        return redisTemplate.opsForZSet().score(key, val);
    }

    @Override
    public Long zCard(String key) {
        return redisTemplate.opsForZSet().size(key);
    }

    @Override
    public Long removeRange(String key, long start, long end) {
        return redisTemplate.opsForZSet().removeRange(key,start,end);
    }

    @Override
    public Long getExpire(String key) {
        return redisTemplate.getExpire(key);
    }
}