package com.yfyy.iotx;

import com.alibaba.fastjson.JSONObject;
import com.yfyy.iotx.bean.DevSubBean;
import com.yfyy.iotx.util.DataUtil;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

//MQTT客户端线程
@Slf4j
public class MqttClientThread extends Thread {
    private static final Logger logger = LoggerFactory.getLogger(MqttClientThread.class);

    //连接地址
    private String serverURL;
    //MQTT订阅主题
    private String mqttTopic;
    //MQTT的client
    private String clientId;
    //mqtt实体类
    private MqttClient mqttClient;

    private String deviceName;

    private String userName = "user";
    private String password = "f335bf402c655ee5fd2b5300905124e";

    //构造函数
    public MqttClientThread(String serverURL, String mqttTopic, String clientId, String deviceName) {
        this.serverURL = serverURL;
        this.mqttTopic = mqttTopic;
        this.clientId = clientId;
        this.deviceName = deviceName;
    }

    //线程方法
    public void run() {
        try {
            // host为主机名，clientid即连接MQTT的客户端ID，一般以客户端唯一标识符表示，
            // MemoryPersistence设置clientid的保存形式，默认为以内存保存，就用username
            mqttClient = new MqttClient(serverURL, clientId, new MemoryPersistence());
            // 配置参数信息
            MqttConnectOptions options = new MqttConnectOptions();
            // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录，
            // 这里设置为true表示每次连接到服务器都以新的身份连接
            options.setCleanSession(true);
            options.setUserName(userName);// 设置用户名
            options.setPassword(password.toCharArray());// 设置密码
            options.setConnectionTimeout(30);// 设置超时时间 单位为秒
            // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线，但这个方法并没有重连的机制
            options.setKeepAliveInterval(60);
            //设置断开后重新连接
            options.setAutomaticReconnect(true);
            mqttClient.connect(options);// 连接
            mqttClient.subscribe(mqttTopic);// 订阅 单主题
            // 设置回调
            mqttClient.setCallback(new MqttCallbackExtended() {
                /**
                 * Called when the connection to the server is completed successfully.
                 *
                 * @param reconnect If true, the connection was the result of automatic reconnect.
                 * @param serverURI The server URI that the connection was made to.
                 */
                @Override
                public void connectComplete(boolean reconnect, String serverURI) {
                    try {
                        //单主题
                        mqttClient.subscribe(mqttTopic);
                        logger.info("----TAG", "connectComplete: 订阅主题成功");
                    } catch (Exception e) {
                        e.printStackTrace();
                        logger.info("----TAG", "error: 订阅主题失败");
                    }
                }

                @Override
                public void connectionLost(Throwable throwable) {
                    try {
                        boolean result = DataUtil.offline(deviceName);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    logger.error("连接断开，下面做重连...");
//                    long reconnectTimes = 1;

                    while (true) {

                        try {
                            // 重连的间隔时间
                            Thread.sleep(60 * 60 * 1000);
                        } catch (InterruptedException e1) {
                            e1.printStackTrace();
                        }

                        try {
                            if (mqttClient.isConnected()) {
                                logger.warn("mqtt reconnect success end");
                                break;
                            }

                            // 不再做重连次数限制
//                            if (reconnectTimes == 10000) {//当重连次数达到24次时，就抛出异常，不在重连
//                                logger.warn("mqtt reconnect error");
//                                return;
//                            }
//                            logger.warn("mqtt reconnect times = {} try again...", reconnectTimes++);

                            mqttClient.reconnect();
                        } catch (MqttException e) {
                            logger.error("", e);
                        }

                    }
                }

                @Override
                public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
                    logger.info("接收消息主题 : " + topic);
                    logger.info("接收消息Qos : " + mqttMessage.getQos());
                    logger.info("接收消息内容 : " + new String(mqttMessage.getPayload()));
                    try {
                        String msgData = new String(mqttMessage.getPayload());
                        DevSubBean devSubBean = JSONObject.parseObject(msgData, DevSubBean.class);
                        DataUtil.handleAndReport(devSubBean);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
                    //认证过程
                    logger.info("deliveryComplete.............");
                }
            });
            //放入缓存，根据clinetId吧mqttClient对象放进去
//            MqttClientManager.MQTT_CLIENT_MAP.putIfAbsent(clientId, mqttClient);
        } catch (Exception e) {
            e.printStackTrace();
            //当创建客户端的时候出现 已断开连接，有可能是在另一个环境下启动了该客户端，直接吧这边的客户端关闭，不然另一边会无限重连
            if (e.getMessage().equals("已断开连接") || e.getMessage().equals("客户机未连接")) {
                try {
                    mqttClient.close();
                } catch (MqttException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }
}
