package com.lutao.cloud.iot.mqtt.core.server.dispatcher;

import com.lutao.cloud.iot.mqtt.codec.MqttQoS;
import com.lutao.cloud.iot.mqtt.core.server.MqttServer;
import com.lutao.cloud.iot.mqtt.core.server.model.enums.MessageType;
import com.lutao.cloud.iot.mqtt.core.server.model.model.Message;
import com.lutao.cloud.iot.mqtt.core.server.session.IMqttSessionManager;
import org.tio.core.ChannelContext;
import org.tio.core.Tio;
import org.tio.server.ServerTioConfig;

import java.util.Objects;

/**
 * 内部消息转发抽象
 */
public abstract class AbstractMqttMessageDispatcher implements IMqttMessageDispatcher {
    protected MqttServer mqttServer;
    protected IMqttSessionManager sessionManager;

    public void config(MqttServer mqttServer) {
        this.mqttServer = mqttServer;
        this.sessionManager = mqttServer.getServerCreator().getSessionManager();
    }

    /**
     * 转发到所有订阅了该 topic 的设备
     *
     * @param message Message
     * @return 是否成功
     */
    abstract public boolean sendAll(Message message);

    /**
     * 转发消息到设备，如果 clientId 就在本服务，会自行消化
     *
     * @param clientId clientId
     * @param message  Message
     * @return 是否成功
     */
    abstract public boolean sendTo(String clientId, Message message);

    @Override
    public boolean send(Message message) {
        Objects.requireNonNull(mqttServer, "MqttServer require not Null.");
        // 1. 先发送到本服务
        MessageType messageType = message.getMessageType();
        if (MessageType.UP_STREAM == messageType) {
            MqttQoS qoS = MqttQoS.valueOf(message.getQos());
            mqttServer.publishAll(message.getTopic(), message.getPayload(), qoS, message.isRetain());
        } else if (MessageType.SUBSCRIBE == messageType) {
            sessionManager.addSubscribe(message.getTopic(), message.getFromClientId(), message.getQos());
        } else if (MessageType.UNSUBSCRIBE == messageType) {
            sessionManager.removeSubscribe(message.getTopic(), message.getFromClientId());
        }
        return sendAll(message);
    }

    @Override
    public boolean send(String clientId, Message message) {
        Objects.requireNonNull(mqttServer, "MqttServer require not Null.");
        // 1. 判断如果 clientId 就在本服务，存在则发送
        ServerTioConfig config = this.mqttServer.getServerConfig();
        ChannelContext context = Tio.getByBsId(config, clientId);
        if (context != null) {
            MqttQoS qoS = MqttQoS.valueOf(message.getQos());
            return this.mqttServer.publish(context, clientId, message.getTopic(), message.getPayload(), qoS, false);
        }
        return this.sendTo(clientId, message);
    }

}
