/*
 * Copyright 2020-2030 码匠君<herodotus@aliyun.com>
 *
 * Dante Engine licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Dante Engine 是 Dante Cloud 系统核心组件库，采用 APACHE LICENSE 2.0 开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1. 请不要删除和修改根目录下的LICENSE文件。
 * 2. 请不要删除和修改 Dante Engine 源码头部的版权声明。
 * 3. 请保留源码和相关描述文件的项目出处，作者声明等。
 * 4. 分发源码时候，请注明软件出处 <https://gitee.com/dromara/dante-cloud>
 * 5. 在修改包名，模块名称，项目代码等时，请注明软件出处 <https://gitee.com/dromara/dante-cloud>
 * 6. 若您的项目无法满足以上几点，可申请商业授权
 */

package org.dromara.dante.message.autoconfigure.mqtt;

import com.google.common.base.MoreObjects;
import org.dromara.dante.message.commons.constant.MessageConstants;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.integration.mqtt.support.MqttHeaders;

import java.time.Duration;
import java.util.List;

/**
 * <p>Description: MQTT 相关配置参数 </p>
 *
 * @author : gengwei.zheng
 * @date : 2023/9/10 17:16
 */
@ConfigurationProperties(prefix = MessageConstants.PROPERTY_MESSAGE_MQTT)
public class MqttProperties {

    /**
     * Mqtt 服务器地址，支持多个
     */
    private List<String> serverUrls;
    /**
     * 连接用户名
     */
    private String username;
    /**
     * 连接密码
     */
    private String password;
    /**
     * Mqtt 客户端ID
     */
    private String clientId = "herodotus-client-manager-client-id-v5";
    /**
     * 设置“保持活动”间隔。此值以秒为单位，定义发送或接收消息之间的最大时间间隔。
     * <p>
     * 它使客户端能够检测服务器是否不再可用，而无需等待TCP/IP超时。客户端将确保在每个保活期内至少有一条消息在网络上传播。在这段时间内没有数据相关消息的情况下，客户端会发送一条非常小的“ping”消息，服务器会对此进行确认。
     * 值为0将禁用客户端中的保持活动处理。
     * <p>
     * 默认值为60秒
     */
    private Duration keepAliveInterval = Duration.ofSeconds(60);
    /**
     * 设置如果连接丢失，客户端是否会自动尝试重新连接到服务器。
     * <p>
     * · 如果设置为false，则在连接丢失的情况下，客户端将不会尝试自动重新连接到服务器。
     * · 如果设置为true，则在连接丢失的情况下，客户端将尝试重新连接到服务器。在尝试重新连接之前，它最初将等待1秒，对于每次失败的重新连接尝试，延迟将加倍，直到达到2分钟，此时延迟将保持在2分钟。
     * <p>
     * 您可以使用setAutomaticReconnectDelay（int，int）更改最小和最大延迟。此默认值为true
     */
    private Boolean automaticReconnect = true;
    /**
     * 第一次自动重新连接尝试前等待的时间（秒）。默认值 1 秒
     */
    private Duration automaticReconnectMinDelay = Duration.ofSeconds(1);
    /**
     * 等待自动重新连接尝试的最长时间（秒）。默认值 120 秒
     */
    private Duration automaticReconnectMaxDelay = Duration.ofSeconds(120);
    /**
     * 设置客户端和服务器是否应在重新启动和重新连接时记住状态。
     * <p>
     * 如果设置为false，则服务器将保留会话状态，直到出现以下情况之一：
     * · 将与客户端建立新连接，并将cleanStart标志设置为true。
     * · 网络连接关闭后超过了会话到期间隔，请参阅setSessionExpiryInterval
     * <p>
     * 如果设置为true，服务器将立即放弃给定客户端的任何现有会话状态，并启动新会话。为了实现QoS 1和QoS 2协议流，客户端和服务器需要将状态与客户端标识符相关联，这被称为会话状态。
     * 服务器还将订阅存储为会话状态的一部分。会话可以在一系列网络连接中继续。它的持续时间与最近的网络连接加上会话到期时间间隔一样长。客户端中的会话状态包括：
     * · QoS 1和QoS 2消息，已发送到服务器，但尚未协同发送
     * · 已从服务器接收但尚未完全确认的QoS 2消息。
     * <p>
     * 服务器中的会话状态包括：
     * <p>
     * · 会话的存在，即使会话状态的其余部分为空。
     * · 客户端订阅，包括任何订阅标识符。
     * · 已发送到客户端但尚未完全确认的QoS 1和QoS 2消息。
     * · 待传输到客户端的QoS 1和QoS 2消息以及待传输到客户机的可选QoS 0消息。
     * · 已从客户端接收到但尚未完全确认的QoS 2消息。遗嘱信息和遗嘱延迟间隔
     * · 如果会话当前未连接，则会话结束的时间和会话状态将被丢弃。
     * <p>
     * 保留的消息不构成服务器中会话状态的一部分，它们不会因会话结束而被删除。
     */
    private Boolean cleanStart = false;
    /**
     * 设置会话超时间隔。该值以秒为单位，定义了客户端断开连接后，代理服务器保持会话的最大时长。客户端仅在计划稍后重新连接时，才应设置较长的会话超时间隔。
     * <p>
     * 默认情况下，此值为空且不会发送，此时会话不会过期。
     * 若发送0，则在网络连接关闭后会话将立即终止。
     * <p>
     * 当客户端确定不再需要该会话时，应以会话过期间隔设为0的方式断开连接。
     */
    private Duration sessionExpiryInterval = Duration.ofSeconds(600);
    /**
     * 默认的主题。如果消息中不存在 mqtt_topic 头，则使用该值作为默认主题。
     */
    private String topicHeader = MqttHeaders.RECEIVED_TOPIC;
    /**
     * 用于确定目标主题的表达式。默认值：headers['mqtt_topic']
     */
    private String topicExpression = "headers['mqtt_topic']";
    /**
     * 默认的 Qos 级别，默认值为：1
     */
    private Integer defaultQos = 1;
    /**
     * 最大允许数据包大小。单位字节，默认值 1MB
     */
    private Long maximumPacketSize = 1048576L;
    /**
     * 默认订阅的主题
     */
    private List<String> defaultSubscribes = List.of("herodotus.mqtt");

    public List<String> getServerUrls() {
        return serverUrls;
    }

    public void setServerUrls(List<String> serverUrls) {
        this.serverUrls = serverUrls;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getClientId() {
        return clientId;
    }

    public void setClientId(String clientId) {
        this.clientId = clientId;
    }

    public Duration getKeepAliveInterval() {
        return keepAliveInterval;
    }

    public void setKeepAliveInterval(Duration keepAliveInterval) {
        this.keepAliveInterval = keepAliveInterval;
    }

    public Boolean getAutomaticReconnect() {
        return automaticReconnect;
    }

    public void setAutomaticReconnect(Boolean automaticReconnect) {
        this.automaticReconnect = automaticReconnect;
    }

    public Duration getAutomaticReconnectMinDelay() {
        return automaticReconnectMinDelay;
    }

    public void setAutomaticReconnectMinDelay(Duration automaticReconnectMinDelay) {
        this.automaticReconnectMinDelay = automaticReconnectMinDelay;
    }

    public Duration getAutomaticReconnectMaxDelay() {
        return automaticReconnectMaxDelay;
    }

    public void setAutomaticReconnectMaxDelay(Duration automaticReconnectMaxDelay) {
        this.automaticReconnectMaxDelay = automaticReconnectMaxDelay;
    }

    public Boolean getCleanStart() {
        return cleanStart;
    }

    public void setCleanStart(Boolean cleanStart) {
        this.cleanStart = cleanStart;
    }

    public Duration getSessionExpiryInterval() {
        return sessionExpiryInterval;
    }

    public void setSessionExpiryInterval(Duration sessionExpiryInterval) {
        this.sessionExpiryInterval = sessionExpiryInterval;
    }

    public String getTopicHeader() {
        return topicHeader;
    }

    public void setTopicHeader(String topicHeader) {
        this.topicHeader = topicHeader;
    }

    public String getTopicExpression() {
        return topicExpression;
    }

    public void setTopicExpression(String topicExpression) {
        this.topicExpression = topicExpression;
    }

    public Integer getDefaultQos() {
        return defaultQos;
    }

    public void setDefaultQos(Integer defaultQos) {
        this.defaultQos = defaultQos;
    }

    public Long getMaximumPacketSize() {
        return maximumPacketSize;
    }

    public void setMaximumPacketSize(Long maximumPacketSize) {
        this.maximumPacketSize = maximumPacketSize;
    }

    public List<String> getDefaultSubscribes() {
        return defaultSubscribes;
    }

    public void setDefaultSubscribes(List<String> defaultSubscribes) {
        this.defaultSubscribes = defaultSubscribes;
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .add("username", username)
                .add("password", password)
                .add("clientId", clientId)
                .add("keepAliveInterval", keepAliveInterval)
                .add("automaticReconnect", automaticReconnect)
                .add("automaticReconnectMinDelay", automaticReconnectMinDelay)
                .add("automaticReconnectMaxDelay", automaticReconnectMaxDelay)
                .add("cleanStart", cleanStart)
                .add("sessionExpiryInterval", sessionExpiryInterval)
                .add("topicHeader", topicHeader)
                .add("topicExpression", topicExpression)
                .add("defaultQos", defaultQos)
                .add("maximumPacketSize", maximumPacketSize)
                .toString();
    }
}
