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

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.assertj.core.util.Lists;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

import com.iqser.red.service.peristence.v1.server.integration.client.LegalBasisClient;
import com.iqser.red.service.peristence.v1.server.integration.client.VersionClient;
import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider;
import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.LegalBasisMappingPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.legalbasis.LegalBasis;

import feign.FeignException;

public class LegalBasisTest extends AbstractPersistenceServerServiceTest {

    @Autowired
    private DossierTemplateTesterAndProvider dossierTemplateTesterAndProvider;

    @Autowired
    private LegalBasisClient legalBasisClient;

    @Autowired
    private VersionClient versionClient;


    @Test
    public void testLegalBasis() {

        var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();

        try {
            legalBasisClient.getLegalBasisMapping(dossierTemplate.getId());
        } catch (FeignException.FeignClientException e) {
            assertThat(e.status()).isEqualTo(404);
        }

        var mappings = new ArrayList<LegalBasis>();
        mappings.add(LegalBasis.builder().name("test 1").description("test 1").reason("test 1").technicalName("test 1").build());
        mappings.add(LegalBasis.builder().name("test 2").description("test 2").reason("test 2").technicalName("test 2").build());
        legalBasisClient.setLegalBasisMapping(mappings, dossierTemplate.getId());

        var mapping = legalBasisClient.getLegalBasisMapping(dossierTemplate.getId());
        assertThat(mapping.size()).isEqualTo(2);
        assertThat(mapping.stream()
                           .map(LegalBasis::getName)
                           .collect(Collectors.toList())).containsExactlyInAnyOrder("test 1", "test 2");

        var legalBasis = LegalBasis.builder().name("test 3").description("test 3").reason("test 3").technicalName("test 3").build();
        legalBasisClient.addOrUpdateLegalBasis(dossierTemplate.getId(), legalBasis);

        mapping = legalBasisClient.getLegalBasisMapping(dossierTemplate.getId());
        assertThat(mapping.size()).isEqualTo(3);
        assertThat(mapping.stream()
                           .map(LegalBasis::getTechnicalName)
                           .collect(Collectors.toList())).containsExactlyInAnyOrder("test 1", "test 2", "test 3");

        legalBasis = LegalBasis.builder().name("test 3").reason("test 3").description("test 3 - updated").technicalName("test 3").build();
        legalBasisClient.addOrUpdateLegalBasis(dossierTemplate.getId(), legalBasis);

        mapping = legalBasisClient.getLegalBasisMapping(dossierTemplate.getId());
        assertThat(mapping.size()).isEqualTo(3);
        assertThat(mapping.stream()
                           .map(LegalBasis::getDescription)
                           .collect(Collectors.toList())).containsExactlyInAnyOrder("test 1", "test 2", "test 3 - updated");

        legalBasisClient.deleteLegalBasis(dossierTemplate.getId(), Lists.newArrayList("test 1"));
        mapping = legalBasisClient.getLegalBasisMapping(dossierTemplate.getId());
        assertThat(mapping.size()).isEqualTo(2);

        legalBasisClient.setLegalBasisMapping(Lists.newArrayList(), dossierTemplate.getId());
        assertThat(legalBasisClient.getLegalBasisMapping(dossierTemplate.getId())).isEmpty();

        legalBasis = LegalBasis.builder().name("test 4").description(null).reason("test ").technicalName("test 4").build();
        legalBasisClient.addOrUpdateLegalBasis(dossierTemplate.getId(), legalBasis);
        mapping = legalBasisClient.getLegalBasisMapping(dossierTemplate.getId());
        assertThat(mapping.size()).isEqualTo(1);

        legalBasis = LegalBasis.builder().name("test 5").description("test 5").reason(null).technicalName("test 5").build();
        legalBasisClient.addOrUpdateLegalBasis(dossierTemplate.getId(), legalBasis);
        mapping = legalBasisClient.getLegalBasisMapping(dossierTemplate.getId());
        assertThat(mapping.size()).isEqualTo(2);

        LegalBasis finalLegalBasis1 = LegalBasis.builder().name(null).description("test").reason("test").technicalName("test").build();
        var e = assertThrows(FeignException.class, () -> legalBasisClient.addOrUpdateLegalBasis(dossierTemplate.getId(), finalLegalBasis1));
        assertEquals(e.status(), 400);

        LegalBasis finalLegalBasis2 = LegalBasis.builder().name("test").description("test").reason("test").technicalName(null).build();
        e = assertThrows(FeignException.class, () -> legalBasisClient.addOrUpdateLegalBasis(dossierTemplate.getId(), finalLegalBasis2));
        assertEquals(e.status(), 400);

        legalBasis = LegalBasis.builder().name("test 4").description(null).reason("test ").technicalName("test 4").build();
        legalBasisClient.setLegalBasisMapping(List.of(legalBasis), dossierTemplate.getId());
        mapping = legalBasisClient.getLegalBasisMapping(dossierTemplate.getId());
        assertThat(mapping.size()).isEqualTo(1);

        legalBasis = LegalBasis.builder().name("test 5").description("test 5").reason(null).technicalName("test 5").build();
        legalBasisClient.setLegalBasisMapping(List.of(legalBasis), dossierTemplate.getId());
        mapping = legalBasisClient.getLegalBasisMapping(dossierTemplate.getId());
        assertThat(mapping.size()).isEqualTo(1);

        LegalBasis finalLegalBasis3 = LegalBasis.builder().name(null).description("test").reason("test").technicalName("test").build();
        e = assertThrows(FeignException.class, () -> legalBasisClient.setLegalBasisMapping(List.of(finalLegalBasis3), dossierTemplate.getId()));
        assertEquals(e.status(), 400);

        LegalBasis finalLegalBasis4 = LegalBasis.builder().name("test").description("test").reason("test").technicalName(null).build();
        e = assertThrows(FeignException.class, () -> legalBasisClient.setLegalBasisMapping(List.of(finalLegalBasis4), dossierTemplate.getId()));
        assertEquals(e.status(), 400);


        String longName = "a".repeat(LegalBasisMappingPersistenceService.MAX_NAME_LENGTH + 1);
        String longField = "a".repeat(LegalBasisMappingPersistenceService.MAX_LEGAL_BASIS_FIELD_LENGTH + 1);

        LegalBasis longNameLegalBasis = LegalBasis.builder().name(longName).description("valid description").reason("valid reason").technicalName("valid technical name").build();
        e = assertThrows(FeignException.class, () -> legalBasisClient.addOrUpdateLegalBasis(dossierTemplate.getId(), longNameLegalBasis));
        assertEquals(e.status(), 400);

        LegalBasis validLegalBasis = LegalBasis.builder().name("valid name").description("valid description").reason("valid reason").technicalName("valid technical name").build();
        LegalBasis longNameSetLegalBasis = LegalBasis.builder().name(longName).description("valid description").reason("valid reason").technicalName("valid technical name").build();
        e = assertThrows(FeignException.class, () -> legalBasisClient.setLegalBasisMapping(List.of(validLegalBasis, longNameSetLegalBasis), dossierTemplate.getId()));
        assertEquals(e.status(), 400);

        LegalBasis longDescriptionLegalBasis = LegalBasis.builder().name("valid name").description(longField).reason("valid reason").technicalName("valid technical name").build();
        e = assertThrows(FeignException.class, () -> legalBasisClient.addOrUpdateLegalBasis(dossierTemplate.getId(), longDescriptionLegalBasis));
        assertEquals(e.status(), 400);

        LegalBasis longDescriptionSetLegalBasis = LegalBasis.builder().name("valid name").description(longField).reason("valid reason").technicalName("valid technical name").build();
        e = assertThrows(FeignException.class, () -> legalBasisClient.setLegalBasisMapping(List.of(validLegalBasis, longDescriptionSetLegalBasis), dossierTemplate.getId()));
        assertEquals(e.status(), 400);

        LegalBasis longReasonLegalBasis = LegalBasis.builder().name("valid name").description("valid description").reason(longField).technicalName("valid technical name").build();
        e = assertThrows(FeignException.class, () -> legalBasisClient.addOrUpdateLegalBasis(dossierTemplate.getId(), longReasonLegalBasis));
        assertEquals(e.status(), 400);

        LegalBasis longReasonSetLegalBasis = LegalBasis.builder().name("valid name").description("valid description").reason(longField).technicalName("valid technical name").build();
        e = assertThrows(FeignException.class, () -> legalBasisClient.setLegalBasisMapping(List.of(validLegalBasis, longReasonSetLegalBasis), dossierTemplate.getId()));
        assertEquals(e.status(), 400);

        LegalBasis longTechnicalNameLegalBasis = LegalBasis.builder().name("valid name").description("valid description").reason("valid reason").technicalName(longField).build();
        e = assertThrows(FeignException.class, () -> legalBasisClient.addOrUpdateLegalBasis(dossierTemplate.getId(), longTechnicalNameLegalBasis));
        assertEquals(e.status(), 400);

        LegalBasis longTechnicalNameSetLegalBasis = LegalBasis.builder().name("valid name").description("valid description").reason("valid reason").technicalName(longField).build();
        e = assertThrows(FeignException.class, () -> legalBasisClient.setLegalBasisMapping(List.of(validLegalBasis, longTechnicalNameSetLegalBasis), dossierTemplate.getId()));
        assertEquals(e.status(), 400);
    }

}
