package com.yida.data.attendance.utils;

import cn.hutool.core.util.StrUtil;
import com.yida.data.attendance.constant.MqttConstant;
import com.yida.data.attendance.service.impl.HaiqingCallbackService;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.context.annotation.Configuration;

@Configuration
@Slf4j
public class MqttUtil {

    private static MqttClient mqttClient;
    private static final String MQTT_CLIENT_ID = StrUtil.uuid();

    public MqttUtil(HaiqingCallbackService haiqingCallbackService, MqttConstant mqttConstant) {
        MemoryPersistence memoryPersistence = new MemoryPersistence();
        try {
            mqttClient = new MqttClient(mqttConstant.getUrl(), MQTT_CLIENT_ID,
                memoryPersistence);
            // 设置回调函数，当订阅到信息时调用此方法
            mqttClient.setCallback(haiqingCallbackService);
            // 向回调添加此客户端
            haiqingCallbackService.setMqttUtil(this);
            MqttConnectOptions connOpts = new MqttConnectOptions();
            // 不自动清除session，每次连接会消费离线期间积累的消息
            // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录，这里设置为true表示每次连接到服务器都以新的身份连接
            connOpts.setCleanSession(true);
            // 设置自动重连
            connOpts.setAutomaticReconnect(true);
            //connOpts.setConnectionTimeout(10);
            // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线，但这个方法并没有重连的机制
            connOpts.setKeepAliveInterval(20);
            connOpts.setUserName(mqttConstant.getUsername());
            connOpts.setPassword(mqttConstant.getPassword().toCharArray());
//            connOpts.setAutomaticReconnect(true);
            mqttClient.connect(connOpts);
        } catch (Exception e) {
            log.error("创建客户端error:{}", e.getMessage());
        }
    }


    public Boolean publish(String msg, String topic) {
        try {
            mqttClient.publish(topic, new MqttMessage(msg.getBytes()));
        } catch (Exception e) {
            log.error("发送设备信息失败, msg: {}, topic: {}", msg, topic, e);
            reconnect();
            return false;
        }
        return true;
    }

    public Boolean addTopic(String topic) {
        try {
            mqttClient.subscribe(topic, 2);
        } catch (Exception e) {
            log.error("发送订阅msg失败:{}", e.getMessage());
            reconnect();
            return false;
        }
        return true;
    }

    public Boolean addTopic(String[] topic) {
        try {
            // 保证一定只接受一次消息
            int[] qos = new int[topic.length];
            for (int i = 0; i < topic.length; i++) {
                qos[i] = 2;
            }
            mqttClient.subscribe(topic, qos);
        } catch (Exception e) {
            log.error("发送订阅msg失败:{}", e.getMessage());
            reconnect();
            return false;
        }
        return true;
    }

    private void reconnect() {
        try {
            mqttClient.reconnect();
        } catch (MqttException e) {
            log.error("重新连接客户端失败", e);
        }
    }

}
