package cn.com.ctop.track.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * redis 工具类
 * @Author Scott
 *
 */
@Component
@Slf4j
public class RedisUtil {


	@Autowired
	private StringRedisTemplate redisTemplate;


	private final String DEFAULT_KEY_PREFIX = "";
	private final int EXPIRE_TIME = 1;
	private final TimeUnit EXPIRE_TIME_TYPE = TimeUnit.DAYS;


	/**
	 * 数据缓存至redis
	 *
	 * @param key
	 * @param value
	 * @return
	 */
	public <K, V> void add(K key, V value) {
		try {
			if (value != null) {
				redisTemplate
						.opsForValue()
						.set(DEFAULT_KEY_PREFIX + key, JSON.toJSONString(value));
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new RuntimeException("数据缓存至redis失败");
		}
	}

	/**
	 * 数据缓存至redis并设置过期时间
	 *
	 * @param key
	 * @param value
	 * @return
	 */
	public <K, V> void add(K key, V value, long timeout, TimeUnit unit) {
		try {
			if (value != null) {
				redisTemplate
						.opsForValue()
						.set(DEFAULT_KEY_PREFIX + key, JSON.toJSONString(value), timeout, unit);
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new RuntimeException("数据缓存至redis失败");
		}
	}

	/**
	 * 写入 hash-set,已经是key-value的键值，不能再写入为hash-set
	 *
	 * @param key    must not be {@literal null}.
	 * @param subKey must not be {@literal null}.
	 * @param value  写入的值
	 */
	public <K, SK, V> void addHashCache(K key, SK subKey, V value) {
		redisTemplate.opsForHash().put(DEFAULT_KEY_PREFIX + key, subKey, value);
	}

	/**
	 * 写入 hash-set,并设置过期时间
	 *
	 * @param key    must not be {@literal null}.
	 * @param subKey must not be {@literal null}.
	 * @param value  写入的值
	 */
	public <K, SK, V> void addHashCache(K key, SK subKey, V value, long timeout, TimeUnit unit) {
		redisTemplate.opsForHash().put(DEFAULT_KEY_PREFIX + key, subKey, value);
		redisTemplate.expire(DEFAULT_KEY_PREFIX + key, timeout, unit);
	}

	/**
	 * 获取 hash-setvalue
	 *
	 * @param key    must not be {@literal null}.
	 * @param subKey must not be {@literal null}.
	 */
	public <K, SK> Object getHashCache(K key, SK subKey) {
		return  redisTemplate.opsForHash().get(DEFAULT_KEY_PREFIX + key, subKey);
	}


	/**
	 * 从redis中获取缓存数据，转成对象
	 *
	 * @param key   must not be {@literal null}.
	 * @param clazz 对象类型
	 * @return
	 */
	public <K, V> V getObject(K key, Class<V> clazz) {
		String value = this.get(key);
		V result = null;
		if (!StringUtils.isEmpty(value)) {
			result = JSONObject.parseObject(value, clazz);
		}
		return result;
	}

	/**
	 * 从redis中获取缓存数据，转成list
	 *
	 * @param key   must not be {@literal null}.
	 * @param clazz 对象类型
	 * @return
	 */
	public <K, V> List<V> getList(K key, Class<V> clazz) {
		String value = this.get(key);
		List<V> result = Collections.emptyList();
		if (!StringUtils.isEmpty(value)) {
			result = JSONArray.parseArray(value, clazz);
		}
		return result;
	}

	/**
	 * 功能描述：Get the value of {@code key}.
	 *
	 * @param key must not be {@literal null}.
	 * @return java.lang.String
	 * @date 2021/9/19
	 **/
	public <K> String get(K key) {
		String value;
		try {
			value = redisTemplate.opsForValue().get(DEFAULT_KEY_PREFIX + key);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new RuntimeException("从redis缓存中获取缓存数据失败");
		}
		return value;
	}

	/**
	 * 删除key
	 */
	public void delete(String key) {
		redisTemplate.delete(key);
	}

	/**
	 * 批量删除key
	 */
	public void delete(Collection<String> keys) {
		redisTemplate.delete(keys);
	}

	/**
	 * 序列化key
	 */
	public byte[] dump(String key) {
		return redisTemplate.dump(key);
	}

	/**
	 * 是否存在key
	 */
	public Boolean hasKey(String key) {
		return redisTemplate.hasKey(key);
	}

	/**
	 * 设置过期时间
	 */
	public Boolean expire(String key, long timeout, TimeUnit unit) {
		return redisTemplate.expire(key, timeout, unit);
	}

	/**
	 * 设置过期时间
	 */
	public Boolean expireAt(String key, Date date) {
		return redisTemplate.expireAt(key, date);
	}


	/**
	 * 移除 key 的过期时间，key 将持久保持
	 */
	public Boolean persist(String key) {
		return redisTemplate.persist(key);
	}

	/**
	 * 返回 key 的剩余的过期时间
	 */
	public Long getExpire(String key, TimeUnit unit) {
		return redisTemplate.getExpire(key, unit);
	}

	/**
	 * 返回 key 的剩余的过期时间
	 */
	public Long getExpire(String key) {
		return redisTemplate.getExpire(key);
	}


	/**
	 *  返回 满足前缀 的key
	 * @param pattern
	 * @return
	 */
	public Set<String> kesy(String pattern){
		return redisTemplate.keys(pattern);
	}

}
