package com.bohuikeji.frame.module.admin.config;

import com.bohuikeji.frame.module.admin.base.MqListener;
import com.bohuikeji.frame.module.admin.entity.mq.MqMsg;
import com.bohuikeji.frame.module.admin.thread.CachedThreadPool;
import com.bohuikeji.frame.module.admin.thread.MqListenerThread;
import com.bohuikeji.frame.module.admin.utils.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

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

/**
 * RabbitMQ配置
 * @author 孙劲辉
 */
@Slf4j
@Configuration("ranch-rabbitmq-conf")
public class MqConf {

    /**
     * 点对点消息队列
     * 默认交换机
     */
    public static final String QUEUE_RANCH_ONE_TO_ONE="queue.ranch.one.to.one";
    /**
     * 发送一对多(广播)消息队列
     */
    public static final String QUEUE_RANCH_ONE_TO_ALL="queue.ranch.one.to.all."+System.currentTimeMillis();

    /**
     * 延时消息队列
     */
    public static final String QUEUE_RANCH_DELAY="queue.ranch.delay";

    /**
     * 广播交换机
     */
    public static final String EXCHANGE_FANOUT_RANCH ="exchange.fanout.ranch";

    /**
     * 延时交换机
     */
    public static final String EXCHANGE_DELAY_RANCH="exchange.delay.ranch";


    @Bean
    public Queue oneToOneQueue() {return new Queue(QUEUE_RANCH_ONE_TO_ONE, true,false,true);}

    @Bean
    public Queue oneToAllQueue(){return new Queue(QUEUE_RANCH_ONE_TO_ALL, true,false,true);}

    @Bean
    public Queue delayQueue(){return new Queue(QUEUE_RANCH_DELAY, true,false,true);}

    /**
     * 广播交换机
     * @return
     */
    @Bean
    public FanoutExchange ranchFanoutExchange(){
        return new FanoutExchange(EXCHANGE_FANOUT_RANCH);
    }

    /**
     * 延时交换机
     * @return
     */
    @Bean
    public CustomExchange ranchDelayExchange(){
        Map<String, Object> args = new HashMap<>();
        args.put("x-delayed-type", "direct");
        return new CustomExchange(EXCHANGE_DELAY_RANCH,"x-delayed-message",true, false,args);
    }

    /**
     * 广播交换机绑定
      * @param oneToAllQueue
     * @param ranchFanoutExchange
     * @return
     */
    @Bean
    public Binding fanoutBuild(Queue oneToAllQueue, FanoutExchange ranchFanoutExchange){
        return BindingBuilder.bind(oneToAllQueue).to(ranchFanoutExchange);
    }

    /**
     * 延时交换机绑定
     * @param delayQueue
     * @param ranchDelayExchange
     * @return
     */
    @Bean
    public Binding delayBuild(Queue delayQueue, CustomExchange ranchDelayExchange){
        return BindingBuilder.bind(delayQueue).to(ranchDelayExchange).with(QUEUE_RANCH_DELAY).noargs();
    }


    /**
     * 统一监听监听
     * @param msg
     */
    @RabbitHandler
    @RabbitListener(queues = {QUEUE_RANCH_ONE_TO_ONE,QUEUE_RANCH_DELAY,"#{oneToAllQueue.name}"},priority = "${spring.rabbitmq.priority}")
    public void news(MqMsg<?> msg) {
        MqListener listener;
        try {
            listener= SpringUtil.getBean(msg.getListener());
        }catch (Exception e){
            log.error("【消息队列监听者业务异常】监听类：{}，缺少@Service注解,已经尝试手动注册。",msg.getListener(),e);
            SpringUtil.registerBean(msg.getListener());
            listener= SpringUtil.getBean(msg.getListener());
        }
        try {
            CachedThreadPool.execute(new MqListenerThread(listener,msg.getData()));
        } catch (Exception e) {
            log.error("【消息队列监听者业务异常】位于：{},错误信息：{}",listener.getClass(),e.getMessage(),e);
            listener.onError(msg.getData(),e);
        }
    }
}
