package com.lingniu.ingest.gateway;

import com.lingniu.ingest.session.CommandDispatcher;
import com.lingniu.ingest.session.DeviceSession;
import com.lingniu.ingest.session.SessionStore;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;

import java.time.Duration;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.UnaryOperator;

import static org.assertj.core.api.Assertions.assertThat;

class CommandGatewayAutoConfigurationTest {

    private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
            .withConfiguration(AutoConfigurations.of(CommandGatewayAutoConfiguration.class))
            .withBean(SessionStore.class, EmptySessionStore::new)
            .withBean(CommandDispatcher.class, NoopCommandDispatcher::new);

    @Test
    void backsOffByDefault() {
        contextRunner.run(context -> assertThat(context).doesNotHaveBean(TerminalCommandController.class));
    }

    @Test
    void createsControllerWhenExplicitlyEnabled() {
        contextRunner
                .withPropertyValues("lingniu.ingest.command-gateway.enabled=true")
                .run(context -> assertThat(context).hasSingleBean(TerminalCommandController.class));
    }

    private static final class NoopCommandDispatcher implements CommandDispatcher {
        @Override
        public CompletableFuture<Void> notify(String sessionId, Object command) {
            return CompletableFuture.completedFuture(null);
        }

        @Override
        public <T> CompletableFuture<T> request(String sessionId,
                                                Object command,
                                                Class<T> responseType,
                                                Duration timeout) {
            return CompletableFuture.failedFuture(new UnsupportedOperationException("not used"));
        }
    }

    private static final class EmptySessionStore implements SessionStore {
        @Override public void put(DeviceSession session) {}
        @Override public Optional<DeviceSession> findBySessionId(String sessionId) { return Optional.empty(); }
        @Override public Optional<DeviceSession> findByVin(String vin) { return Optional.empty(); }
        @Override public Optional<DeviceSession> findByPhone(String phone) { return Optional.empty(); }
        @Override public Optional<DeviceSession> update(String sessionId, UnaryOperator<DeviceSession> updater) {
            return Optional.empty();
        }
        @Override public void remove(String sessionId) {}
        @Override public int size() { return 0; }
    }
}
