package com.lingniu.ingest.jt808app;

import com.lingniu.ingest.core.config.IngestCoreAutoConfiguration;
import com.lingniu.ingest.identity.MySqlVehicleIdentityService;
import com.lingniu.ingest.identity.config.VehicleIdentityAutoConfiguration;
import com.lingniu.ingest.protocol.jt808.codec.Jt808MessageDecoder;
import com.lingniu.ingest.protocol.jt808.config.Jt808AutoConfiguration;
import com.lingniu.ingest.protocol.jt808.inbound.Jt808NettyServer;
import com.lingniu.ingest.session.SessionStore;
import com.lingniu.ingest.session.config.SessionCoreAutoConfiguration;
import com.lingniu.ingest.sink.archive.ArchiveStore;
import com.lingniu.ingest.sink.archive.RawArchiveEventSink;
import com.lingniu.ingest.sink.archive.config.SinkArchiveAutoConfiguration;
import com.lingniu.ingest.sink.kafka.KafkaEnvelopeDeadLetterSink;
import com.lingniu.ingest.sink.kafka.KafkaEventSink;
import com.lingniu.ingest.sink.kafka.KafkaSinkAutoConfiguration;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.util.ClassUtils;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

class Jt808IngestAppCompositionTest {

    private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
            .withConfiguration(AutoConfigurations.of(
                    IngestCoreAutoConfiguration.class,
                    SessionCoreAutoConfiguration.class,
                    VehicleIdentityAutoConfiguration.class,
                    KafkaSinkAutoConfiguration.class,
                    SinkArchiveAutoConfiguration.class,
                    Jt808AutoConfiguration.class))
            .withAllowBeanDefinitionOverriding(true)
            .withBean("kafkaProducer", KafkaProducer.class, Jt808IngestAppCompositionTest::kafkaProducer)
            .withBean(SessionStore.class, () -> mock(SessionStore.class))
            .withPropertyValues(
                    "lingniu.ingest.jt808.enabled=true",
                    "lingniu.ingest.jt808.port=0",
                    "lingniu.ingest.identity.store=mysql",
                    "lingniu.ingest.identity.mysql.initialize-schema=false",
                    "lingniu.ingest.sink.kafka.enabled=true",
                    "lingniu.ingest.sink.kafka.bootstrap-servers=localhost:9092",
                    "lingniu.ingest.sink.kafka.consumer.enabled=false",
                    "lingniu.ingest.sink.archive.enabled=true",
                    "lingniu.ingest.sink.archive.path=target/test-archive-jt808",
                    "lingniu.ingest.event-history.enabled=false");

    @Test
    void createsJt808ListenerWithoutHistoryStorageBoundaries() {
        contextRunner.run(context -> {
            assertThat(context).hasSingleBean(Jt808MessageDecoder.class);
            assertThat(context).hasSingleBean(Jt808NettyServer.class);
            assertThat(context).hasSingleBean(MySqlVehicleIdentityService.class);
            assertThat(context).hasSingleBean(KafkaEventSink.class);
            assertThat(context).hasSingleBean(KafkaEnvelopeDeadLetterSink.class);
            assertThat(context).hasSingleBean(ArchiveStore.class);
            assertThat(context).hasSingleBean(RawArchiveEventSink.class);

            assertTypeNotPresent(context, "com.lingniu.ingest.eventfilestore.DuckDbParquetEventFileStore");
            assertTypeNotPresent(context, "com.lingniu.ingest.eventfilestore.config.EventFileStoreAutoConfiguration");
        });
    }

    @SuppressWarnings("unchecked")
    private static KafkaProducer<String, byte[]> kafkaProducer() {
        return mock(KafkaProducer.class);
    }

    private static void assertTypeNotPresent(ApplicationContext context, String className) {
        assertThat(ClassUtils.isPresent(className, context.getClassLoader()))
                .as("%s must stay outside the JT808 ingest runtime", className)
                .isFalse();
    }
}
