package com.lutao.cloud.iot.mqtt.spring.server;

import com.lutao.cloud.iot.mqtt.core.server.MqttServer;
import com.lutao.cloud.iot.mqtt.core.server.MqttServerCreator;
import com.lutao.cloud.iot.mqtt.core.server.auth.IMqttServerAuthHandler;
import com.lutao.cloud.iot.mqtt.core.server.auth.IMqttServerSubscribeValidator;
import com.lutao.cloud.iot.mqtt.core.server.auth.IMqttServerUniqueIdService;
import com.lutao.cloud.iot.mqtt.core.server.dispatcher.IMqttMessageDispatcher;
import com.lutao.cloud.iot.mqtt.core.server.event.IMqttConnectStatusListener;
import com.lutao.cloud.iot.mqtt.core.server.event.IMqttMessageListener;
import com.lutao.cloud.iot.mqtt.core.server.session.IMqttSessionManager;
import com.lutao.cloud.iot.mqtt.core.server.store.IMqttMessageStore;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.tio.core.stat.IpStatListener;
import org.tio.utils.hutool.StrUtil;

import java.util.Objects;

/**
 * mqtt server 配置
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(
        prefix = MqttServerProperties.PREFIX,
        name = "enabled",
        havingValue = "true",
        matchIfMissing = true
)
@EnableConfigurationProperties(MqttServerProperties.class)
@Slf4j
public class MqttServerConfiguration {

    @Bean
    public MqttServerCreator mqttServerCreator(MqttServerProperties properties,
                                               ObjectProvider<IMqttServerAuthHandler> authHandlerObjectProvider,
                                               ObjectProvider<IMqttServerUniqueIdService> uniqueIdServiceObjectProvider,
                                               ObjectProvider<IMqttServerSubscribeValidator> subscribeValidatorObjectProvider,
                                               ObjectProvider<IMqttMessageDispatcher> messageDispatcherObjectProvider,
                                               ObjectProvider<IMqttMessageStore> messageStoreObjectProvider,
                                               ObjectProvider<IMqttSessionManager> sessionManagerObjectProvider,
                                               ObjectProvider<IMqttMessageListener> messageListenerObjectProvider,
                                               ObjectProvider<IMqttConnectStatusListener> connectStatusListenerObjectProvider,
                                               ObjectProvider<IpStatListener> ipStatListenerObjectProvider,
                                               ObjectProvider<MqttServerCustomizer> customizers) {

        MqttServerCreator serverCreator = MqttServer.create()
                .name(properties.getName())
                .ip(properties.getIp())
                .port(properties.getPort())
                .heartbeatTimeout(properties.getHeartbeatTimeout())
                .readBufferSize(properties.getReadBufferSize())
                .maxBytesInMessage(properties.getMaxBytesInMessage())
                .bufferAllocator(properties.getBufferAllocator())
                .maxClientIdLength(properties.getMaxClientIdLength())
                .webPort(properties.getWebPort())
                .websocketEnable(properties.isWebsocketEnable())
                .httpEnable(properties.isHttpEnable())
                .nodeName(properties.getNodeName());
        if (properties.isDebug()) {
            serverCreator.debug();
        }
        MqttServerProperties.HttpBasicAuth httpBasicAuth = properties.getHttpBasicAuth();
        if (serverCreator.isHttpEnable() && httpBasicAuth.isEnable()) {
            serverCreator.httpBasicAuth(httpBasicAuth.getUsername(), httpBasicAuth.getPassword());
        }

        MqttServerProperties.Ssl ssl = properties.getSsl();
        String keyStorePath = ssl.getKeyStorePath();
        String trustStorePath = ssl.getTrustStorePath();
        String password = ssl.getPassword();

        // ssl 配置
        log.info("-----------ssl{}{}{}", keyStorePath,trustStorePath,password);
        if (StrUtil.isNotBlank(keyStorePath) && StrUtil.isNotBlank(trustStorePath) && StrUtil.isNotBlank(password)) {
            log.info("-----------ssl{}{}", ssl.getKeyStorePath(),ssl.getTrustStorePath());
            serverCreator.useSsl(keyStorePath, trustStorePath, password);
        }
        // bean 初始化
        IMqttMessageListener messageListener = messageListenerObjectProvider.getIfAvailable();
        // 消息监听器不能为 null
        Objects.requireNonNull(messageListener, "Mqtt server IMqttMessageListener Bean not found.");
        serverCreator.messageListener(messageListener);
        // 认证处理器
        authHandlerObjectProvider.ifAvailable(serverCreator::authHandler);
        // mqtt 内唯一id
        uniqueIdServiceObjectProvider.ifAvailable(serverCreator::uniqueIdService);
        // 订阅校验
        subscribeValidatorObjectProvider.ifAvailable(serverCreator::subscribeValidator);
        // 消息转发
        messageDispatcherObjectProvider.ifAvailable(serverCreator::messageDispatcher);
        // 消息存储
        messageStoreObjectProvider.ifAvailable(serverCreator::messageStore);
        // session 管理
        sessionManagerObjectProvider.ifAvailable(serverCreator::sessionManager);
        // 状态监听
        connectStatusListenerObjectProvider.ifAvailable(serverCreator::connectStatusListener);
        // ip 状态监听
        ipStatListenerObjectProvider.ifAvailable(serverCreator::ipStatListener);
        // 自定义处理
        customizers.ifAvailable((customizer) -> customizer.customize(serverCreator));
        return serverCreator;
    }

    @Bean
    public MqttServer mqttServer(MqttServerCreator mqttServerCreator) {
        return mqttServerCreator.build();
    }

    @Bean
    public MqttServerLauncher mqttServerLauncher(MqttServer mqttServer) {
        return new MqttServerLauncher(mqttServer);
    }

    @Bean
    public MqttServerTemplate mqttServerTemplate(MqttServer mqttServer) {
        return new MqttServerTemplate(mqttServer);
    }

}
