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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;

import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.SpyBean;

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.service.TypeProvider;
import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest;
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.LegalBasisEntity;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.LegalBasisMappingPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel;
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Position;
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.warning.ApproveResponse;
import com.iqser.red.service.persistence.service.v1.api.shared.model.warning.WarningType;

public class ApprovalTest extends AbstractPersistenceServerServiceTest {

    @Autowired
    private DossierTemplateTesterAndProvider dossierTemplateTesterAndProvider;

    @Autowired
    private FileTesterAndProvider fileTesterAndProvider;

    @Autowired
    private DossierTesterAndProvider dossierTesterAndProvider;

    @Autowired
    private TypeProvider typeProvider;

    @Autowired
    private FileClient fileClient;

    @SpyBean
    private LegalBasisMappingPersistenceService legalBasisMappingPersistenceService;


    @Test
    public void testApprovalNoWarnings() {

        DossierTemplateModel dossierTemplateModel = dossierTemplateTesterAndProvider.provideTestTemplate();
        Dossier dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplateModel);
        FileStatus file = fileTesterAndProvider.testAndProvideFile(dossier, "file");
        fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file.getFileId());

        when(legalBasisMappingPersistenceService.getLegalBasisMapping(anyString())).thenReturn(List.of(LegalBasisEntity.builder()
                                                                                                               .technicalName("legal_basis")
                                                                                                               .reason("legalBasis")
                                                                                                               .build()));
        EntityLog entityLog = new EntityLog();
        entityLog.setEntityLogEntry(List.of(EntityLogEntry.builder()
                                                    .id("id1")
                                                    .positions(List.of(new Position(1, 1, 1, 1, 1)))
                                                    .state(EntryState.APPLIED)
                                                    .legalBasis("legal_basis")
                                                    .entryType(EntryType.ENTITY)
                                                    .value("value")
                                                    .build()));
        when(entityLogService.getEntityLog(anyString(), anyString(), anyBoolean())).thenReturn(entityLog);

        ApproveResponse approveResponse = fileClient.setStatusApproved(dossier.getId(), file.getFileId(), false);

        assertFalse(approveResponse.isHasWarnings());
        assertTrue(approveResponse.getFileWarnings().isEmpty());
    }


    @Test
    public void testApprovalWithWarnings() {

        DossierTemplateModel dossierTemplateModel = dossierTemplateTesterAndProvider.provideTestTemplate();
        Dossier dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplateModel);
        FileStatus file = fileTesterAndProvider.testAndProvideFile(dossier, "file");
        fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file.getFileId());

        EntityLog entityLog = new EntityLog();
        entityLog.setEntityLogEntry(List.of(EntityLogEntry.builder()
                                                    .id("id1")
                                                    .positions(List.of(new Position(1, 1, 1, 1, 1)))
                                                    .state(EntryState.APPLIED)
                                                    .entryType(EntryType.ENTITY)
                                                    .value("value")
                                                    .build(),
                                            EntityLogEntry.builder()
                                                    .id("id2")
                                                    .positions(List.of(new Position(1, 1, 1, 1, 2)))
                                                    .state(EntryState.PENDING)
                                                    .entryType(EntryType.ENTITY)
                                                    .legalBasis("legalBasis")
                                                    .value("value")
                                                    .build()));

        when(entityLogService.getEntityLog(anyString(), anyString(), anyBoolean())).thenReturn(entityLog);

        ApproveResponse approveResponse = fileClient.setStatusApproved(dossier.getId(), file.getFileId(), false);

        assertTrue(approveResponse.isHasWarnings());
        assertFalse(approveResponse.getFileWarnings().isEmpty());
        assertEquals(approveResponse.getFileWarnings()
                             .stream()
                             .filter(c -> c.getWarningType().equals(WarningType.PENDING_CHANGE))
                             .count(), 1);
        assertEquals(approveResponse.getFileWarnings()
                             .stream()
                             .filter(c -> c.getWarningType().equals(WarningType.LEGAL_BASIS_MISSING))
                             .count(), 1);
    }


    @Test
    public void testApprovalWithWarningValueTooLoong() {

        DossierTemplateModel dossierTemplateModel = dossierTemplateTesterAndProvider.provideTestTemplate();
        Dossier dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplateModel);
        FileStatus file = fileTesterAndProvider.testAndProvideFile(dossier, "file");
        fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file.getFileId());

        EntityLog entityLog = new EntityLog();
        entityLog.setEntityLogEntry(List.of(EntityLogEntry.builder()
                                                    .id("id2")
                                                    .positions(List.of(new Position(1, 1, 1, 1, 2)))
                                                    .state(EntryState.PENDING)
                                                    .legalBasis("legalBasis")
                                                    .value(StringUtils.repeat("a", 1000))
                                                    .build()));

        when(entityLogService.getEntityLog(anyString(), anyString(), anyBoolean())).thenReturn(entityLog);

        ApproveResponse approveResponse = fileClient.setStatusApproved(dossier.getId(), file.getFileId(), false);

        assertTrue(approveResponse.isHasWarnings());
        assertFalse(approveResponse.getFileWarnings().isEmpty());
        assertEquals(approveResponse.getFileWarnings()
                             .get(0).getValue().length(), 100);
        assertEquals(approveResponse.getFileWarnings()
                             .get(0).getWarningType(), WarningType.PENDING_CHANGE);
    }


    @Test
    public void testForceApprovalWithIssues() {

        DossierTemplateModel dossierTemplateModel = dossierTemplateTesterAndProvider.provideTestTemplate();
        Dossier dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplateModel);
        FileStatus file = fileTesterAndProvider.testAndProvideFile(dossier, "file");
        fileTesterAndProvider.markFileAsProcessed(dossier.getId(), file.getFileId());

        EntityLog entityLog = new EntityLog();
        entityLog.setEntityLogEntry(List.of(EntityLogEntry.builder()
                                                    .id("id2")
                                                    .positions(List.of(new Position(1, 1, 1, 1, 2)))
                                                    .state(EntryState.PENDING)
                                                    .legalBasis("legalBasis")
                                                    .value(StringUtils.repeat("a", 1000))
                                                    .build()));

        when(entityLogService.getEntityLog(anyString(), anyString(), anyBoolean())).thenReturn(entityLog);

        ApproveResponse approveResponse = fileClient.setStatusApproved(dossier.getId(), file.getFileId(), true);

        assertFalse(approveResponse.isHasWarnings());
        assertTrue(approveResponse.getFileWarnings().isEmpty());
    }

}
