package com.tzld.piaoquan.ad.engine.commons.redis;


import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @author ehlxr
 */
@Configuration
public class RedisTemplateConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.redis.lettuce.pool")
    public GenericObjectPoolConfig<LettucePoolingClientConfiguration> redisPool() {
        return new GenericObjectPoolConfig<>();
    }

    @Bean(name = "algorithmRedisTemplate")
    public RedisTemplate<String, String> getAlgorithmRedisTemplate(@Qualifier("algorithmRedisFactory") RedisConnectionFactory algorithmRedisFactory) {
        return buildRedisTemplateByString(algorithmRedisFactory);
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.redis-algorithm")
    public RedisStandaloneConfiguration algorithmRedisConfig() {
        return new RedisStandaloneConfiguration();
    }

    @Primary
    @Bean("algorithmRedisFactory")
    public LettuceConnectionFactory algorithmRedisFactory(GenericObjectPoolConfig<LettucePoolingClientConfiguration> config,@Qualifier("algorithmRedisConfig") RedisStandaloneConfiguration algorithmRedisConfig) {
        LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
        return new LettuceConnectionFactory(algorithmRedisConfig, lettuceClientConfiguration);
    }

    @Bean(name = "adRedisTemplate")
    public RedisTemplate<String, String> adRedisTemplate(@Qualifier("adRedisFactory") RedisConnectionFactory adRedisFactory) {
        return buildRedisTemplateByString(adRedisFactory);
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.redis-ad")
    public RedisStandaloneConfiguration adRedisConfig() {
        return new RedisStandaloneConfiguration();
    }

    @Bean("adRedisFactory")
    public LettuceConnectionFactory adRedisFactory(GenericObjectPoolConfig<LettucePoolingClientConfiguration> config,@Qualifier("adRedisConfig") RedisStandaloneConfiguration adRedisConfig) {
        LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
        return new LettuceConnectionFactory(adRedisConfig, lettuceClientConfiguration);
    }


    @Bean
    @ConfigurationProperties(prefix = "spring.redis-ad-cache")
    public RedisStandaloneConfiguration newAdRedisConfig() {
        return new RedisStandaloneConfiguration();
    }

    @Bean("newAdRedisFactory")
    public LettuceConnectionFactory newAdRedisFactory(GenericObjectPoolConfig<LettucePoolingClientConfiguration> config,@Qualifier("newAdRedisConfig") RedisStandaloneConfiguration adRedisConfig) {
        LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
        return new LettuceConnectionFactory(adRedisConfig, lettuceClientConfiguration);
    }

    @Bean(name = "newAdRedisTemplate")
    public RedisTemplate<String, String> newAdRedisTemplate(@Qualifier("newAdRedisFactory") RedisConnectionFactory adRedisFactory) {
        return buildRedisTemplateByString(adRedisFactory);
    }



    /**
     * 构建redisTemplate 使用string序列化
     *
     * @param factory
     * @return
     */
    public RedisTemplate<String, String> buildRedisTemplateByString(RedisConnectionFactory factory) {
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        // key的序列化类型 保证可读性
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
        return redisTemplate;
    }

    /**
     * 构建redisTemplate value使用fastjson序列化
     *
     * @param factory
     * @return
     */
    public RedisTemplate<String, Object> buildRedisTemplateByFastJson(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        // key的序列化类型 保证可读性
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //value的序列化类型 fastjson 保证效率
        FastJson2JsonRedisSerializer fastJson2JsonRedisSerializer = fastJson2JsonRedisSerializer();
        redisTemplate.setValueSerializer(fastJson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(fastJson2JsonRedisSerializer);
        return redisTemplate;
    }

    /**
     * 构建redisTemplate value使用jackson序列化
     *
     * @param factory
     * @return
     */
    public RedisTemplate<String, Object> buildRedisTemplateByJackson(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        // key的序列化类型 保证可读性
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //value的序列化类型 jackson 保证效率
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = jackson2JsonRedisSerializer();
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        return redisTemplate;
    }

    /**
     * Jackson 序列化
     *
     * @return
     */
    public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        return jackson2JsonRedisSerializer;
    }

    /**
     * FastJson 序列化
     *
     * @return
     */
    public FastJson2JsonRedisSerializer<Object> fastJson2JsonRedisSerializer() {
        return new FastJson2JsonRedisSerializer(Object.class);
    }
}
