package com.chushang.redis.config;

import cn.hutool.core.util.ObjectUtil;
import com.chushang.common.core.exception.utils.AssertUtil;
import com.chushang.common.core.util.StringUtils;
import com.chushang.redis.cache.PlusSpringCacheManager;
import com.chushang.redis.config.properties.RedissonProperties;
import com.chushang.redis.hanlder.KeyPrefixHandler;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <h2>redis配置</h2>
 *
 * @author 单傲
 * @date 2023/1/17 16:27
 */
@Slf4j
@EnableCaching
@Component
public class RedisConfiguration {
    @Resource
    private RedissonProperties redissonProperties;
    @Resource
    private ObjectMapper objectMapper;

    @Bean
    public RedissonAutoConfigurationCustomizer redissonCustomizer() {
        return config -> {
            config.setThreads(redissonProperties.getThreads())
                    .setNettyThreads(redissonProperties.getNettyThreads())
                    .setCodec(new JsonJacksonCodec(objectMapper))
            ;
            RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig();
            RedissonProperties.ClusterServersConfig clusterServerConfig = redissonProperties.getClusterServersConfig();
            RedissonProperties.SentinelServersConfig sentinelServerConfig = redissonProperties.getSentinelServersConfig();
            if (ObjectUtil.isNotNull(singleServerConfig)) {
                String address = singleServerConfig.getAddress();
                AssertUtil.invalidate(StringUtils.isEmpty(address), "redisson 配置错误");
                if (!address.contains("redis://")){
                    address = "redis://" + address;
                }
                // 使用单机模式
                config.useSingleServer()
                        .setClientName(redissonProperties.getClientName())
                        //设置redis key前缀
                        .setNameMapper(new KeyPrefixHandler(redissonProperties.getPrefix()))
                        .setTimeout(redissonProperties.getTimeout())
                        .setPassword(redissonProperties.getPassword())
                        .setUsername(redissonProperties.getUsername())
                        .setDatabase(singleServerConfig.getDatabase())
                        .setAddress(address)
                ;
            }
            else
            if (ObjectUtil.isNotNull(clusterServerConfig)) {
                String nodes = clusterServerConfig.getNodes();
                AssertUtil.invalidate(StringUtils.isEmpty(nodes), "redisson cluster 配置错误");
                List<String> nodeList;
                if (nodes.contains("redis://")){
                    nodeList = Arrays.stream(nodes.split(",")).toList();
                }else {
                    nodeList = Arrays.stream(nodes.split(",")).map(s-> "redis://" + s).collect(Collectors.toList());
                }
                config.useClusterServers()
                        //设置redis key前缀
                        .setNameMapper(new KeyPrefixHandler(redissonProperties.getPrefix()))
                        .setClientName(redissonProperties.getClientName())
                        .setTimeout(redissonProperties.getTimeout())
                        .setPassword(redissonProperties.getPassword())
                        .setUsername(redissonProperties.getUsername())
                        .setNodeAddresses(nodeList);
                ;
            } else if (ObjectUtil.isNotNull(sentinelServerConfig)){
                String nodes = clusterServerConfig.getNodes();
                AssertUtil.invalidate(StringUtils.isEmpty(nodes), "redisson sentinel 配置错误");
                List<String> nodeList;
                if (nodes.contains("redis://")){
                    nodeList = Arrays.stream(nodes.split(",")).toList();
                }else {
                    nodeList = Arrays.stream(nodes.split(",")).map(s-> "redis://" + s).collect(Collectors.toList());
                }
                config.useSentinelServers()
                        .setNameMapper(new KeyPrefixHandler(redissonProperties.getPrefix()))
                        .setClientName(redissonProperties.getClientName())
                        .setTimeout(redissonProperties.getTimeout())
                        .setUsername(redissonProperties.getUsername())
                        .setPassword(redissonProperties.getPassword())
                        .setDatabase(sentinelServerConfig.getDatabase())
                        .setMasterName(sentinelServerConfig.getMasterName())
                        .setSentinelAddresses(nodeList)
                ;
            }
            log.info("------------- 初始化 redis 配置 -------------");
        };
    }

    /**
     * 自定义缓存管理器 整合spring-cache
     */
    @Bean
    public CacheManager cacheManager() {
        return new PlusSpringCacheManager();
    }
}
