package com.springboot.cloud.auth.authentication.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.springboot.cloud.auth.authentication.events.BusReceiver;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.amqp.support.converter.ContentTypeDelegatingMessageConverter;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 消息设置
 */
@Configuration
@Slf4j
public class BusConfig {

    private static final String EXCHANGE_NAME = "spring-boot-exchange";
    private static final String ROUTING_KEY = "organization-popedom";

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


    /**
     * 配置监听队列，mq只能直接监听队列，不能直接监听交换机
     * @return 队列
     */
    @Bean
    Queue queue() {
        String queueName = new Base64UrlNamingStrategy(appName + ".").generateName();
        log.info("queue name:{}", queueName);
        return new Queue(queueName, false);
    }

    /**
     * 采用主题交换机
     * @return 主题交换机
     */
    @Bean
    TopicExchange exchange() {
        log.info("exchange:{}", EXCHANGE_NAME);
        return new TopicExchange(EXCHANGE_NAME);
    }

    /**
     * 将队列绑定到主题交换机上，以router_key作为键
     * @param queue
     * @param exchange
     * @return
     */
    @Bean
    Binding binding(Queue queue, TopicExchange exchange) {
        log.info("binding {} to {} with {}", queue, exchange, ROUTING_KEY);
        return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY);
    }

    /**
     * 设置消息处理监听器
     * @param connectionFactory mq连接工厂，用于配置mq服务器地址，端口，连接关闭或者断开监听器等等
     * @param messageListenerAdapter 消息监听适配器，用于收到消息后对消息进行处理，或者是代理到其他对象进行处理的适配器，默认处理方法为handleMessage
     * @param queue 消息接收队列，可以配置多个队列
     * @return 消息监听容器，可以设置消费者数量、最大最小数量、批量消费等等
     */
    @Bean
    SimpleMessageListenerContainer simpleMessageListenerContainer(ConnectionFactory connectionFactory, MessageListenerAdapter messageListenerAdapter, Queue queue) {
        log.info("init simpleMessageListenerContainer {}", queue.getName());
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
        container.setQueueNames(queue.getName());
        container.setMessageListener(messageListenerAdapter);
        return container;
    }

    /**
     * 设置消息监听适配器
     * @param busReceiver 处理消息的代理对象
     * @param messageConverter 消息转换器，此处用Jackson作为json转换工具类
     * @return
     */
    @Bean
    MessageListenerAdapter messageListenerAdapter(BusReceiver busReceiver, MessageConverter messageConverter) {
        log.info("new listener");
        return new MessageListenerAdapter(busReceiver, messageConverter);
    }

    /**
     * 消息转换器
     * @return Jackson转换器
     */
    @Bean
    public MessageConverter messageConverter() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        return new ContentTypeDelegatingMessageConverter(new Jackson2JsonMessageConverter(objectMapper));
    }
}
