package com.ruoyi.dataprocess.mqtt.client.config;

import com.ruoyi.dataprocess.mqtt.client.listener.MqttClientConnectListener;
import com.ruoyi.dataprocess.service.IDataProcessService;
import com.ruoyi.dataprocess.service.IDeviceStatusService;
import net.dreamlu.iot.mqtt.codec.MqttPublishMessage;
import net.dreamlu.iot.mqtt.codec.MqttQoS;
import net.dreamlu.iot.mqtt.codec.MqttSubAckMessage;
import net.dreamlu.iot.mqtt.core.client.IMqttClientMessageListener;
import net.dreamlu.iot.mqtt.core.client.MqttClient;
import net.dreamlu.iot.mqtt.core.client.MqttClientCreator;
import net.dreamlu.iot.mqtt.spring.client.MqttClientCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.tio.core.ChannelContext;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;

//mqtt:
//        client:
//        enabled: true               # 是否开启客户端，默认：false 使用到的场景有限，非必要请不要启用
//        ip: 127.0.0.1               # 连接的服务端 ip ，默认：127.0.0.1
//        port: 1883                  # 端口：默认：1883
//        name: Mica-Mqtt-Client      # 名称，默认：Mica-Mqtt-Client
//        clientId: 000001            # 客户端Id（非常重要，一般为设备 sn，不可重复）
//        user-name: mica             # 认证的用户名
//        password: 123456            # 认证的密码
//        timeout: 5                  # 超时时间，单位：秒，默认：5秒
//        reconnect: true             # 是否重连，默认：true
//        re-interval: 5000           # 重连时间，默认 5000 毫秒
//        version: MQTT_5             # mqtt 协议版本，默认：3.1.1
//        read-buffer-size: 8KB       # 接收数据的 buffer size，默认：8k
//        max-bytes-in-message: 10MB  # 消息解析最大 bytes 长度，默认：10M
//        buffer-allocator: heap      # 堆内存和堆外内存，默认：堆内存
//        keep-alive-secs: 60         # keep-alive 时间，单位：秒
//        clean-session: true         # mqtt clean session，默认：true
//        use-ssl: false              # 是否启用 ssl，默认：false

//todo:read-buffer-size
@Configuration
public class MqttConfiguration {
    private static final Logger logger = LoggerFactory.getLogger(MqttConfiguration.class);

    @Value("${mqtt.client.ip}")
    String ip;
    @Value("${mqtt.client.port}")
    int port;
    @Value("${mqtt.client.username}")
    String username;
    @Value("${mqtt.client.password}")
    String password;
    @Value("${mqtt.client.clientId}")
    String clientId;
    @Value("${mqtt.client.timeout}")
    int timeOut;
    @Value("${mqtt.client.keepalive}")
    int keepAlive;
    @Value("${mqtt.client.qos}")
    int qos;
    @Value("${mqtt.client.dataTopicFilter}")
    String dataTopicFilter;
    @Value("${mqtt.client.deviceStatusTopic}")
    String deviceStatusTopic;
    @Value("${mqtt.client.imagePath}")
    String imagePath;
    @Value("${mqtt.client.imagePatterns}")
    String imagePatterns;

    @Autowired
    private IDataProcessService dataProcessService;

    @Autowired
    private IDeviceStatusService deviceStatusService;

    @Bean//注入spring
    public MqttClientCustomizer mqttClientCustomizer() {
        return new MqttClientCustomizer() {
            @Override
            public void customize(MqttClientCreator creator) {
                // 此处可自定义配置 creator，会覆盖 yml 中的配置
                System.out.println("----------------MqttServerCustomizer-----------------");
                MqttClient client = creator.ip(ip)
                        .port(port)
                        .username(username)
                        .password(password)
                        .timeout(timeOut)
                        .keepAliveSecs(keepAlive)
//			如果包体过大，建议将此参数设置和 maxBytesInMessage 一样大
//			.readBufferSize(1024 * 10)
//			最大包体长度,如果包体过大需要设置此参数
//			.maxBytesInMessage(1024 * 10)
//			.version(MqttVersion.MQTT_5)
//			连接监听
                        .connectListener(new MqttClientConnectListener())
                        .willMessage(builder -> {
                            builder.topic("/test/offline")
                                    .messageText("down")
                                    .retain(false)
                                    .qos(MqttQoS.AT_MOST_ONCE);    // 遗嘱消息
                        })
                        // 同步连接，也可以使用 connect() 异步（可以避免 broker 没启动照成启动卡住），但是下面的订阅和发布可能还没连接成功。
                        .connectSync();
                String[] topicArr = {dataTopicFilter, deviceStatusTopic};

                client.subscribe(topicArr, MqttQoS.valueOf(qos), new IMqttClientMessageListener() {
                    @Override
                    public void onSubscribed(ChannelContext context, String topicFilter, MqttQoS mqttQoS, MqttSubAckMessage message) {
                        IMqttClientMessageListener.super.onSubscribed(context, topicFilter, mqttQoS, message);
                    }

                    @Override
                    public void onSubscribed(ChannelContext context, String topicFilter, MqttQoS mqttQoS) {
                        IMqttClientMessageListener.super.onSubscribed(context, topicFilter, mqttQoS);
                    }

                    @Override
                    public void onMessage(ChannelContext channelContext, String topic, MqttPublishMessage mqttPublishMessage, ByteBuffer payload) {
                        System.out.println("dataprocessservice:" + dataProcessService);
                        String payloadString = new String(payload.array(), StandardCharsets.UTF_8);
                        System.out.println("paa:" + topic);
                        logger.info("topic:{} payload:{}", topic, payloadString);
                        System.out.println(topic+"----"+dataTopicFilter);
                        System.out.println(topic.startsWith(dataTopicFilter));
                        if (topic.startsWith(dataTopicFilter.replace("#",""))) {
                            dataProcessService.processBusinessData(payloadString, imagePath, imagePatterns);
                        } else if (topic.equals(deviceStatusTopic)) {
                            deviceStatusService.handleDeviceStatus(payloadString,clientId);
                        }
                    }
                });

//                client.subscribe(topicArr,MqttQoS.valueOf(1),new MqttClientMessageListener());
//                client.subQos0(dataTopic,new MqttClientMessageListener());
            }
        };
    }


    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getClientId() {
        return clientId;
    }

    public void setClientId(String clientId) {
        this.clientId = clientId;
    }

    public int getTimeOut() {
        return timeOut;
    }

    public void setTimeOut(int timeOut) {
        this.timeOut = timeOut;
    }

    public int getKeepAlive() {
        return keepAlive;
    }

    public void setKeepAlive(int keepAlive) {
        this.keepAlive = keepAlive;
    }

    public int getQos() {
        return qos;
    }

    public void setQos(int qos) {
        this.qos = qos;
    }

    public String getDataTopicFilter() {
        return dataTopicFilter;
    }

    public void setDataTopicFilter(String dataTopicFilter) {
        this.dataTopicFilter = dataTopicFilter;
    }

    public String getDeviceStatusTopic() {
        return deviceStatusTopic;
    }

    public void setDeviceStatusTopic(String deviceStatusTopic) {
        this.deviceStatusTopic = deviceStatusTopic;
    }

    public String getImagePath() {
        return imagePath;
    }

    public void setImagePath(String imagePath) {
        this.imagePath = imagePath;
    }

    public String getImagePatterns() {
        return imagePatterns;
    }

    public void setImagePatterns(String imagePatterns) {
        this.imagePatterns = imagePatterns;
    }
}
