package org.dromara.mqtt;

import cn.hutool.extra.spring.SpringUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.dromara.app.domain.mqtt.DeviceCommand;
import org.dromara.mqtt.config.properties.MqttProperties;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.GenericApplicationContext;

import java.util.function.Supplier;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.springframework.test.util.ReflectionTestUtils.invokeMethod;

@Tag("dev")
class DeviceMqttCommandPublisherTest {

    private static GenericApplicationContext applicationContext;

    @BeforeAll
    static void initializeJsonUtils() {
        applicationContext = new GenericApplicationContext();
        applicationContext.registerBean(ObjectMapper.class, (Supplier<ObjectMapper>) ObjectMapper::new);
        applicationContext.refresh();
        new SpringUtil().setApplicationContext(applicationContext);
    }

    @AfterAll
    static void closeApplicationContext() {
        applicationContext.close();
    }

    @Test
    void buildCommandTopicDefaultsToDeviceNo() {
        MqttProperties properties = new MqttProperties();
        DeviceMqttCommandPublisher publisher = new DeviceMqttCommandPublisher(
            null,
            null,
            properties
        );

        String topic = invokeMethod(publisher, "buildCommandTopic", "D01");

        assertThat(topic).isEqualTo("/d01/subscriber/cmd");
    }

    @Test
    void sendSchedulesFirstRetryTenSecondsAfterInitialPublish() {
        DeviceMqttCommandPublisher publisher = new DeviceMqttCommandPublisher(
            mock(MqttClientManager.class),
            mock(MqttCommandAckService.class),
            new MqttProperties()
        );
        DeviceCommand command = new DeviceCommand();
        command.setDeviceNo("D01");
        command.setCommandType("switch");

        publisher.send(command);

        assertThat(command.getNextRetryAt() - command.getLastSentAt()).isEqualTo(10000);
    }
}
