/*
 * Copyright (c) 2023 codvision.com All Rights Reserved.
 */

package com.codvision.mqcore.config;

import com.codvision.mqcore.annotation.MQHandler;
import com.codvision.mqcore.annotation.MQListener;
import com.codvision.mqcore.service.MQSender;
import com.codvision.mqcore.service.impl.MQSenderByRedis;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * 消息队列配置类
 *
 * @author lingee
 * @date 2023/8/22
 */
@Slf4j
@Configuration
@ConditionalOnProperty(value = "cvbp.mq.type", havingValue = "redis", matchIfMissing = true)
public class RedisMQConfig {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public MQSender mq() {
        return new MQSenderByRedis();
    }

    @Bean
    public RedisDelayQueueRunner redisDelayQueueRunner() {
        return new RedisDelayQueueRunner();
    }

    /**
     * redis消息监听器容器
     *
     * @param connectionFactory redis连接工厂
     * @return
     */
    @Bean
    public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);

        try {
            Map<String, Object> beanMap = applicationContext.getBeansWithAnnotation(MQHandler.class);
            for (Map.Entry<String, Object> entry : beanMap.entrySet()) {
                Class<?> clazz = entry.getValue().getClass();
                for (Method method : clazz.getMethods()) {
                    if (method.isAnnotationPresent(MQListener.class)) {
                        MQListener mqListener = AnnotationUtils.getAnnotation(method, MQListener.class);
                        for (String queue : mqListener.queues()) {
                            MessageListenerAdapter messageListenerAdapter
                                    = new MessageListenerAdapter(entry.getValue(), method.getName());
                            messageListenerAdapter.afterPropertiesSet();
                            // 使用Jackson2JsonRedisSerialize 替换默认序列化(默认采用的是JDK序列化)
                            Jackson2JsonRedisSerializer<?> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
                            ObjectMapper om = new ObjectMapper();
                            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
                            om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
                            jackson2JsonRedisSerializer.setObjectMapper(om);
                            messageListenerAdapter.setSerializer(jackson2JsonRedisSerializer);
                            container.addMessageListener(messageListenerAdapter, new PatternTopic(queue));
                        }
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
        return container;
    }

}
