package com.lingniu.ingest.analyticsapp;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lingniu.ingest.api.consumer.EnvelopeConsumerProcessor;
import com.lingniu.ingest.sink.kafka.KafkaEnvelopeDeadLetterSink;
import com.lingniu.ingest.sink.kafka.KafkaEventSink;
import com.lingniu.ingest.sink.kafka.KafkaSinkAutoConfiguration;
import com.lingniu.ingest.vehiclestat.JdbcVehicleStatMetricRepository;
import com.lingniu.ingest.vehiclestat.VehicleStatController;
import com.lingniu.ingest.vehiclestat.VehicleStatEnvelopeIngestor;
import com.lingniu.ingest.vehiclestat.VehicleStatRepository;
import com.lingniu.ingest.vehiclestat.config.VehicleStatAutoConfiguration;
import com.lingniu.ingest.vehiclestat.jt808.Jt808MileageStreamProcessor;
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.jdbc.core.JdbcTemplate;
import org.springframework.util.ClassUtils;

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

class VehicleAnalyticsAppCompositionTest {

    @Test
    void createsStatsBeansWithoutProtocolListenerOrFileHistoryStore() {
        new ApplicationContextRunner()
                .withConfiguration(AutoConfigurations.of(
                        KafkaSinkAutoConfiguration.class,
                        VehicleStatAutoConfiguration.class))
                .withAllowBeanDefinitionOverriding(true)
                .withBean("kafkaProducer", KafkaProducer.class, VehicleAnalyticsAppCompositionTest::kafkaProducer)
                .withBean(JdbcTemplate.class, () -> mock(JdbcTemplate.class))
                .withBean(ObjectMapper.class, ObjectMapper::new)
                .withPropertyValues(
                        "lingniu.ingest.sink.kafka.enabled=true",
                        "lingniu.ingest.sink.kafka.bootstrap-servers=localhost:9092",
                        "lingniu.ingest.sink.kafka.consumer.enabled=false",
                        "lingniu.ingest.vehicle-stat.enabled=true",
                        "lingniu.ingest.vehicle-stat.jt808.enabled=true")
                .run(context -> {
                    assertThat(context).hasSingleBean(VehicleStatRepository.class);
                    assertThat(context).hasSingleBean(JdbcVehicleStatMetricRepository.class);
                    assertThat(context).hasSingleBean(Jt808MileageStreamProcessor.class);
                    assertThat(context).hasSingleBean(VehicleStatEnvelopeIngestor.class);
                    assertThat(context).hasSingleBean(VehicleStatController.class);
                    assertThat(context).hasSingleBean(KafkaEventSink.class);
                    assertThat(context).hasSingleBean(KafkaEnvelopeDeadLetterSink.class);
                    assertThat(context).hasBean("vehicleStatEnvelopeConsumerProcessor");
                    assertThat(context.getBean("vehicleStatEnvelopeConsumerProcessor"))
                            .isInstanceOf(EnvelopeConsumerProcessor.class);

                    assertTypeNotPresent(context, "com.lingniu.ingest.vehiclestate.VehicleStateEnvelopeIngestor");
                    assertTypeNotPresent(context, "com.lingniu.ingest.vehiclestate.config.VehicleStateAutoConfiguration");
                    assertTypeNotPresent(context, "com.lingniu.ingest.protocol.gb32960.inbound.Gb32960NettyServer");
                    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 vehicle analytics runtime", className)
                .isFalse();
    }
}
