package com.iqser.red.service.peristence.v1.server.integration.tests;

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

import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

import com.iqser.red.service.peristence.v1.server.integration.client.DossierClient;
import com.iqser.red.service.peristence.v1.server.integration.client.DossierStatsClient;
import com.iqser.red.service.peristence.v1.server.integration.client.FileClient;
import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider;
import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider;
import com.iqser.red.service.peristence.v1.server.integration.service.FileTesterAndProvider;
import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierStats;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus;
import com.knecon.fforesight.tenantcommons.TenantContext;

public class DossierStatsTest extends AbstractPersistenceServerServiceTest {

    private static final int NUMBER_PAGES_ANALYZED = 5;
    private static final OffsetDateTime NOW = OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS);
    private static final OffsetDateTime OLDER_1 = NOW.minusSeconds(5);
    private static final OffsetDateTime OLDER_2 = NOW.minusSeconds(15);

    @Autowired
    private DossierTemplateTesterAndProvider dossierTemplateTesterAndProvider;

    @Autowired
    private DossierTesterAndProvider dossierTesterAndProvider;

    @Autowired
    private FileTesterAndProvider fileTesterAndProvider;

    @Autowired
    private FileClient fileClient;

    @Autowired
    private DossierClient dossierClient;

    @Autowired
    private DossierStatsClient dossierStatsClient;

    private Dossier dossier1;
    private Dossier dossier2;


    @BeforeEach
    public void setupData() {
        TenantContext.setTenantId("redaction");
        var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();
        dossier1 = dossierTesterAndProvider.provideTestDossier(dossierTemplate);
        //provides 2 files
        var file1 = fileTesterAndProvider.testAndProvideFile(dossier1, "file1");
        var file2 = fileTesterAndProvider.testAndProvideFile(dossier1, "file2");

        assertThat(fileClient.getDossierStatus(dossier1.getId()).size()).isEqualTo(2);

        // alter file 1
        var loadedFile1 = fileClient.getFileStatus(dossier1.getId(), file1.getId());
        assertThat(loadedFile1.isHasRedactions()).isFalse();
        fileRepository.findById(file1.getId()).ifPresent((file) -> {
            file.setNumberOfPages(NUMBER_PAGES_ANALYZED);
            file.setHasRedactions(true);
            file.setHasHints(true);
            file.setHasUpdates(true);
            file.setLastUpdated(NOW);
            file.setFileManipulationDate(null);
            fileRepository.save(file);
        });
        loadedFile1 = fileClient.getFileStatus(dossier1.getId(), file1.getId());
        assertThat(loadedFile1.isHasRedactions()).isTrue();
        assertThat(loadedFile1.getLastUpdated()).isEqualTo(NOW);

        // alter file 2
        fileRepository.findById(file2.getId()).ifPresent((file) -> {
            file.setHasSuggestions(true);
            file.setLastUpdated(OLDER_1);
            file.setFileManipulationDate(OLDER_2);
            fileRepository.save(file);
        });

        // second dossier
        dossier2 = dossierTesterAndProvider.provideTestDossier(dossierTemplate, "Dossier2");
        var file3 = fileTesterAndProvider.testAndProvideFile(dossier2, "file3");
        var file4 = fileTesterAndProvider.testAndProvideFile(dossier2, "file4");
        //alter file 2
        fileRepository.findById(file3.getId()).ifPresent((file) -> {
            file.setLastUpdated(OLDER_1);
            file.setFileManipulationDate(null);
            fileRepository.save(file);
        });

        //alter file 4
        fileRepository.findById(file4.getId()).ifPresent((file) -> {
            file.setHasHints(true);
            file.setWorkflowStatus(WorkflowStatus.APPROVED);
            file.setLastUpdated(OLDER_2);
            file.setFileManipulationDate(OLDER_2);
            fileRepository.save(file);
        });
    }


    @Test
    public void testDossierStatsWithOneDossierId() {

        DossierStats dossierStats = dossierStatsClient.getDossierStats(dossier1.getId());
        assertThat(dossierStats.getDossierId()).isEqualTo(dossier1.getId());
        assertThat(dossierStats.getNumberOfFiles()).isEqualTo(2);
        assertThat(dossierStats.getNumberOfPages()).isEqualTo(NUMBER_PAGES_ANALYZED);
        assertThat(dossierStats.isHasRedactionsFilePresent()).isTrue();
        assertThat(dossierStats.isHasHintsNoRedactionsFilePresent()).isFalse();
        assertThat(dossierStats.isHasSuggestionsFilePresent()).isTrue();
        assertThat(dossierStats.isHasUpdatesFilePresent()).isTrue();
        assertThat(dossierStats.isHasNoFlagsFilePresent()).isFalse();
        assertThat(dossierStats.getFileCountPerProcessingStatus().get(ProcessingStatus.PRE_PROCESSING_QUEUED)).isEqualTo(2);
        assertThat(dossierStats.getLastFileUpdateDate()).isEqualTo(NOW);
        assertThat(dossierStats.getFileManipulationDate()).isEqualTo(OLDER_2);
    }


    @Test
    public void testDossierStatsWithMoreDossierIds() {
        Set<String> dossierIds = new HashSet<>();
        dossierIds.add(dossier1.getId());
        dossierIds.add(dossier2.getId());

        List<DossierStats> dossierStatsList = dossierStatsClient.getDossierStats(dossierIds);

        // get the result for dossier2
        DossierStats dossierStats = dossierStatsList.stream().filter(d -> d.getDossierId().equals(dossier2.getId())).findAny().get();
        assertThat(dossierStats.getNumberOfFiles()).isEqualTo(2);
        assertThat(dossierStats.getNumberOfPages()).isEqualTo(0);
        assertThat(dossierStats.isHasRedactionsFilePresent()).isFalse();
        assertThat(dossierStats.isHasHintsNoRedactionsFilePresent()).isTrue();
        assertThat(dossierStats.isHasSuggestionsFilePresent()).isFalse();
        assertThat(dossierStats.isHasUpdatesFilePresent()).isFalse();
        assertThat(dossierStats.isHasNoFlagsFilePresent()).isTrue();
        assertThat(dossierStats.getFileCountPerWorkflowStatus().get(WorkflowStatus.NEW)).isEqualTo(1);
        assertThat(dossierStats.getFileCountPerWorkflowStatus().get(WorkflowStatus.APPROVED)).isEqualTo(1);
        assertThat(dossierStats.getLastFileUpdateDate()).isEqualTo(OLDER_1);
        assertThat(dossierStats.getFileManipulationDate()).isEqualTo(OLDER_2);
    }


    @Test
    public void testArchivedAndDeletedDossierStats() {
        DossierStats dossierStats = dossierStatsClient.getDossierStats(dossier1.getId());
        assertThat(dossierStats.getNumberOfFiles()).isEqualTo(2);

        dossierClient.archiveDossiers(Set.of(dossier1.getId()));
        dossierStats = dossierStatsClient.getDossierStats(dossier1.getId());
        assertThat(dossierStats.getNumberOfFiles()).isEqualTo(2);

        dossierClient.deleteDossier(dossier1.getId());

        var allDossiers = dossierClient.getDossiers(true, true);
        assertThat(allDossiers.size()).isEqualTo(2);
        assertThat(dossierClient.getSoftDeletedDossiers().size()).isEqualTo(1);

        dossierStats = dossierStatsClient.getDossierStats(dossier1.getId());
        assertThat(dossierStats.getNumberOfSoftDeletedFiles()).isEqualTo(2);

    }

}
