package com.zsc.edu.gateway.modules.mqtt.config;

import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONPath;
import com.zsc.edu.gateway.modules.iot.record.service.RecordDataService;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.beans.factory.annotation.Value;
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.core.MessageProducer;
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;
import org.springframework.util.StringUtils;

import java.util.UUID;

@Slf4j
@Configuration
public class MqttConfig {
    @Resource
    private RecordDataService recordDataService;


    public static final String CHANNEL_OUT = "mqttOutboundChannel";
    public static final String CHANNEL_IN = "mqttInputChannel";

    private static final byte[] WILL_DATA;

    static {
        WILL_DATA = "offline".getBytes();
    }

    @Value("${gatherer.version}")
    private String gatherer;
    @Value("${mqtt.username}")
    private String username;
    @Value("${mqtt.password}")
    private String password;
    @Value("${mqtt.host}")
    private String host;
    @Value("${mqtt.port}")
    private String port;
    @Getter
    @Value("${mqtt.topic}")
    private String topic;
    @Value("${mqtt.qos}")
    private Integer qos;

    /**
     * 创建MqttPahoClientFactory，设置MQTT Broker连接属性，如果使用ssl验证也在这里设置
     *
     * @return factory
     */
    @Bean
    public MqttPahoClientFactory mqttPahoClientFactory() {
        DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
        MqttConnectOptions options = new MqttConnectOptions();

        if (StringUtils.hasText(username)) {
            options.setUserName(username);
        }

        options.setPassword(password.toCharArray());

        options.setServerURIs(new String[]{host + ":" + port});

        options.setConnectionTimeout(10);

        options.setKeepAliveInterval(20);

        options.setWill("willTopic", WILL_DATA, 2, false);
        factory.setConnectionOptions(options);

        return factory;
    }

    /**
     * 入站通道
     */
    @Bean
    public MessageChannel mqttInputChannel() {
        return new DirectChannel();
    }

    /**
     * 入站
     */
    @Bean
    public MessageProducer inbound() {
        // Paho客户端消息驱动通道适配器，主要用来订阅主题
        MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(
                "clientId-" + UUID.randomUUID(),
                mqttPahoClientFactory(),
                "/r1/devices/+/datas"
        );
        adapter.setCompletionTimeout(5000);

        // Paho消息转换器
        DefaultPahoMessageConverter defaultPahoMessageConverter = new DefaultPahoMessageConverter();

        // 按字节接收消息
        defaultPahoMessageConverter.setPayloadAsBytes(true);
        adapter.setConverter(defaultPahoMessageConverter);
        adapter.setQos(qos);
        adapter.setOutputChannel(mqttInputChannel());
        return adapter;

    }

    /**
     * ServiceActivator注解表明： 当前方法用于处理MQTT消息，inputChannel参数指定了用于消费的channel
     *
     * @return
     */
    @Bean
    @ServiceActivator(inputChannel = CHANNEL_IN)
    public MessageHandler handler() {
        return message -> {
            String topic = message.getHeaders().get("mqtt_receivedTopic").toString();
            String clientId = topic.split("/")[3];
            String deviceGatherer = clientId.substring(0, 3);
            if (topic.matches("/r1/devices/\\d{12}/datas") && deviceGatherer.equals(gatherer)) {
                String payloadString = new String((byte[]) message.getPayload());
                JSONObject payload = JSONObject.parseObject(payloadString);
                log.info("获取设备编码：" + clientId);
                log.info("负载：" + payload);
                JSONObject data = (JSONObject) JSONPath.eval(payload, "$.devices[0].services[0].data");
                recordDataService.recordData(clientId, data);
            } else {
                log.error("丢弃信息，主题[" + topic + "]");
            }
        };
    }


    /**
     * 出站通道
     */
    @Bean
    public MessageChannel mqttOutboundChannel() {
        return new DirectChannel();
    }

    /**
     * 出站
     */
    @Bean
    @ServiceActivator(inputChannel = CHANNEL_OUT)
    public MessageHandler outbound() {
        MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(
                "clientId" + UUID.randomUUID(),
                mqttPahoClientFactory()
        );
        messageHandler.setAsync(true);
        messageHandler.setDefaultTopic(topic);
        messageHandler.setConverter(new DefaultPahoMessageConverter());
        return messageHandler;

    }

}
