package com.ruoyi.device.mqtt.client;

import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.device.config.MessageRouter;
import com.ruoyi.device.config.MqttConfig;
import com.ruoyi.device.mqtt.constants.MqttConstants;
import com.ruoyi.device.mqtt.enums.QosEnum;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import jakarta.annotation.Resource;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * mqtt 客户端 初始化
 *
 * @author lwm
 */
@Component
public class EmqClient
{
    private static final Logger log = LoggerFactory.getLogger(EmqClient.class);

    private IMqttClient mqttClient;
    @Resource
    private MqttCallback mqttCallback;
    @Resource
    private MqttConfig mqttConfig;

    @PostConstruct
    public synchronized void init()
    {
        if (StringUtils.isEmpty(mqttConfig.getBroker()))
        {
            log.info("未配置 emqx.broker，跳过 MQTT 客户端初始化");
            return;
        }
        MqttClientPersistence persistence = new MemoryPersistence();
        String clientId = MqttConstants.CLIENT_ID_PREFIX + IdUtils.simpleUUID();
        try
        {
            log.info("客户端ID：{}", clientId);
            mqttClient = new MqttClient(mqttConfig.getBroker(), clientId, persistence);
            connect();
            subscribeAll();
        }
        catch (MqttException e)
        {
            log.error("初始化客户端mqttClient对象失败,errormsg={},brokerUrl={},clientId={}",
                    e.getMessage(), mqttConfig.getBroker(), clientId);
        }
    }

    /**
     * 连接broker
     */
    public void connect()
    {
        if (mqttClient == null)
        {
            return;
        }
        MqttConnectOptions options = new MqttConnectOptions();
        options.setAutomaticReconnect(Boolean.TRUE.equals(mqttConfig.getReconnect()));
        options.setUserName(mqttConfig.getUserName());
        options.setPassword(StringUtils.isEmpty(mqttConfig.getPassword()) ? new char[0] : mqttConfig.getPassword().toCharArray());
        options.setCleanSession(Boolean.TRUE.equals(mqttConfig.getCleanSession()));
        options.setKeepAliveInterval(mqttConfig.getKeepAlive());
        options.setConnectionTimeout(mqttConfig.getTimeout());
        mqttClient.setCallback(mqttCallback);
        try
        {
            mqttClient.connect(options);
            log.info("mqtt客户端连接服务端成功");
        }
        catch (MqttException e)
        {
            log.error("mqtt客户端连接服务端失败,失败原因{}", e.getMessage());
        }
    }

    /**
     * 默认订阅全部主题
     */
    public void subscribeAll()
    {
        if (mqttClient == null || !mqttClient.isConnected())
        {
            return;
        }
        if (StringUtils.isEmpty(mqttConfig.getMessageRouters()))
        {
            return;
        }
        for (MessageRouter router : mqttConfig.getMessageRouters())
        {
            try
            {
                IMqttMessageListener listener = SpringUtils.getBean(router.getListener());
                mqttClient.subscribe(router.getTopic(), router.getQos(), listener);
                log.info("订阅主题名称:{}, QOS:{}, 监听器:{}", router.getTopic(), router.getQos(), router.getListener());
            }
            catch (Exception e)
            {
                log.error("订阅主题失败 topic={} listener={} : errormsg={}", router.getTopic(), router.getListener(),
                    e.getMessage(), e);
            }
        }
    }

    /**
     * 重连
     */
    public void reConnect()
    {
        if (mqttClient == null)
        {
            return;
        }
        for (int i = 0; i < MqttConstants.CLIENT_RECONNECT_ATTEMPTS; i++)
        {
            if (mqttClient.isConnected())
            {
                break;
            }
            try
            {
                mqttClient.reconnect();
                log.info("连接中断，尝试重新连接，重新连接次数：{}", i + 1);
                TimeUnit.SECONDS.sleep(MqttConstants.CLIENT_RECONNECT_INTERVAL);
            }
            catch (MqttException e)
            {
                log.error("重连失败,失败原因{}", e.getMessage());
            }
            catch (InterruptedException e)
            {
                log.error("线程等待重连失败,失败原因{}", e.getMessage());
            }
        }
    }

    /**
     * 发布消息
     * @param topic 主题
     * @param msg 消息
     * @param qos 等级
     * @param retain 是否保留
     */
    public void publish(String topic, byte[] msg, QosEnum qos, boolean retain)
    {
        if (mqttClient == null || !mqttClient.isConnected())
        {
            log.info("发布消息失败，mqtt未连接，放弃发布 topic={}", topic);
            return;
        }
        try
        {
            MqttMessage mqttMessage = new MqttMessage();
            mqttMessage.setPayload(msg);
            mqttMessage.setQos(qos.getValue());
            mqttMessage.setRetained(retain);
            mqttClient.publish(topic, mqttMessage);
        }
        catch (MqttException e)
        {
            log.error("发布消息失败,errormsg={},topic={},msg={},qos={},retain={}",
                    e.getMessage(), topic, msg, qos.getValue(), retain);
        }
    }

    /**
     * 断开连接
     */
    @PreDestroy
    public void disconnectOnShutdown()
    {
        if (mqttClient != null && mqttClient.isConnected())
        {
            try
            {
                mqttClient.disconnect();
            }
            catch (MqttException e)
            {
                log.error("断开连接产生异常,异常信息{}", e.getMessage());
            }
        }
    }


}
