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.List;

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

import com.iqser.red.service.peristence.v1.server.integration.client.FileClient;
import com.iqser.red.service.peristence.v1.server.integration.client.FileManagementClient;
import com.iqser.red.service.peristence.v1.server.integration.client.FileProcessingClient;
import com.iqser.red.service.peristence.v1.server.integration.client.ReanalysisClient;
import com.iqser.red.service.peristence.v1.server.integration.client.UploadClient;
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.service.UserProvider;
import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.AnalyzeResult;
import com.iqser.red.service.persistence.service.v1.api.shared.model.MessageType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileErrorInfo;
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;

public class FileProcessingTest extends AbstractPersistenceServerServiceTest {

    @Autowired
    private FileTesterAndProvider fileTesterAndProvider;

    @Autowired
    private DossierTesterAndProvider dossierTesterAndProvider;

    @Autowired
    private FileProcessingClient fileProcessingClient;

    @Autowired
    private FileClient fileClient;

    @Autowired
    private UploadClient uploadClient;

    @Autowired
    private ReanalysisClient reanalysisClient;

    @Autowired
    private FileManagementClient fileManagementClient;

    @Autowired
    private UserProvider userProvider;

    @Test
    public void testFileProcessing() {

        var dossier = dossierTesterAndProvider.provideTestDossier();

        var file = fileTesterAndProvider.testAndProvideFile(dossier);

        assertThat(file.getOcrStartTime()).isNull();

        fileProcessingClient.analysisFailed(dossier.getId(), file.getId(), new FileErrorInfo());
        var loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
        assertThat(loadedFile.getProcessingStatus()).isEqualTo(ProcessingStatus.ERROR);

        fileProcessingClient.analysisSuccessful(dossier.getId(), file.getId(), AnalyzeResult.builder()
                .manualRedactions(new ManualRedactions())
                .messageType(MessageType.ANALYSE).analysisVersion(0).fileId(file.getId()).dossierId(dossier.getId()).build());
        loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
        assertThat(loadedFile.getWorkflowStatus()).isEqualTo(WorkflowStatus.NEW);
        assertThat(loadedFile.getAnalysisVersion()).isEqualTo(0);

        fileProcessingClient.ocrFailed(dossier.getId(), file.getId(), new FileErrorInfo());
        loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
        assertThat(loadedFile.getProcessingStatus()).isEqualTo(ProcessingStatus.ERROR);

        fileProcessingClient.ocrSuccessful(dossier.getId(), file.getId());
        loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
        assertThat(loadedFile.getProcessingStatus()).isEqualTo(ProcessingStatus.FULL_PROCESSING);

        fileProcessingClient.indexing(dossier.getId(), file.getId());
        loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
        assertThat(loadedFile.getProcessingStatus()).isEqualTo(ProcessingStatus.INDEXING);
        assertThat(loadedFile.getLastIndexed()).isNull();

        fileProcessingClient.indexingFailed(dossier.getId(), file.getId(), new FileErrorInfo());
        loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
        assertThat(loadedFile.getProcessingStatus()).isEqualTo(ProcessingStatus.ERROR);

        fileProcessingClient.indexingSuccessful(dossier.getId(), file.getId());
        loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
        assertThat(loadedFile.getWorkflowStatus()).isEqualTo(WorkflowStatus.NEW);
        assertThat(loadedFile.getLastIndexed()).isNotNull();

    }


    @Test
    public void testFileProcessingAfterDeletion() {

        var dossier = dossierTesterAndProvider.provideTestDossier();

        var file = fileTesterAndProvider.testAndProvideFile(dossier);

        assertThat(file.getOcrStartTime()).isNull();

        var queue = "queue1";
        fileProcessingClient.analysisFailed(dossier.getId(), file.getId(), new FileErrorInfo("something failed", queue, "service", OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS)));
        var loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
        assertThat(loadedFile.getProcessingStatus()).isEqualTo(ProcessingStatus.ERROR);
        assertThat(loadedFile.getFileErrorInfo().getQueue()).isEqualTo(queue);

        fileProcessingClient.analysisSuccessful(dossier.getId(),
                file.getId(),
                AnalyzeResult.builder().messageType(MessageType.ANALYSE).analysisVersion(100).fileId(file.getId()).dossierId(dossier.getId()).build());
        loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
        assertThat(loadedFile.getWorkflowStatus()).isEqualTo(WorkflowStatus.NEW);
        assertThat(loadedFile.getAnalysisVersion()).isEqualTo(0);

        // Delete file
        fileManagementClient.deleteFile(dossier.getId(), file.getId());
        loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
//        assertThat(loadedFile.getProcessingStatus()).isEqualTo(ProcessingStatus.DELETED);
        assertThat(loadedFile.getSoftDeletedTime()).isNotNull();

        fileProcessingClient.ocrSuccessful(dossier.getId(), file.getId());
        loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
//        assertThat(loadedFile.getProcessingStatus()).isEqualTo(ProcessingStatus.DELETED);
        assertThat(loadedFile.getSoftDeletedTime()).isNotNull();

        fileProcessingClient.indexing(dossier.getId(), file.getId());
        loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
//        assertThat(loadedFile.getProcessingStatus()).isEqualTo(ProcessingStatus.DELETED);
        assertThat(loadedFile.getSoftDeletedTime()).isNotNull();

        fileProcessingClient.indexingFailed(dossier.getId(), file.getId(), new FileErrorInfo());
        loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
//        assertThat(loadedFile.getProcessingStatus()).isEqualTo(ProcessingStatus.DELETED);
        assertThat(loadedFile.getSoftDeletedTime()).isNotNull();

        fileProcessingClient.indexingSuccessful(dossier.getId(), file.getId());
        loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
//        assertThat(loadedFile.getProcessingStatus()).isEqualTo(ProcessingStatus.DELETED);
        assertThat(loadedFile.getSoftDeletedTime()).isNotNull();

    }


    @Test
    public void testFileReanlyseAfterToggleExclusion() {

        var dossier = dossierTesterAndProvider.provideTestDossier();

        var file = fileTesterAndProvider.testAndProvideFile(dossier);

        var userId = userProvider.getUserId();
        fileClient.setStatusUnderReview(dossier.getId(), file.getId(), userId);

        fileProcessingClient.analysisSuccessful(dossier.getId(),
                file.getId(),
                AnalyzeResult.builder().messageType(MessageType.ANALYSE).analysisVersion(100).fileId(file.getId()).dossierId(dossier.getId()).build());
        var loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
        assertThat(loadedFile.getProcessingStatus()).isEqualTo(ProcessingStatus.PROCESSED);



        reanalysisClient.toggleExclusion(file.getDossierId(), file.getId(), true);

        reanalysisClient.toggleExclusion(file.getDossierId(), file.getId(), false);

        loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());

        assertThat(loadedFile.getProcessingStatus()).isEqualTo(ProcessingStatus.FULL_PROCESSING);

    }


    @Test
    public void testGetSoftDeletedForDossierList() {

        var dossier = dossierTesterAndProvider.provideTestDossier();

        var file = fileTesterAndProvider.testAndProvideFile(dossier);

        fileProcessingClient.analysisSuccessful(dossier.getId(),
                file.getId(),
                AnalyzeResult.builder().messageType(MessageType.ANALYSE).analysisVersion(100).fileId(file.getId()).dossierId(dossier.getId()).build());
        var loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
        assertThat(loadedFile.getProcessingStatus()).isEqualTo(ProcessingStatus.PROCESSED);

        // Delete file
        fileManagementClient.deleteFile(dossier.getId(), file.getId());
        loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
        assertThat(loadedFile.getSoftDeletedTime()).isNotNull();

        var fileList = fileClient.getSoftDeletedFilesForDossiers(List.of(dossier.getId()));
        assertThat(fileList.size()).isEqualTo(1);

    }


    @Test
    public void testFileProcessingInErrorStateAndReanalyise() {

        var dossier = dossierTesterAndProvider.provideTestDossier();

        var file = fileTesterAndProvider.testAndProvideFile(dossier);

        fileProcessingClient.analysisFailed(dossier.getId(), file.getId(), new FileErrorInfo());
        var loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
        assertThat(loadedFile.getProcessingStatus()).isEqualTo(ProcessingStatus.ERROR);
        assertThat(loadedFile.getFileErrorInfo()).isNotNull();
        assertThat(loadedFile.getFileErrorInfo().getCause()).isEqualTo("analysisFailed");

        reanalysisClient.reanalyzeFilesForDossier(dossier.getId(), List.of(loadedFile.getId()), true);
        loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
        assertThat(loadedFile.getProcessingStatus()).isEqualTo(ProcessingStatus.FULL_PROCESSING);

    }

}
