package com.lingniu.ingest.vehiclestat.config;

import com.lingniu.ingest.api.consumer.EnvelopeConsumerProcessor;
import com.lingniu.ingest.api.consumer.EnvelopeDeadLetterSink;
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.jt808.Jt808MileageStreamProcessor;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;

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

class VehicleStatAutoConfigurationTest {

    private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
            .withConfiguration(AutoConfigurations.of(VehicleStatAutoConfiguration.class))
            .withBean(EnvelopeDeadLetterSink.class, () -> record -> {});

    @Test
    void createsOnlyMetricRepositoryAndReadControllerWhenJt808MileageDisabled() {
        contextRunner
                .withBean(JdbcTemplate.class, () -> mock(JdbcTemplate.class))
                .withPropertyValues("lingniu.ingest.vehicle-stat.enabled=true")
                .run(context -> {
                    assertThat(context).hasSingleBean(VehicleStatRepository.class);
                    assertThat(context).hasSingleBean(JdbcVehicleStatMetricRepository.class);
                    assertThat(context).hasSingleBean(VehicleStatController.class);
                    assertThat(context).doesNotHaveBean(Jt808MileageStreamProcessor.class);
                    assertThat(context).doesNotHaveBean(VehicleStatEnvelopeIngestor.class);
                    assertThat(context).doesNotHaveBean(EnvelopeConsumerProcessor.class);
                });
    }

    @Test
    void backsOffWhenDisabled() {
        contextRunner.run(context -> {
            assertThat(context).doesNotHaveBean(VehicleStatRepository.class);
            assertThat(context).doesNotHaveBean(VehicleStatEnvelopeIngestor.class);
        });
    }

    @Test
    void doesNotCreateRepositoryWithoutJdbcMetricStore() {
        new ApplicationContextRunner()
                .withConfiguration(AutoConfigurations.of(VehicleStatAutoConfiguration.class))
                .withPropertyValues("lingniu.ingest.vehicle-stat.enabled=true")
                .run(context -> {
                    assertThat(context).doesNotHaveBean(VehicleStatRepository.class);
                    assertThat(context).doesNotHaveBean(VehicleStatController.class);
                });
    }

    @Test
    void createsJt808MileageBeansWhenEnabledWithMetricRepositoryOnly() {
        contextRunner
                .withBean(JdbcTemplate.class, () -> mock(JdbcTemplate.class))
                .withPropertyValues(
                        "lingniu.ingest.vehicle-stat.enabled=true",
                        "lingniu.ingest.vehicle-stat.jt808.enabled=true")
                .run(context -> {
                    assertThat(context).hasSingleBean(Jt808MileageStreamProcessor.class);
                    assertThat(context).hasSingleBean(VehicleStatEnvelopeIngestor.class);
                    assertThat(context).hasSingleBean(EnvelopeConsumerProcessor.class);
                });
    }

    @Test
    void rejectsLegacyStateStorePropertyInsteadOfCreatingHiddenRuntimeMode() {
        contextRunner
                .withBean(JdbcTemplate.class, () -> mock(JdbcTemplate.class))
                .withPropertyValues(
                        "lingniu.ingest.vehicle-stat.enabled=true",
                        "lingniu.ingest.vehicle-stat.jt808.enabled=true",
                        "lingniu.ingest.vehicle-stat.jt808.state-store=memory")
                .run(context -> assertThat(context.getStartupFailure())
                        .hasRootCauseInstanceOf(IllegalStateException.class)
                        .hasMessageContaining("vehicle-stat.jt808.state-store has been removed")
                        .hasMessageContaining("vehicle_stat_metric"));
    }

    @Test
    void createsJt808MileageBeansAfterJdbcAutoConfiguration() {
        new ApplicationContextRunner()
                .withConfiguration(AutoConfigurations.of(
                        JdbcTemplateAutoConfiguration.class,
                        VehicleStatAutoConfiguration.class))
                .withBean(EnvelopeDeadLetterSink.class, () -> record -> {})
                .withBean(DataSource.class, () -> new DriverManagerDataSource(
                        "jdbc:h2:mem:vehicle_stat_auto;MODE=MySQL;DATABASE_TO_LOWER=TRUE;DB_CLOSE_DELAY=-1",
                        "sa",
                        ""))
                .withPropertyValues(
                        "lingniu.ingest.vehicle-stat.enabled=true",
                        "lingniu.ingest.vehicle-stat.jt808.enabled=true")
                .run(context -> {
                    assertThat(context).hasSingleBean(JdbcTemplate.class);
                    assertThat(context).hasSingleBean(JdbcVehicleStatMetricRepository.class);
                    assertThat(context).hasSingleBean(Jt808MileageStreamProcessor.class);
                    assertThat(context).hasSingleBean(VehicleStatEnvelopeIngestor.class);
                    assertThat(context).hasSingleBean(EnvelopeConsumerProcessor.class);
                });
    }

}
