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.DossierAttributeClient;
import com.iqser.red.service.peristence.v1.server.integration.client.DossierAttributeConfigClient;
import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider;
import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierAttributes;
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierAttributesConfig;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierAttributeConfig;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.DossierAttribute;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.DossierAttributeType;

import feign.FeignException;
import lombok.SneakyThrows;

public class DossierAttributeTest extends AbstractPersistenceServerServiceTest {

    @Autowired
    private DossierTesterAndProvider dossierTesterAndProvider;

    @Autowired
    private DossierAttributeConfigClient dossierAttributeConfigClient;

    @Autowired
    private DossierAttributeClient dossierAttributeClient;


    @SneakyThrows
    @Test
    public void testDossierAttributes() {

        var dossier = dossierTesterAndProvider.provideTestDossier();

        var loadedAttributes = dossierAttributeConfigClient.getDossierAttributesConfig(dossier.getDossierTemplateId());
        assertThat(loadedAttributes.getDossierAttributeConfigs()).isEmpty();

        DossierAttributeConfig attribute = new DossierAttributeConfig();
        attribute.setLabel("test");
        attribute.setEditable(true);
        attribute.setType(DossierAttributeType.TEXT);

        var created = dossierAttributeConfigClient.addOrUpdateDossierAttributeConfig(dossier.getDossierTemplateId(), attribute);
        assertThat(created.getPlaceholder()).isEqualTo("{{dossier.attribute.Test}}");
        loadedAttributes = dossierAttributeConfigClient.getDossierAttributesConfig(dossier.getDossierTemplateId());
        assertThat(loadedAttributes.getDossierAttributeConfigs()).isNotEmpty();
        assertThat(loadedAttributes.getDossierAttributeConfigs().get(0).getDossierTemplateId()).isEqualTo(dossier.getDossierTemplateId());

        attribute.setId(created.getId());
        attribute.setLabel("updated test");
        var updated = dossierAttributeConfigClient.addOrUpdateDossierAttributeConfig(dossier.getDossierTemplateId(), attribute);
        assertThat(updated.getLabel()).isEqualTo("updated test");
        assertThat(updated.getPlaceholder()).isEqualTo("{{dossier.attribute.UpdatedTest}}");

        attribute.setPlaceholder("{{dossier.attribute.MyOwnPlaceholder}}");
        updated = dossierAttributeConfigClient.addOrUpdateDossierAttributeConfig(dossier.getDossierTemplateId(), attribute);
        assertThat(updated.getLabel()).isEqualTo("updated test");
        assertThat(updated.getPlaceholder()).isEqualTo("{{dossier.attribute.MyOwnPlaceholder}}");


        dossierAttributeConfigClient.setDossierAttributesConfig(dossier.getDossierTemplateId(), new DossierAttributesConfig());
        loadedAttributes = dossierAttributeConfigClient.getDossierAttributesConfig(dossier.getDossierTemplateId());
        assertThat(loadedAttributes.getDossierAttributeConfigs()).isEmpty();

        dossierAttributeConfigClient.setDossierAttributesConfig(dossier.getDossierTemplateId(), new DossierAttributesConfig(List.of(attribute)));
        loadedAttributes = dossierAttributeConfigClient.getDossierAttributesConfig(dossier.getDossierTemplateId());
        assertThat(loadedAttributes.getDossierAttributeConfigs()).isNotEmpty();

        dossierAttributeConfigClient.deleteDossierAttributesConfig(dossier.getDossierTemplateId(),
                                                                   loadedAttributes.getDossierAttributeConfigs()
                                                                           .stream()
                                                                           .map(DossierAttributeConfig::getId)
                                                                           .collect(Collectors.toList()));
        dossierAttributeConfigClient.setDossierAttributesConfig(dossier.getDossierTemplateId(), new DossierAttributesConfig(List.of(attribute)));
        loadedAttributes = dossierAttributeConfigClient.getDossierAttributesConfig(dossier.getDossierTemplateId());
        assertThat(loadedAttributes.getDossierAttributeConfigs()).isNotEmpty();

        var configId = loadedAttributes.getDossierAttributeConfigs()
                .iterator().next().getId();

        List<DossierAttribute> dossierAttributes = new ArrayList<>();
        dossierAttributes.add(DossierAttribute.builder().dossierAttributeConfigId(configId).dossierId(dossier.getId()).value("lorem ipsum").build());
        dossierAttributeClient.setDossierAttributes(dossier.getId(), new DossierAttributes(dossierAttributes));

        var loadedAttributeValues = dossierAttributeClient.getDossierAttributes(dossier.getId());
        assertThat(loadedAttributeValues.getDossierAttributeList()).isNotEmpty();

        var firstAttribute = loadedAttributeValues.getDossierAttributeList()
                .iterator().next();
        assertThat(firstAttribute.getValue()).isEqualTo("lorem ipsum");

        firstAttribute.setValue("  ");
        dossierAttributeClient.addOrUpdateDossierAttribute(dossier.getId(), firstAttribute);

        loadedAttributeValues = dossierAttributeClient.getDossierAttributes(dossier.getId());
        assertThat(loadedAttributeValues.getDossierAttributeList()).isNotEmpty();
        firstAttribute = loadedAttributeValues.getDossierAttributeList()
                .iterator().next();
        assertThat(firstAttribute.getValue()).isNull();

        firstAttribute.setValue(null);
        dossierAttributeClient.addOrUpdateDossierAttribute(dossier.getId(), firstAttribute);

        loadedAttributeValues = dossierAttributeClient.getDossierAttributes(dossier.getId());
        assertThat(loadedAttributeValues.getDossierAttributeList()).isNotEmpty();
        firstAttribute = loadedAttributeValues.getDossierAttributeList()
                .iterator().next();
        assertThat(firstAttribute.getValue()).isNull();

        dossierAttributeClient.deleteDossierAttribute(dossier.getId(), firstAttribute.getDossierAttributeConfigId());
        loadedAttributeValues = dossierAttributeClient.getDossierAttributes(dossier.getId());
        assertThat(loadedAttributeValues.getDossierAttributeList()).isEmpty();

        dossierAttributeClient.setDossierAttributes(dossier.getId(), new DossierAttributes(dossierAttributes));
        loadedAttributeValues = dossierAttributeClient.getDossierAttributes(dossier.getId());
        assertThat(loadedAttributeValues.getDossierAttributeList()).isNotEmpty();

        //delete the list of dossier attribute config with child
        dossierAttributeConfigClient.deleteDossierAttributesConfig(dossier.getDossierTemplateId(),
                                                                   Lists.newArrayList(loadedAttributes.getDossierAttributeConfigs()
                                                                                              .iterator().next().getId()));
        loadedAttributes = dossierAttributeConfigClient.getDossierAttributesConfig(dossier.getDossierTemplateId());
        assertThat(loadedAttributes.getDossierAttributeConfigs()).isEmpty();
        loadedAttributeValues = dossierAttributeClient.getDossierAttributes(dossier.getId());
        assertThat(loadedAttributeValues.getDossierAttributeList()).isEmpty();

    }


    @SneakyThrows
    @Test
    public void testSetDossierAttributesInvalidAddsOrUpdates() {

        var dossier = dossierTesterAndProvider.provideTestDossier();

        var loadedAttributes = dossierAttributeConfigClient.getDossierAttributesConfig(dossier.getDossierTemplateId());
        assertThat(loadedAttributes.getDossierAttributeConfigs()).isEmpty();

        dossierAttributeConfigClient.addOrUpdateDossierAttributeConfig(dossier.getDossierTemplateId(),
                                                                       DossierAttributeConfig.builder().label("Text").editable(true).type(DossierAttributeType.TEXT).build());
        dossierAttributeConfigClient.addOrUpdateDossierAttributeConfig(dossier.getDossierTemplateId(),
                                                                       DossierAttributeConfig.builder().label("Number").editable(true).type(DossierAttributeType.NUMBER).build());
        dossierAttributeConfigClient.addOrUpdateDossierAttributeConfig(dossier.getDossierTemplateId(),
                                                                       DossierAttributeConfig.builder().label("Date").editable(true).type(DossierAttributeType.DATE).build());
        dossierAttributeConfigClient.addOrUpdateDossierAttributeConfig(dossier.getDossierTemplateId(),
                                                                       DossierAttributeConfig.builder().label("Image1").editable(true).type(DossierAttributeType.IMAGE).build());
        dossierAttributeConfigClient.addOrUpdateDossierAttributeConfig(dossier.getDossierTemplateId(),
                                                                       DossierAttributeConfig.builder().label("Image2").editable(true).type(DossierAttributeType.IMAGE).build());
        loadedAttributes = dossierAttributeConfigClient.getDossierAttributesConfig(dossier.getDossierTemplateId());
        assertThat(loadedAttributes.getDossierAttributeConfigs().size()).isEqualTo(5);

        var configIds = loadedAttributes.getDossierAttributeConfigs();

        String valueConfig0 = "lorem ipsum 123";
        String valueConfig1 = "12345";
        String valueConfig2 = "2023-08-08";
        String valueConfig3 = "data:image/png;base64,w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==...";
        String valueConfig4 = "data:image/jpg;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4...";
        List<DossierAttribute> dossierAttributes = new ArrayList<>();
        dossierAttributes.add(DossierAttribute.builder().dossierAttributeConfigId(configIds.get(0).getId()).dossierId(dossier.getId()).value(valueConfig0).build());
        dossierAttributes.add(DossierAttribute.builder().dossierAttributeConfigId(configIds.get(1).getId()).dossierId(dossier.getId()).value(valueConfig1).build());
        dossierAttributes.add(DossierAttribute.builder().dossierAttributeConfigId(configIds.get(2).getId()).dossierId(dossier.getId()).value(valueConfig2).build());
        dossierAttributes.add(DossierAttribute.builder().dossierAttributeConfigId(configIds.get(3).getId()).dossierId(dossier.getId()).value(valueConfig3).build());
        dossierAttributeClient.setDossierAttributes(dossier.getId(), new DossierAttributes(dossierAttributes));

        DossierAttribute imageAttribute = DossierAttribute.builder().dossierAttributeConfigId(configIds.get(4).getId()).dossierId(dossier.getId()).value(valueConfig4).build();
        dossierAttributeClient.addOrUpdateDossierAttribute(dossier.getId(), imageAttribute);

        var loadedAttributeValues = dossierAttributeClient.getDossierAttributes(dossier.getId());
        assertThat(loadedAttributeValues.getDossierAttributeList().size()).isEqualTo(5);
        assertThat(loadedAttributeValues.getDossierAttributeList()
                           .get(0).getValue()).isEqualTo(valueConfig0);
        assertThat(loadedAttributeValues.getDossierAttributeList()
                           .get(1).getValue()).isEqualTo(valueConfig1);
        assertThat(loadedAttributeValues.getDossierAttributeList()
                           .get(2).getValue()).isEqualTo(valueConfig2);
        assertThat(loadedAttributeValues.getDossierAttributeList()
                           .get(3).getValue()).isEqualTo(valueConfig3);
        assertThat(loadedAttributeValues.getDossierAttributeList()
                           .get(4).getValue()).isEqualTo(valueConfig4);

        String valueUpdate = "data:image/jpeg;base64,jkaf0000JJkasfaiiiiiHHHEkkkkki12Pd3Jaks222ggggB...";
        imageAttribute.setValue(valueUpdate);
        dossierAttributeClient.addOrUpdateDossierAttribute(dossier.getId(), imageAttribute);
        loadedAttributeValues = dossierAttributeClient.getDossierAttributes(dossier.getId());
        assertThat(loadedAttributeValues.getDossierAttributeList()
                           .get(4).getValue()).isEqualTo(valueUpdate);

        var e = assertThrows(FeignException.class,
                             () -> dossierAttributeClient.addOrUpdateDossierAttribute(dossier.getId(),
                                                                                      DossierAttribute.builder()
                                                                                              .dossierAttributeConfigId(configIds.get(1).getId())
                                                                                              .dossierId(dossier.getId())
                                                                                              .value("12345qwer")
                                                                                              .build()));
        assertEquals(400, e.status());
        e = assertThrows(FeignException.class,
                         () -> dossierAttributeClient.addOrUpdateDossierAttribute(dossier.getId(),
                                                                                  DossierAttribute.builder()
                                                                                          .dossierAttributeConfigId(configIds.get(1).getId())
                                                                                          .dossierId(dossier.getId())
                                                                                          .value("")
                                                                                          .build()));
        assertEquals(400, e.status());
        e = assertThrows(FeignException.class,
                         () -> dossierAttributeClient.addOrUpdateDossierAttribute(dossier.getId(),
                                                                                  DossierAttribute.builder()
                                                                                          .dossierAttributeConfigId(configIds.get(2).getId())
                                                                                          .dossierId(dossier.getId())
                                                                                          .value("07.02.2024")
                                                                                          .build()));
        assertEquals(400, e.status());
        e = assertThrows(FeignException.class,
                         () -> dossierAttributeClient.addOrUpdateDossierAttribute(dossier.getId(),
                                                                                  DossierAttribute.builder()
                                                                                          .dossierAttributeConfigId(configIds.get(2).getId())
                                                                                          .dossierId(dossier.getId())
                                                                                          .value("2021-17-31")
                                                                                          .build()));
        assertEquals(400, e.status());
        e = assertThrows(FeignException.class,
                         () -> dossierAttributeClient.addOrUpdateDossierAttribute(dossier.getId(),
                                                                                  DossierAttribute.builder()
                                                                                          .dossierAttributeConfigId(configIds.get(2).getId())
                                                                                          .dossierId(dossier.getId())
                                                                                          .value("")
                                                                                          .build()));
        assertEquals(400, e.status());
        e = assertThrows(FeignException.class,
                         () -> dossierAttributeClient.addOrUpdateDossierAttribute(dossier.getId(),
                                                                                  DossierAttribute.builder()
                                                                                          .dossierAttributeConfigId(configIds.get(3).getId())
                                                                                          .dossierId(dossier.getId())
                                                                                          .value("data:image/gif;base64,test")
                                                                                          .build()));
        assertEquals(400, e.status());

        List<DossierAttribute> invalidDossierAttributes1 = List.of(DossierAttribute.builder()
                                                                           .dossierAttributeConfigId(configIds.get(0).getId())
                                                                           .dossierId(dossier.getId())
                                                                           .value(valueConfig0)
                                                                           .build(),
                                                                   DossierAttribute.builder()
                                                                           .dossierAttributeConfigId(configIds.get(1).getId())
                                                                           .dossierId(dossier.getId())
                                                                           .value("asdf12345")
                                                                           .build());
        e = assertThrows(FeignException.class, () -> dossierAttributeClient.setDossierAttributes(dossier.getId(), new DossierAttributes(invalidDossierAttributes1)));
        assertEquals(400, e.status());
        List<DossierAttribute> invalidDossierAttributes2 = List.of(DossierAttribute.builder()
                                                                           .dossierAttributeConfigId(configIds.get(1).getId())
                                                                           .dossierId(dossier.getId())
                                                                           .value(valueConfig1)
                                                                           .build(),
                                                                   DossierAttribute.builder()
                                                                           .dossierAttributeConfigId(configIds.get(2).getId())
                                                                           .dossierId(dossier.getId())
                                                                           .value("20140705")
                                                                           .build());
        e = assertThrows(FeignException.class, () -> dossierAttributeClient.setDossierAttributes(dossier.getId(), new DossierAttributes(invalidDossierAttributes2)));
        assertEquals(400, e.status());
        List<DossierAttribute> invalidDossierAttributes3 = List.of(DossierAttribute.builder()
                                                                           .dossierAttributeConfigId(configIds.get(1).getId())
                                                                           .dossierId(dossier.getId())
                                                                           .value(valueConfig1)
                                                                           .build(),
                                                                   DossierAttribute.builder()
                                                                           .dossierAttributeConfigId(configIds.get(3).getId())
                                                                           .dossierId(dossier.getId())
                                                                           .value("data:image/jpe;base64,test")
                                                                           .build());
        e = assertThrows(FeignException.class, () -> dossierAttributeClient.setDossierAttributes(dossier.getId(), new DossierAttributes(invalidDossierAttributes3)));
        assertEquals(400, e.status());

    }

}
