package at.procon.eventhub.importing.extraction;

import at.procon.eventhub.config.EventHubProperties;
import at.procon.eventhub.dto.AcquisitionStrategy;
import at.procon.eventhub.dto.EventFamily;
import at.procon.eventhub.dto.EventSourceDto;
import at.procon.eventhub.dto.ImportCursorStateDto;
import at.procon.eventhub.dto.ImportMode;
import at.procon.eventhub.dto.ImportScopeDto;
import at.procon.eventhub.importing.ExtractionBatchResult;
import at.procon.eventhub.importing.ImportPlanItemDto;
import at.procon.eventhub.importing.ImportRunRequest;
import at.procon.eventhub.importing.ImportTimeChunkDto;
import at.procon.eventhub.importing.persistence.ImportCursorRepository;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import org.junit.jupiter.api.Test;

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

class AbstractJdbcExtractionBatchExecutorCursorTest {

    @Test
    void bootstrapsWatermarkCursorFromLatestExistingCursorWhenExactCursorIsMissing() {
        ImportCursorRepository repository = mock(ImportCursorRepository.class);
        TestExecutor executor = new TestExecutor(repository);
        TestRequest request = new TestRequest();
        ImportPlanItemDto planItem = new ImportPlanItemDto(
                EventFamily.DRIVER_ACTIVITY,
                "VEHICLE_UNIT",
                "VU_ACTIVITY",
                List.of("VUActivity"),
                "VEHICLE",
                "Vehicle activity",
                AcquisitionStrategy.SOURCE_ROW_WATERMARK
        );
        ImportCursorStateDto fallbackCursor = new ImportCursorStateDto(
                null,
                "9001",
                null,
                OffsetDateTime.parse("2026-04-09T23:59:59+02:00")
        );

        when(repository.findCursor(
                "tenant-1",
                21,
                request.importScope().stableKey(),
                EventFamily.DRIVER_ACTIVITY,
                "VEHICLE_UNIT",
                AcquisitionStrategy.SOURCE_ROW_WATERMARK
        )).thenReturn(null);
        when(repository.findLatestCursor(
                "tenant-1",
                21,
                request.importScope().stableKey(),
                EventFamily.DRIVER_ACTIVITY,
                "VEHICLE_UNIT"
        )).thenReturn(fallbackCursor);

        assertThat(executor.resolveCursor(21, request, planItem)).isEqualTo(fallbackCursor);

        verify(repository).findLatestCursor(
                "tenant-1",
                21,
                request.importScope().stableKey(),
                EventFamily.DRIVER_ACTIVITY,
                "VEHICLE_UNIT"
        );
    }

    private static final class TestExecutor extends AbstractJdbcExtractionBatchExecutor<TestRequest, TestResult> {

        private TestExecutor(ImportCursorRepository repository) {
            super(null, null, null, new EventHubProperties(), null, repository);
        }

        private ImportCursorStateDto resolveCursor(int eventSourceId, TestRequest request, ImportPlanItemDto planItem) {
            return findCursor(eventSourceId, request, planItem);
        }

        @Override
        protected Optional<ExtractionDefinition<TestRequest>> findDefinition(String code) {
            return Optional.empty();
        }

        @Override
        protected EventSourceDto eventSourceFor(TestRequest request, ImportPlanItemDto planItem) {
            return request.eventSource();
        }

        @Override
        protected TestResult resultFor(UUID packageId, ImportPlanItemDto planItem, ImportTimeChunkDto chunk, ImportCursorStateDto cursor, ExtractedEventStats stats) {
            return new TestResult();
        }
    }

    private record TestRequest() implements ImportRunRequest {

        @Override
        public String tenantKey() {
            return "tenant-1";
        }

        @Override
        public EventSourceDto eventSource() {
            return new EventSourceDto("TACHOGRAPH", "VEHICLE_UNIT", "TACHOGRAPH_VEHICLE_UNIT", "instance-1", "setting-1", null);
        }

        @Override
        public at.procon.eventhub.dto.SourceGroupRefDto sourceGroup() {
            return null;
        }

        @Override
        public ImportScopeDto importScope() {
            return ImportScopeDto.tenantAll(
                    OffsetDateTime.parse("2026-04-01T00:00:00+02:00"),
                    OffsetDateTime.parse("2026-04-10T00:00:00+02:00")
            );
        }

        @Override
        public Set<EventFamily> eventFamilies() {
            return Set.of(EventFamily.DRIVER_ACTIVITY);
        }

        @Override
        public ImportMode mode() {
            return ImportMode.INCREMENTAL_UPDATE;
        }

        @Override
        public boolean refreshMasterDataFirst() {
            return false;
        }

        @Override
        public AcquisitionStrategy acquisitionStrategy() {
            return AcquisitionStrategy.SOURCE_ROW_WATERMARK;
        }
    }

    private static final class TestResult implements ExtractionBatchResult {

        @Override
        public int eventsInserted() {
            return 0;
        }

        @Override
        public boolean executed() {
            return false;
        }

        @Override
        public OffsetDateTime lastSourcePackageImportedAt() {
            return null;
        }

        @Override
        public String lastSourcePackageId() {
            return null;
        }

        @Override
        public OffsetDateTime lastSourceRowUpdatedAt() {
            return null;
        }

        @Override
        public OffsetDateTime lastOccurredTo() {
            return null;
        }

        @Override
        public Map<String, Integer> eventTypeCounts() {
            return Map.of();
        }
    }
}
