package org.jeecg.config.mqtt;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;

@Slf4j
@AllArgsConstructor
@Configuration
@EnableIntegration
@EnableConfigurationProperties(MqttConfigProperties.class)
// MQTT 配置类
public class MqttConfig {

    private MqttConfigProperties mqttConfigProperties;
    private MqttMessageHandler mqttMessageHandler;

    // 创建 MQTT 客户端工厂的 Bean
    @Bean
    public MqttPahoClientFactory mqttClientFactory() {
        DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
        MqttConnectOptions options = new MqttConnectOptions();
        options.setServerURIs(new String[] { mqttConfigProperties.getUrl() });  // 设置服务器 URI
        if (StringUtils.isNotBlank(mqttConfigProperties.getUsername())) {
            options.setUserName(mqttConfigProperties.getUsername()); // 设置MQTT用户名
        }
        if (StringUtils.isNotBlank(mqttConfigProperties.getPassword())) {
            options.setPassword(mqttConfigProperties.getPassword().toCharArray()); // 设置MQTT密码
        }
        //断开后是否尝试重连
        options.setAutomaticReconnect(true);
        //连接超时时长，收到服务器连接确认前的等待时间，等待时间内未收到连接确认则为连接失败
        options.setConnectionTimeout(10);
        //保活周期，是一个以秒为单位的时间间隔。客户端在无报文发送时，将按 Keep Alive 设定的值定时向服务端发送心跳报文，确保连接不被服务端断开
        //在连接建立成功后，如果服务器没有在 Keep Alive 的 1.5 倍时间内收到来自客户端的任何包，则会认为和客户端之间的连接出现了问题，此时服务器便会断开和客户端的连接
        options.setKeepAliveInterval(90);
        factory.setConnectionOptions(options);  // 应用连接选项
        return factory;
    }

    // 创建输入消息通道的 Bean
    @Bean
    public MessageChannel mqttInputChannel() { return new DirectChannel(); }
    // 创建输出消息通道的 Bean
    @Bean
    public MessageChannel mqttOutputChannel() { return new DirectChannel(); }
    @Bean
    public MessageChannel errorChannel(){
        return new DirectChannel();
    }

    // 配置 MQTT 消息驱动通道适配器（用于接收消息）
    @Bean
    public MqttPahoMessageDrivenChannelAdapter mqttInbound(MqttPahoClientFactory clientFactory) {
        //此处订阅设备监控系统模块发送消息的topic和卡尺数据接收程序发送消息的topic
        MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(mqttConfigProperties.getConsumerClientId(), clientFactory,
                mqttConfigProperties.getProducerTopic(),mqttConfigProperties.getProducerTopicMobile());
        adapter.setCompletionTimeout(5000);  // 设置完成超时时间
        adapter.setConverter(new DefaultPahoMessageConverter());  // 设置消息转换器
        adapter.setQos(0);  // 设置服务质量等级
        adapter.setOutputChannel(mqttInputChannel());  // 设置输出通道
        log.info("接收消息通道初始化完毕");
        return adapter;
    }

    //使用ServiceActivator 指定接收消息的管道为 mqttInboundChannel，投递到mqttInboundChannel管道中的消息会被该方法接收并执行
    @Bean
    @ServiceActivator(inputChannel = "mqttInputChannel")
    public MessageHandler handleMessage() {
        return mqttMessageHandler;
    }

    // 配置 MQTT 消息处理器（用于发送消息）
    @Bean
    @ServiceActivator(inputChannel = "mqttOutputChannel")
    public MqttPahoMessageHandler mqttOutbound(MqttPahoClientFactory clientFactory) {
        MqttPahoMessageHandler messageHandler =
                new MqttPahoMessageHandler(mqttConfigProperties.getProducerClientId(), clientFactory);
        messageHandler.setAsync(true);  // 设置异步发送
        messageHandler.setConverter(new DefaultPahoMessageConverter());
        messageHandler.setDefaultTopic(mqttConfigProperties.getProducerTopic());  // 设置主题(设备监控系统模块使用此主题发送消息)
        log.info("发送消息通道初始化完毕");
        return messageHandler;
    }
}
