package cn.iocoder.yudao.module.iot.framework.mqtt.consumer.impl;

import cn.iocoder.yudao.module.iot.dal.dataobject.gateway.GatewayDO;
import cn.iocoder.yudao.module.iot.framework.constant.IsEnableConstant;
import cn.iocoder.yudao.module.iot.framework.mqtt.common.MqttCallbackImpl;
import cn.iocoder.yudao.module.iot.framework.mqtt.config.DefaultBizTopicSet;
import cn.iocoder.yudao.module.iot.framework.mqtt.consumer.IMqttservice;
import cn.iocoder.yudao.module.iot.framework.mqtt.consumer.MqttDataHandler;
import cn.iocoder.yudao.module.iot.framework.mqtt.entity.Pattern;
import cn.iocoder.yudao.module.iot.framework.mqtt.entity.SubscriptTopic;
import cn.iocoder.yudao.module.iot.service.gateway.GatewayService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.DependsOn;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

@Service
@EnableScheduling
@DependsOn("defaultMqttStarter")
@Slf4j
public class MqttserviceImpl implements IMqttservice, ApplicationListener<ApplicationReadyEvent> {

    @Resource
    private GatewayService gatewayService;

    @Resource
    private MqttClient client;
    @Resource
    private DefaultBizTopicSet defaultBizTopicSet;
    @Resource
    private MqttConnectOptions options;

    @Resource
    private MqttDataHandler dataHandler;


    @Override
    public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
        new Thread(() -> {
            subscribeMysqlTopic();
        }).start();
    }

    /**
     * 一次性定时器
     * 程序启动后去数据库找到所有需要订阅的topic 添加进client订阅
     */
    @Override
    public void subscribeMysqlTopic() {
        if (client.isConnected()) {

            List<GatewayDO> gatewayList = gatewayService.selectListByIsEnable(IsEnableConstant.IsEnableTrue);
            for (GatewayDO gateway : gatewayList) {
                if (StringUtils.isNotBlank(gateway.getTopic())) {
                    SubscriptTopic topic = new SubscriptTopic(gateway.getTopic(),
                            gateway.getTopic(), Pattern.QUEUE, 0, dataHandler);
                    defaultBizTopicSet.getTopicMap().add(topic);
                    try {
                        client.subscribe(topic.getSubTopic(), 0, dataHandler);
                    } catch (MqttException e) {
                        e.printStackTrace();
                    }
                }
            }
            client.setCallback(new MqttCallbackImpl(defaultBizTopicSet.getTopicMap(), client, options));
            log.info("共订阅:   " + defaultBizTopicSet.getTopicMap().size() + "  个主题!");
        } else {
            log.error("Mqtt is not connected !");
        }

    }

    /**
     * 需要订阅的topic 添加进client订阅
     */
    @Override
    public int subscribeTopic(String topic) throws MqttException {
        SubscriptTopic subscriptTopic = new SubscriptTopic(topic, topic, Pattern.QUEUE, 0, dataHandler);
        defaultBizTopicSet.getTopicMap().add(subscriptTopic);
        client.subscribe(topic, 0, dataHandler);
        client.setCallback(new MqttCallbackImpl(defaultBizTopicSet.getTopicMap(), client, options));
        return 0;
    }

    /**
     * 关闭订阅topic 从client中关闭topic
     */
    @Override
    public int unsubscribeTopic(String topic) throws MqttException {
        for (int i = 0; i < defaultBizTopicSet.getTopicMap().size(); i++) {
            if (topic.equals(defaultBizTopicSet.getTopicMap().get(i).getSubTopic())) {
                defaultBizTopicSet.getTopicMap().remove(defaultBizTopicSet.getTopicMap().get(i));
                break;
            }
        }
        client.unsubscribe(topic);
        client.setCallback(new MqttCallbackImpl(defaultBizTopicSet.getTopicMap(), client, options));
        return 0;
    }


}
