package com.ytpm.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.ytpm.constant.CacheConstant;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.lang.Nullable;

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

/**
 * 缓存工具类
 *
 * @author xuwh
 */
public class CacheUtil {

    /**
     * 获取缓存
     *
     * @param key 缓存键值
     * @return Object
     */
    @Nullable
    public static Object get(String key) {
        return get(CacheConstant.DEFAULT_CACHE, CacheConstant.DEFAULT_CACHE_PREFIX, key);
    }

    /**
     * 获取缓存
     *
     * @param cacheName 缓存名
     * @param key       缓存键值
     * @return Object
     */
    @Nullable
    public static <T> T get(String cacheName, String prefixKey, String key, Class<T> type) {
        Object value = get(cacheName, prefixKey, key);
        if (value != null && type != null && !type.isInstance(value)) {
            throw new IllegalStateException(
                    "缓存值与类型不匹配 [" + type.getName() + "]: " + value);
        }
        return (T) value;
    }

    /**
     * 获取缓存
     *
     * @param cacheName 缓存名
     * @param prefixKey 缓存前缀
     * @param key       缓存键值
     * @return Object
     */
    @Nullable
    public static Object get(String cacheName, String prefixKey, String key) {
        return getRedisTemplate().opsForValue().get(formatCacheKey(cacheName, prefixKey, key));
    }

    /**
     * 设置缓存，缓存key统一采用 缓存名+缓存前缀+缓存key 的格式，以便后续系统可以对部分缓存进行重新加载
     *
     * @param key   缓存键值
     * @param value 缓存值
     */
    public static void put(String key, @Nullable Object value) {
        put(key, value, -1);
    }


    /**
     * 模糊匹配,返回string
     *
     * @param match
     * @return
     */
    public static Map<String, String> getLike(String match) {

        Map<String, String> rmap = new HashMap<>();
        Set<String> keys = getRedisTemplate().keys(match);
        if (CollectionUtil.isEmpty(keys)) {
            return null;
        }

        for (String key : keys) {
            rmap.put(key, getRedisTemplate().opsForValue().get(key).toString());
        }

        return rmap;
    }

    /**
     * 模糊查询获取所有key
     *
     * @param match
     * @return
     */
    public static Set<String> getKeySetLike(String match) {
        Set<String> keys = getRedisTemplate().keys(match);
        if (CollectionUtil.isEmpty(keys)) {
            return null;
        }
        return keys;
    }

    /**
     * 设置缓存，缓存key统一采用 缓存名+缓存前缀+缓存key 的格式，以便后续系统可以对部分缓存进行重新加载
     *
     * @param key   缓存键值
     * @param value 缓存值
     * @param ttl   有效时间（单位：秒)
     */
    public static void put(String key, @Nullable Object value, long ttl) {
        put(CacheConstant.DEFAULT_CACHE, CacheConstant.DEFAULT_CACHE_PREFIX, key, value, ttl);
    }

    /**
     * 设置缓存，缓存key统一采用 缓存名+缓存前缀+缓存key 的格式，以便后续系统可以对部分缓存进行重新加载
     *
     * @param cacheName 缓存名
     * @param key       缓存键值
     * @param key       缓存键值
     * @param value     缓存值
     */
    public static void put(String cacheName, String prefixKey, String key, @Nullable Object value) {
        put(cacheName, prefixKey, key, value, -1);
    }

    /**
     * 设置缓存，缓存key统一采用 缓存名+缓存前缀+缓存key 的格式，以便后续系统可以对部分缓存进行重新加载
     *
     * @param cacheName 缓存名
     * @param prefixKey 缓存键值前缀
     * @param key       缓存键值
     * @param value     缓存值
     * @param ttl       有效时间（单位：秒)
     */
    public static void put(String cacheName, String prefixKey, String key, @Nullable Object value, long ttl) {
        if (ttl > 0) {
            getRedisTemplate().opsForValue().set(formatCacheKey(cacheName, prefixKey, key), value, ttl, TimeUnit.SECONDS);
        } else {
            getRedisTemplate().opsForValue().set(formatCacheKey(cacheName, prefixKey, key), value);
        }
    }


    /**
     * 清除缓存
     *
     * @param cacheName 缓存名
     * @param prefixKey 缓存键值前缀
     * @param key       缓存键值
     */
    public static void clear(String cacheName, String prefixKey, String key) {
        if (StrUtil.isAllBlank(cacheName, prefixKey, key)) {
            return;
        }
        getRedisTemplate().delete(formatCacheKey(cacheName, prefixKey, key));
    }

    /**
     * 清除缓存
     *
     * @param cacheName 缓存名
     * @param prefixKey 缓存键值前缀
     */
    public static void clear(String cacheName, String prefixKey) {
        if (StrUtil.isAllBlank(cacheName, prefixKey)) {
            return;
        }
        Set<String> keys = getRedisTemplate().keys(cacheName.concat(prefixKey).concat("*"));
        getRedisTemplate().delete(keys);
    }

    /**
     * 清空缓存
     *
     * @param cacheName 缓存名
     */
    public static void clear(String cacheName) {
        if (StrUtil.isBlank(cacheName)) {
            return;
        }
        Set<String> keys = getRedisTemplate().keys(cacheName.concat("*"));
        getRedisTemplate().delete(keys);
    }

    public static RedisTemplate<String, Object> getRedisTemplateList() {
        return getRedisTemplate();
    }

    /**
     * 获取redisTemplate
     *
     * @return
     */
    private static RedisTemplate<String, Object> getRedisTemplate() {
        return SpringUtil.getBean("redisTemplate", RedisTemplate.class);
    }

    /**
     * 格式化缓存key
     *
     * @param cacheName 缓存名
     * @param prefixKey 缓存前缀
     * @param key       缓存key
     * @return
     */
    private static String formatCacheKey(String cacheName, String prefixKey, String key) {
        StringBuilder sb = new StringBuilder(cacheName.length() + prefixKey.length() + key.length() + 2);
        sb.append(cacheName).append(':').append(prefixKey).append(':').append(key);
        return sb.toString().replace("::",":");
    }

}
