package com.crunii.micro.component.redis.config;

import com.crunii.micro.component.redis.properties.MicroCacheProperties;
import org.redisson.spring.data.connection.RedissonConnectionFactory;
import org.redisson.spring.starter.RedissonAutoConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ResourceLoader;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;

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

/**
 * @author 田平 create 2020年1月22日上午10:44:32
 */
@Configuration
@ConditionalOnProperty(name = "spring.redis.password")
@AutoConfigureAfter(RedissonAutoConfiguration.class)
@EnableConfigurationProperties(value = { MicroCacheProperties.class, CacheProperties.class })
public class RedisCacheAutoConfiguration {

	@Autowired
	private MicroCacheProperties microCacheProperties;

	@Autowired
	private CacheProperties cacheProperties;

	@Value("${spring.application.name}")
	private String appName;


	@Primary
	@Bean(name = "cacheManager")
	public CacheManager regCacheManager(RedisConnectionFactory connectionFactory) {

		// 生成一个默认配置，通过config对象即可对缓存进行自定义配置
		// 设置缓存的默认过期时间，也是使用Duration设置 6小时
		// 不缓存空值
		RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig()
				.entryTtl(cacheProperties.getRedis().getTimeToLive())
				.prefixCacheNameWith(cacheProperties.getRedis().getKeyPrefix())
				.disableCachingNullValues();

		Map<String, RedisCacheConfiguration> initialCacheConfigurations = new HashMap<>(8);

		// 单独设置某个缓存的配置，例如过期时间等
		microCacheProperties.getExpires()
				.stream()
				.filter(expire -> expire.getAppName().equals(appName))
				.forEach(expire -> {
					RedisCacheConfiguration specialConfig = RedisCacheConfiguration.defaultCacheConfig();
					specialConfig = specialConfig.entryTtl(expire.getTimeToLive())
							.prefixCacheNameWith(cacheProperties.getRedis().getKeyPrefix());
					initialCacheConfigurations.put(expire.getCacheName(), specialConfig);
				});

		// 全局缓存前缀，全局缓存单独的前缀设置,项目重启不会刷新全局缓存
		microCacheProperties.getGlobalCacheNames().forEach(name -> {
			RedisCacheConfiguration globalConfig = RedisCacheConfiguration.defaultCacheConfig();
			globalConfig = globalConfig.entryTtl(microCacheProperties.getGlobalTimeToLive())
					.prefixCacheNameWith(microCacheProperties.getGlobalPrefix());
			initialCacheConfigurations.put(name, globalConfig);
		});

		RedisCacheManager cacheManager = RedisCacheManager.builder(connectionFactory)
				.cacheDefaults(defaultConfig)
				.withInitialCacheConfigurations(initialCacheConfigurations)
				.build();

		//项目重启会情况缓存
		String keyPrefix = appName + "*";
		Set<byte[]> keys = connectionFactory.getConnection().keys(keyPrefix.getBytes());
		if (keys.size() > 0) {
			connectionFactory.getConnection().del(keys.toArray(new byte[keys.size()][]));
		}
		return cacheManager;
	}
}
