package at.procon.eventhub.tachograph.service;

import at.procon.eventhub.config.EventHubProperties;
import at.procon.eventhub.dto.EventFamily;
import at.procon.eventhub.dto.EventSourceDto;
import at.procon.eventhub.dto.ImportScopeDto;
import at.procon.eventhub.importing.ImportChunkPlanner;
import at.procon.eventhub.service.EventDetailsFactory;
import at.procon.eventhub.tachograph.dto.TachographImportRequest;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.EnumSet;
import java.util.List;
import org.junit.jupiter.api.Test;

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

class TachographImportPlanServiceTest {

    private final EventDetailsFactory detailsFactory = new EventDetailsFactory(new ObjectMapper());
    private final TachographExtractionDefinitionRegistry definitionRegistry = new TachographExtractionDefinitionRegistry(
            new CardActivityRowMapper(detailsFactory),
            new VuActivityRowMapper(detailsFactory),
            new IwCycleCardEventRowMapper(detailsFactory),
            new CardVehiclesUsedCardEventRowMapper(detailsFactory),
            new VuBorderCrossingRowMapper(detailsFactory),
            new CardBorderCrossingRowMapper(detailsFactory),
            new VuLoadUnloadRowMapper(detailsFactory),
            new CardLoadUnloadRowMapper(detailsFactory),
            new VuSpecificConditionRowMapper(detailsFactory),
            new CardSpecificConditionRowMapper(detailsFactory),
            new VuPositionRowMapper(detailsFactory),
            new CardPositionRowMapper(detailsFactory),
            new VuPlaceRowMapper(detailsFactory),
            new CardPlaceRowMapper(detailsFactory),
            new SpeedingEventRowMapper(detailsFactory)
    );

    @Test
    void allowsSupportedDriverActivityFamilyWhenJdbcExtractionIsEnabled() {
        TachographImportPlanService service = serviceWithJdbcExtractor();
        TachographImportRequest request = requestForFamilies(EventFamily.DRIVER_ACTIVITY);

        var plan = service.createPlan(request);

        assertThat(plan.items())
                .extracting(item -> item.extractionCode())
                .containsExactlyInAnyOrder("VU_ACTIVITY", "CARD_ACTIVITY");
    }

    @Test
    void allowsSupportedDriverCardFamilyWhenJdbcExtractionIsEnabled() {
        TachographImportPlanService service = serviceWithJdbcExtractor();
        TachographImportRequest request = requestForFamilies(EventFamily.DRIVER_CARD);

        var plan = service.createPlan(request);

        assertThat(plan.items())
                .extracting(item -> item.extractionCode())
                .containsExactlyInAnyOrder("IW_CYCLE", "CARD_VEHICLES_USED");
    }

    @Test
    void allowsSupportedBorderCrossingFamilyWhenJdbcExtractionIsEnabled() {
        TachographImportPlanService service = serviceWithJdbcExtractor();
        TachographImportRequest request = requestForFamilies(EventFamily.BORDER_CROSSING);

        var plan = service.createPlan(request);

        assertThat(plan.items())
                .extracting(item -> item.extractionCode())
                .containsExactlyInAnyOrder("VU_BORDER_CROSSING", "CARD_BORDER_CROSSING");
    }

    @Test
    void allowsSupportedLoadUnloadFamilyWhenJdbcExtractionIsEnabled() {
        TachographImportPlanService service = serviceWithJdbcExtractor();
        TachographImportRequest request = requestForFamilies(EventFamily.LOAD_UNLOAD);

        var plan = service.createPlan(request);

        assertThat(plan.items())
                .extracting(item -> item.extractionCode())
                .containsExactlyInAnyOrder("VU_LOAD_UNLOAD", "CARD_LOAD_UNLOAD");
    }

    @Test
    void allowsSupportedSpecificConditionFamilyWhenJdbcExtractionIsEnabled() {
        TachographImportPlanService service = serviceWithJdbcExtractor();
        TachographImportRequest request = requestForFamilies(EventFamily.SPECIFIC_CONDITION);

        var plan = service.createPlan(request);

        assertThat(plan.items())
                .extracting(item -> item.extractionCode())
                .containsExactlyInAnyOrder("VU_SPECIFIC_CONDITION", "CARD_SPECIFIC_CONDITION");
    }

    @Test
    void allowsSupportedPositionFamilyWhenJdbcExtractionIsEnabled() {
        TachographImportPlanService service = serviceWithJdbcExtractor();
        TachographImportRequest request = requestForFamilies(EventFamily.POSITION);

        var plan = service.createPlan(request);

        assertThat(plan.items())
                .extracting(item -> item.extractionCode())
                .containsExactlyInAnyOrder("VU_POSITION", "CARD_POSITION");
    }

    @Test
    void allowsSupportedPlaceFamilyWhenJdbcExtractionIsEnabled() {
        TachographImportPlanService service = serviceWithJdbcExtractor();
        TachographImportRequest request = requestForFamilies(EventFamily.PLACE);

        var plan = service.createPlan(request);

        assertThat(plan.items())
                .extracting(item -> item.extractionCode())
                .containsExactlyInAnyOrder("VU_PLACE", "CARD_PLACE");
    }

    @Test
    void allowsSupportedSpeedingFamilyWhenJdbcExtractionIsEnabled() {
        TachographImportPlanService service = serviceWithJdbcExtractor();
        TachographImportRequest request = requestForFamilies(EventFamily.SPEEDING);

        var plan = service.createPlan(request);

        assertThat(plan.items())
                .extracting(item -> item.extractionCode())
                .containsExactly("SPEEDING_EVENTS");
    }

    private TachographImportPlanService serviceWithJdbcExtractor() {
        EventHubProperties properties = new EventHubProperties();
        properties.getTachograph().getDatasource().setJdbcUrl("jdbc:sqlserver://tachograph-db");
        return new TachographImportPlanService(properties, new ImportChunkPlanner(), definitionRegistry);
    }

    private TachographImportRequest requestForFamilies(EventFamily... families) {
        EnumSet<EventFamily> selectedFamilies = families.length == 0
                ? EnumSet.noneOf(EventFamily.class)
                : EnumSet.copyOf(List.of(families));
        return new TachographImportRequest(
                "tenant-1",
                new EventSourceDto("TACHOGRAPH", "MIXED", "TACHOGRAPH_DB", "tachograph-db", null, null),
                null,
                ImportScopeDto.tenantAll(null, null),
                selectedFamilies,
                null,
                false,
                null
        );
    }
}
