package at.procon.dip.domain.ted.startup;

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

import at.procon.dip.domain.ted.config.TedProjectionProperties;
import at.procon.dip.domain.ted.entity.TedNoticeProjection;
import at.procon.dip.domain.ted.repository.TedNoticeProjectionRepository;
import at.procon.dip.domain.ted.service.TedLotDocumentMaterializationService;
import at.procon.dip.domain.ted.service.TedNoticeProjectionService;
import at.procon.ted.model.entity.ProcurementDocument;
import at.procon.ted.repository.ProcurementDocumentRepository;
import java.util.List;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;

@ExtendWith(MockitoExtension.class)
class TedProjectionStartupRunnerTest {

    @Mock
    private ProcurementDocumentRepository procurementDocumentRepository;
    @Mock
    private TedNoticeProjectionRepository projectionRepository;
    @Mock
    private TedNoticeProjectionService projectionService;
    @Mock
    private TedLotDocumentMaterializationService lotDocumentMaterializationService;

    private TedProjectionProperties properties;
    private TedProjectionStartupRunner runner;

    @BeforeEach
    void setUp() {
        properties = new TedProjectionProperties();
        runner = new TedProjectionStartupRunner(
                properties,
                procurementDocumentRepository,
                projectionRepository,
                projectionService,
                lotDocumentMaterializationService
        );
    }

    @Test
    void lotDocumentBackfillTreatsZeroLimitAsUnboundedBatch() {
        properties.getLotDocuments().setEnabled(true);
        properties.getLotDocuments().setStartupBackfillEnabled(true);
        properties.getLotDocuments().setStartupBackfillLimit(0);

        UUID projectionId = UUID.randomUUID();
        TedNoticeProjection projection = new TedNoticeProjection();
        projection.setId(projectionId);

        when(projectionRepository.findAll(any(Pageable.class)))
                .thenAnswer(invocation -> new PageImpl<>(List.of(projection), invocation.getArgument(0), 1));
        when(lotDocumentMaterializationService.materializeProjectionLots(projectionId)).thenReturn(2);

        runner.run(null);

        ArgumentCaptor<Pageable> pageable = ArgumentCaptor.forClass(Pageable.class);
        verify(projectionRepository).findAll(pageable.capture());
        assertThat(pageable.getValue().getPageSize()).isEqualTo(1000);
        verify(lotDocumentMaterializationService).materializeProjectionLots(projectionId);
    }

    @Test
    void noticeProjectionBackfillTreatsZeroLimitAsUnboundedBatch() {
        properties.setStartupBackfillEnabled(true);
        properties.setStartupBackfillLimit(0);

        UUID legacyDocumentId = UUID.randomUUID();
        ProcurementDocument legacyDocument = new ProcurementDocument();
        legacyDocument.setId(legacyDocumentId);

        when(procurementDocumentRepository.findAll(any(Pageable.class)))
                .thenAnswer(invocation -> new PageImpl<>(List.of(legacyDocument), invocation.getArgument(0), 1));
        when(projectionRepository.existsByLegacyProcurementDocumentId(legacyDocumentId)).thenReturn(false);

        runner.run(null);

        ArgumentCaptor<Pageable> pageable = ArgumentCaptor.forClass(Pageable.class);
        verify(procurementDocumentRepository).findAll(pageable.capture());
        assertThat(pageable.getValue().getPageSize()).isEqualTo(1000);
        verify(projectionService).registerOrRefreshProjection(legacyDocument);
    }
}
