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

import static com.iqser.red.service.persistence.service.v1.api.external.resource.FileAttributesResource.ASCII_ENCODING;
import static com.iqser.red.service.persistence.service.v1.api.external.resource.FileAttributesResource.ISO_ENCODING;
import static com.iqser.red.service.persistence.service.v1.api.external.resource.FileAttributesResource.UTF_ENCODING;
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 static org.junit.jupiter.api.Assertions.assertTrue;

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

import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mock.web.MockMultipartFile;

import com.iqser.red.service.peristence.v1.server.integration.client.FileAttributeClient;
import com.iqser.red.service.peristence.v1.server.integration.client.FileAttributeConfigClient;
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.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.utils.AbstractPersistenceServerServiceTest;
import com.iqser.red.service.persistence.management.v1.processor.service.FileAttributesManagementService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttributes;
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttributesConfig;
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.FileAttributeConfig;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileAttributeType;

import feign.FeignException;
import lombok.SneakyThrows;

public class FileAttributeTest extends AbstractPersistenceServerServiceTest {

    @Autowired
    private FileTesterAndProvider fileTesterAndProvider;

    @Autowired
    private DossierTesterAndProvider dossierTesterAndProvider;

    @Autowired
    private FileAttributeConfigClient fileAttributeConfigClient;

    @Autowired
    private FileAttributeClient fileAttributeClient;

    @Autowired
    private FileClient fileClient;
    @Autowired
    private UploadClient uploadClient;

    @Autowired
    private FileManagementClient fileManagementClient;

    @Autowired
    private FileAttributesManagementService fileAttribute;


    @SneakyThrows
    @Test
    public void testFileAttributes() {

        var dossier = dossierTesterAndProvider.provideTestDossier();

        var file = fileTesterAndProvider.testAndProvideFile(dossier);

        var generalConfig = new FileAttributesConfig();
        generalConfig.setDelimiter(",");
        generalConfig.setEncoding(UTF_ENCODING);
        generalConfig.setFilenameMappingColumnHeaderName("Name");

        fileAttributeConfigClient.setFileAttributesConfig(dossier.getDossierTemplateId(), generalConfig);
        var loadedConfig = fileAttributeConfigClient.getFileAttributesConfiguration(dossier.getDossierTemplateId());
        assertThat(loadedConfig.getDelimiter()).isEqualTo(",");
        assertThat(loadedConfig.getEncoding()).isEqualTo(UTF_ENCODING);

        generalConfig.setEncoding(" ASCII ");
        fileAttributeConfigClient.setFileAttributesConfig(dossier.getDossierTemplateId(), generalConfig);
        loadedConfig = fileAttributeConfigClient.getFileAttributesConfiguration(dossier.getDossierTemplateId());
        assertThat(loadedConfig.getEncoding()).isEqualTo(ASCII_ENCODING);

        List<FileAttributeConfig> configs = new ArrayList<>();
        String myOwnPlaceholder = "{{file.attribute.MyOwnPlaceholder}}";
        configs.add(FileAttributeConfig.builder().csvColumnHeader("Name").primaryAttribute(true).label("Name").build());
        configs.add(FileAttributeConfig.builder().csvColumnHeader("Attribute A").primaryAttribute(true).label("Attribute A").build());
        FileAttributeConfig attributeB = FileAttributeConfig.builder().csvColumnHeader("Attribute B").primaryAttribute(true).label("Attribute B").placeholder(myOwnPlaceholder).includeInCsvExport(true).build();
        configs.add(attributeB);
        configs.add(FileAttributeConfig.builder().csvColumnHeader("Attribute C").primaryAttribute(false).label("Attribute C").build());
        configs.add(FileAttributeConfig.builder().csvColumnHeader("Attribute D").primaryAttribute(false).label("Attribute D").build());

        fileAttributeConfigClient.setFileAttributesConfig(dossier.getDossierTemplateId(), new FileAttributesConfig("Name", ",", UTF_ENCODING, configs));

        List<FileAttributeConfig> loadedConfigs = fileAttributeConfigClient.getFileAttributesConfiguration(dossier.getDossierTemplateId()).getFileAttributeConfigs();
        assertThat(loadedConfigs.size()).isEqualTo(5);
        FileAttributeConfig primaryAttribute = loadedConfigs.stream()
                .filter(FileAttributeConfig::isPrimaryAttribute)
                .findAny()
                .get();
        assertThat(primaryAttribute.getLabel()).isEqualTo(attributeB.getLabel());
        assertThat(primaryAttribute.getPlaceholder()).isEqualTo(attributeB.getPlaceholder());
        assertTrue(primaryAttribute.isIncludeInCsvExport());

        fileAttributeConfigClient.deleteFileAttribute(dossier.getDossierTemplateId(),
                                                      loadedConfigs.stream()
                                                              .filter(a -> a.getCsvColumnHeader().equalsIgnoreCase("Attribute C"))
                                                              .findAny()
                                                              .map(FileAttributeConfig::getId)
                                                              .orElseThrow(() -> new IllegalArgumentException("Should exists!")));

        fileAttributeConfigClient.deleteFileAttributes(dossier.getDossierTemplateId(),
                                                       loadedConfigs.stream()
                                                               .filter(a -> a.getCsvColumnHeader().equalsIgnoreCase("Attribute D"))
                                                               .findAny()
                                                               .map(FileAttributeConfig::getId)
                                                               .stream()
                                                               .collect(Collectors.toList()));

        loadedConfigs = fileAttributeConfigClient.getFileAttributesConfiguration(dossier.getDossierTemplateId()).getFileAttributeConfigs();
        assertThat(loadedConfigs.size()).isEqualTo(3);
        assertThat(loadedConfigs.get(0).getDossierTemplateId()).isEqualTo(dossier.getDossierTemplateId());

        FileAttributeConfig newConfig = new FileAttributeConfig();
        newConfig.setPrimaryAttribute(true);
        newConfig.setLabel("Test Attribute");
        var created = fileAttributeConfigClient.addOrUpdateFileAttribute(dossier.getDossierTemplateId(), newConfig);
        loadedConfigs = fileAttributeConfigClient.getFileAttributesConfiguration(dossier.getDossierTemplateId()).getFileAttributeConfigs();
        assertThat(loadedConfigs.size()).isEqualTo(4);
        assertThat(created.getPlaceholder()).isEqualTo("{{file.attribute.TestAttribute}}");
        assertThat(created.getCsvColumnHeader()).isNull();

        newConfig.setId(created.getId());
        newConfig.setLabel("Test Attribute Update");
        newConfig.setIncludeInCsvExport(true);
        var updated = fileAttributeConfigClient.addOrUpdateFileAttribute(dossier.getDossierTemplateId(), newConfig);
        loadedConfigs = fileAttributeConfigClient.getFileAttributesConfiguration(dossier.getDossierTemplateId()).getFileAttributeConfigs();
        assertThat(loadedConfigs.size()).isEqualTo(4);
        assertThat(updated.getLabel()).isEqualTo("Test Attribute Update");
        assertTrue(updated.isIncludeInCsvExport());
        assertThat(updated.getPlaceholder()).isEqualTo("{{file.attribute.TestAttributeUpdate}}");

        newConfig.setPlaceholder(myOwnPlaceholder);
        var e = assertThrows(FeignException.class,
                     () -> fileAttributeConfigClient.addOrUpdateFileAttribute(dossier.getDossierTemplateId(), newConfig));
        assertEquals(409, e.status());
        newConfig.setPlaceholder("{{file.attribute.TestAttributeUpdate2}}");
        updated = fileAttributeConfigClient.addOrUpdateFileAttribute(dossier.getDossierTemplateId(), newConfig);
        assertThat(updated.getPlaceholder()).isEqualTo("{{file.attribute.TestAttributeUpdate2}}");

        assertThat(fileClient.getFileStatus(dossier.getId(), file.getId()).getLastFileAttributeChange()).isNull();

        fileAttributeClient.setFileAttributes(dossier.getId(), file.getId(), new FileAttributes(Map.of(updated.getId(), "Lorem Ipsum")));

        assertThat(fileClient.getFileStatus(dossier.getId(), file.getId()).getLastFileAttributeChange()).isNotNull();

        Map<String, String> fileAttributes = fileClient.getFileStatus(dossier.getId(), file.getId()).getFileAttributes().getAttributeIdToValue();
        assertThat(fileAttributes.size()).isEqualTo(1);
        assertThat(fileAttributes.entrySet()
                           .iterator().next().getValue()).isEqualTo("Lorem Ipsum");

        fileAttributeClient.setFileAttributes(dossier.getId(), file.getId(), new FileAttributes(Map.of(updated.getId(), "   ")));

        fileAttributes = fileClient.getFileStatus(dossier.getId(), file.getId()).getFileAttributes().getAttributeIdToValue();
        assertThat(fileAttributes.size()).isEqualTo(1);
        assertThat(fileAttributes.entrySet()
                           .iterator().next().getValue()).isNull();

        Map<String, String> fileAttributesWithNullValue = new HashMap<>();
        fileAttributesWithNullValue.put(updated.getId(), null);
        fileAttributeClient.setFileAttributes(dossier.getId(), file.getId(), new FileAttributes(fileAttributesWithNullValue));

        fileAttributes = fileClient.getFileStatus(dossier.getId(), file.getId()).getFileAttributes().getAttributeIdToValue();
        assertThat(fileAttributes.size()).isEqualTo(1);
        assertThat(fileAttributes.entrySet()
                           .iterator().next().getValue()).isNull();

        var mock = new MockMultipartFile("test.csv", "test.csv", "application/csv", IOUtils.toByteArray(new ClassPathResource("files/test.csv").getInputStream()));
        uploadClient.upload(mock, dossier.getId(), false, false);

        fileAttributes = fileClient.getFileStatus(dossier.getId(), file.getId()).getFileAttributes().getAttributeIdToValue();
        assertThat(fileAttributes.size()).isEqualTo(2);

        fileAttributes.put(fileAttributes.keySet()
                                   .iterator().next(), "changed");
        fileAttributeClient.setFileAttributes(dossier.getId(), file.getId(), new FileAttributes(fileAttributes));

        fileAttributes = fileClient.getFileStatus(dossier.getId(), file.getId()).getFileAttributes().getAttributeIdToValue();
        assertThat(fileAttributes.size()).isEqualTo(2);

        fileAttributeConfigClient.setFileAttributesConfig(dossier.getDossierTemplateId(), new FileAttributesConfig("Name", ",", "ASCII", new ArrayList<>()));

        loadedConfigs = fileAttributeConfigClient.getFileAttributesConfiguration(dossier.getDossierTemplateId()).getFileAttributeConfigs();
        assertThat(loadedConfigs.size()).isEqualTo(0);

        fileAttributes = fileClient.getFileStatus(dossier.getId(), file.getId()).getFileAttributes().getAttributeIdToValue();
        assertThat(fileAttributes.size()).isEqualTo(0);
    }


    @SneakyThrows
    @Test
    public void testDeleteFile() {
        // Create file with attributes
        var dossier = dossierTesterAndProvider.provideTestDossier();
        var file = fileTesterAndProvider.testAndProvideFile(dossier);

        var generalConfig = new FileAttributesConfig();
        generalConfig.setDelimiter(",");
        generalConfig.setEncoding(UTF_ENCODING);
        generalConfig.setFilenameMappingColumnHeaderName("Name");

        fileAttributeConfigClient.setFileAttributesConfig(dossier.getDossierTemplateId(), generalConfig);
        var loadedConfig = fileAttributeConfigClient.getFileAttributesConfiguration(dossier.getDossierTemplateId());
        assertThat(loadedConfig.getDelimiter()).isEqualTo(",");

        List<FileAttributeConfig> configs = new ArrayList<>();
        configs.add(FileAttributeConfig.builder().csvColumnHeader("Name").primaryAttribute(true).label("Name").build());
        configs.add(FileAttributeConfig.builder().csvColumnHeader("Attribute A").primaryAttribute(false).label("Attribute A").build());
        configs.add(FileAttributeConfig.builder().csvColumnHeader("Attribute B").primaryAttribute(false).label("Attribute B").build());
        configs.add(FileAttributeConfig.builder().csvColumnHeader("Attribute C").primaryAttribute(false).label("Attribute C").build());
        configs.add(FileAttributeConfig.builder().csvColumnHeader("Attribute D").primaryAttribute(false).label("Attribute D").build());

        generalConfig.setFileAttributeConfigs(configs);

        fileAttributeConfigClient.setFileAttributesConfig(dossier.getDossierTemplateId(), generalConfig);

        List<FileAttributeConfig> loadedConfigs = fileAttributeConfigClient.getFileAttributesConfiguration(dossier.getDossierTemplateId()).getFileAttributeConfigs();
        assertThat(loadedConfigs.size()).isEqualTo(5);

        fileAttributeClient.setFileAttributes(dossier.getId(), file.getId(), new FileAttributes(Map.of(loadedConfigs.get(0).getId(), "Lorem Ipsum")));

        Map<String, String> fileAttributes = fileClient.getFileStatus(dossier.getId(), file.getId()).getFileAttributes().getAttributeIdToValue();
        assertThat(fileAttributes.size()).isEqualTo(1);
        assertThat(fileAttributes.entrySet()
                           .iterator().next().getValue()).isEqualTo("Lorem Ipsum");

        // Delete file
        fileManagementClient.deleteFile(dossier.getId(), file.getId());
        fileManagementClient.hardDeleteFiles(dossier.getId(), List.of(file.getId()));
        var deletedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
        assertThat(deletedFile.getFileAttributes().getAttributeIdToValue()).isEmpty();

        // Reupload file
        var newFile = fileTesterAndProvider.testAndProvideFile(dossier);
        assertThat(file.getId()).isEqualTo(newFile.getId());

        var loadedFile = fileClient.getFileStatus(dossier.getId(), newFile.getId());
        assertThat(loadedFile.getFileAttributes().getAttributeIdToValue()).isEmpty();
    }


    @SneakyThrows
    @Test
    public void testSetFileAttributesInvalidUpdates() {
        // Create file with attributes
        var dossier = dossierTesterAndProvider.provideTestDossier();
        var file = fileTesterAndProvider.testAndProvideFile(dossier);

        var generalConfig = new FileAttributesConfig();
        generalConfig.setDelimiter(",");
        generalConfig.setEncoding(UTF_ENCODING);
        generalConfig.setFilenameMappingColumnHeaderName("Name");

        fileAttributeConfigClient.setFileAttributesConfig(dossier.getDossierTemplateId(), generalConfig);
        var loadedConfig = fileAttributeConfigClient.getFileAttributesConfiguration(dossier.getDossierTemplateId());
        assertThat(loadedConfig.getDelimiter()).isEqualTo(",");

        List<FileAttributeConfig> configs = new ArrayList<>();
        configs.add(FileAttributeConfig.builder().csvColumnHeader("Date").primaryAttribute(true).label("Date").type(FileAttributeType.DATE).build());
        configs.add(FileAttributeConfig.builder().csvColumnHeader("Number").primaryAttribute(true).label("Number").type(FileAttributeType.NUMBER).build());
        configs.add(FileAttributeConfig.builder().csvColumnHeader("Text").primaryAttribute(true).label("Text").type(FileAttributeType.TEXT).build());

        generalConfig.setFileAttributeConfigs(configs);

        fileAttributeConfigClient.setFileAttributesConfig(dossier.getDossierTemplateId(), generalConfig);

        List<FileAttributeConfig> loadedConfigs = fileAttributeConfigClient.getFileAttributesConfiguration(dossier.getDossierTemplateId()).getFileAttributeConfigs();
        assertThat(loadedConfigs.size()).isEqualTo(3);

        Map<String, String> fileAttributesMap = new HashMap<>();
        fileAttributesMap.put(loadedConfigs.get(0).getId(), "2023-12-31");
        fileAttributesMap.put(loadedConfigs.get(1).getId(), "12345");
        fileAttributesMap.put(loadedConfigs.get(2).getId(), "Free Text 123");
        fileAttributeClient.setFileAttributes(dossier.getId(), file.getId(), new FileAttributes(fileAttributesMap));

        Map<String, String> fileAttributes = fileClient.getFileStatus(dossier.getId(), file.getId()).getFileAttributes().getAttributeIdToValue();
        assertThat(fileAttributes.size()).isEqualTo(3);
        assertThat(fileAttributes.get(loadedConfigs.get(0).getId())).isEqualTo("2023-12-31");
        assertThat(fileAttributes.get(loadedConfigs.get(1).getId())).isEqualTo("12345");
        assertThat(fileAttributes.get(loadedConfigs.get(2).getId())).isEqualTo("Free Text 123");

        var e = assertThrows(FeignException.class,
                             () -> fileAttributeClient.setFileAttributes(dossier.getId(), file.getId(), new FileAttributes(Map.of(loadedConfigs.get(0).getId(), "random/text"))));
        assertEquals(400, e.status());
        assertThrows(FeignException.class,
                     () -> fileAttributeClient.setFileAttributes(dossier.getId(), file.getId(), new FileAttributes(Map.of(loadedConfigs.get(0).getId(), "2023-12-32"))));
        assertEquals(400, e.status());
        assertThrows(FeignException.class,
                     () -> fileAttributeClient.setFileAttributes(dossier.getId(), file.getId(), new FileAttributes(Map.of(loadedConfigs.get(0).getId(), "2023-02-30"))));
        assertEquals(400, e.status());
        assertThrows(FeignException.class,
                     () -> fileAttributeClient.setFileAttributes(dossier.getId(), file.getId(), new FileAttributes(Map.of(loadedConfigs.get(0).getId(), ""))));
        assertEquals(400, e.status());
        assertThrows(FeignException.class,
                     () -> fileAttributeClient.setFileAttributes(dossier.getId(), file.getId(), new FileAttributes(Map.of(loadedConfigs.get(1).getId(), "abc"))));
        assertEquals(400, e.status());
        assertThrows(FeignException.class,
                     () -> fileAttributeClient.setFileAttributes(dossier.getId(), file.getId(), new FileAttributes(Map.of(loadedConfigs.get(1).getId(), "1-2-3-4"))));
        assertEquals(400, e.status());
        assertThrows(FeignException.class,
                     () -> fileAttributeClient.setFileAttributes(dossier.getId(), file.getId(), new FileAttributes(Map.of(loadedConfigs.get(1).getId(), ""))));
        assertEquals(400, e.status());

    }


    @SneakyThrows
    @Test
    public void testFileAttributeWithNoLabel() {

        Dossier dossier = dossierTesterAndProvider.provideTestDossier();
        FeignException exception = assertThrows(FeignException.class,
                                                () -> fileAttributeConfigClient.addOrUpdateFileAttribute(dossier.getDossierTemplateId(), new FileAttributeConfig()));
        assertTrue(exception.getMessage().contains("File Attribute label can not be empty."));
        assertEquals(400, exception.status());
    }


    @Test
    @SneakyThrows
    public void testUploadCSV() {

        var dossier = dossierTesterAndProvider.provideTestDossier();

        var generalConfig = new FileAttributesConfig();
        generalConfig.setDelimiter(",");
        generalConfig.setEncoding(UTF_ENCODING);
        generalConfig.setFilenameMappingColumnHeaderName("Path");

        fileAttributeConfigClient.setFileAttributesConfig(dossier.getDossierTemplateId(), generalConfig);

        FileAttributeConfig vertebrateStudy = new FileAttributeConfig();
        vertebrateStudy.setPrimaryAttribute(false);
        vertebrateStudy.setLabel("Vertebrate Study");
        vertebrateStudy.setCsvColumnHeader("Vertebrate Study");
        vertebrateStudy.setType(FileAttributeType.TEXT);
        vertebrateStudy.setFilterable(true);
        vertebrateStudy.setDisplayedInFileList(true);
        fileAttributeConfigClient.addOrUpdateFileAttribute(dossier.getDossierTemplateId(), vertebrateStudy);

        FileAttributeConfig minorVersion = new FileAttributeConfig();
        minorVersion.setPrimaryAttribute(false);
        minorVersion.setLabel("Minor Version Number");
        minorVersion.setCsvColumnHeader("Minor Version Number");
        minorVersion.setType(FileAttributeType.DATE);
        minorVersion.setFilterable(true);
        minorVersion.setDisplayedInFileList(true);
        fileAttributeConfigClient.addOrUpdateFileAttribute(dossier.getDossierTemplateId(), minorVersion);

        FileAttributeConfig majorVersion = new FileAttributeConfig();
        majorVersion.setPrimaryAttribute(false);
        majorVersion.setLabel("Major Version Number");
        majorVersion.setCsvColumnHeader("Major Version Number");
        majorVersion.setType(FileAttributeType.NUMBER);
        majorVersion.setFilterable(true);
        majorVersion.setDisplayedInFileList(true);
        fileAttributeConfigClient.addOrUpdateFileAttribute(dossier.getDossierTemplateId(), majorVersion);

        var missingComma = new MockMultipartFile("file.csv",
                                               "fileattributes_missing_comma.csv",
                                               "application/csv",
                                               IOUtils.toByteArray(new ClassPathResource("files/csv/fileattributes_missing_comma.csv").getInputStream()));

        var result = assertThrows(FeignException.class, () -> uploadClient.upload(missingComma, dossier.getId(), false, false));
        assertTrue(result.getMessage().contains("Invalid CSV file format: Invalid CSV file format at line 2: Expected 5 columns but found 4"));


        var missingQuotation = new MockMultipartFile("file.csv",
                                               "fileattributes_missing_quotation_mark.csv",
                                               "application/csv",
                                               IOUtils.toByteArray(new ClassPathResource("files/csv/fileattributes_missing_quotation_mark.csv").getInputStream()));

        result = assertThrows(FeignException.class, () -> uploadClient.upload(missingQuotation, dossier.getId(), false, false));
        assertTrue(result.getMessage().contains("Invalid CSV file format: Unterminated quoted field at end of CSV line. Beginning of lost text: [4.636.0,4.363.0,4.363.0\\n]") || result.getMessage().contains("Invalid CSV file format: Unterminiertes Anführungszeichen am Ende einer CSV-Zeile. Anfang des verlorenen Textes: [4.636.0,4.363.0,4.363.0\\n]"));
    }

    @Test
    public void testParsingEncoding() {
        var dossier = dossierTesterAndProvider.provideTestDossier();


        var generalConfig = new FileAttributesConfig();
        generalConfig.setDelimiter(",");
        generalConfig.setEncoding("ISO");
        generalConfig.setFilenameMappingColumnHeaderName("Name");

        var e = assertThrows(FeignException.class,
                             () -> fileAttributeConfigClient.setFileAttributesConfig(dossier.getDossierTemplateId(), generalConfig));
        assertEquals(400, e.status());
        generalConfig.setEncoding(ISO_ENCODING);
        fileAttributeConfigClient.setFileAttributesConfig(dossier.getDossierTemplateId(), generalConfig);
        var loadedConfig = fileAttributeConfigClient.getFileAttributesConfiguration(dossier.getDossierTemplateId());
        assertThat(loadedConfig.getEncoding()).isEqualTo(ISO_ENCODING);


    }

    @SneakyThrows
    @Test
    public void testUpdatePrimaryAttributeAndVerify() {

        var dossier = dossierTesterAndProvider.provideTestDossier();
        var file = fileTesterAndProvider.testAndProvideFile(dossier);

        List<FileAttributeConfig> initialConfigs = new ArrayList<>();
        initialConfigs.add(FileAttributeConfig.builder()
                                   .csvColumnHeader("Attribute A")
                                   .primaryAttribute(true)
                                   .label("Attribute A")
                                   .build());
        initialConfigs.add(FileAttributeConfig.builder()
                                   .csvColumnHeader("Attribute B")
                                   .primaryAttribute(false)
                                   .label("Attribute B")
                                   .build());
        initialConfigs.add(FileAttributeConfig.builder()
                                   .csvColumnHeader("Attribute C")
                                   .primaryAttribute(false)
                                   .label("Attribute C")
                                   .build());

        FileAttributesConfig initialConfig = new FileAttributesConfig();
        initialConfig.setDelimiter(",");
        initialConfig.setEncoding(UTF_ENCODING);
        initialConfig.setFilenameMappingColumnHeaderName("Name");
        initialConfig.setFileAttributeConfigs(initialConfigs);

        fileAttributeConfigClient.setFileAttributesConfig(dossier.getDossierTemplateId(), initialConfig);

        var loadedInitialConfig = fileAttributeConfigClient.getFileAttributesConfiguration(dossier.getDossierTemplateId());
        assertThat(loadedInitialConfig.getFileAttributeConfigs()).hasSize(3);
        FileAttributeConfig initialPrimary = loadedInitialConfig.getFileAttributeConfigs().stream()
                .filter(FileAttributeConfig::isPrimaryAttribute)
                .findFirst()
                .orElseThrow(() -> new AssertionError("No primary attribute found initially"));
        assertThat(initialPrimary.getLabel()).isEqualTo("Attribute A");

        List<FileAttributeConfig> updatedConfigs = loadedInitialConfig.getFileAttributeConfigs().stream()
                .map(config -> {
                    if (config.getLabel().equals("Attribute B")) {
                        config.setPrimaryAttribute(true);
                    } else if (config.getLabel().equals("Attribute A")) {
                        config.setPrimaryAttribute(false);
                    }
                    return config;
                })
                .collect(Collectors.toList());

        FileAttributesConfig updatedConfig = new FileAttributesConfig();
        updatedConfig.setDelimiter(loadedInitialConfig.getDelimiter());
        updatedConfig.setEncoding(loadedInitialConfig.getEncoding());
        updatedConfig.setFilenameMappingColumnHeaderName(loadedInitialConfig.getFilenameMappingColumnHeaderName());
        updatedConfig.setFileAttributeConfigs(updatedConfigs);

        fileAttributeConfigClient.setFileAttributesConfig(dossier.getDossierTemplateId(), updatedConfig);

        var loadedUpdatedConfig = fileAttributeConfigClient.getFileAttributesConfiguration(dossier.getDossierTemplateId());
        assertThat(loadedUpdatedConfig.getFileAttributeConfigs()).hasSize(3);
        FileAttributeConfig newPrimary = loadedUpdatedConfig.getFileAttributeConfigs().stream()
                .filter(FileAttributeConfig::isPrimaryAttribute)
                .findFirst()
                .orElseThrow(() -> new AssertionError("No primary attribute found after update"));
        assertThat(newPrimary.getLabel()).isEqualTo("Attribute B");

        fileAttributeConfigClient.setFileAttributesConfig(dossier.getDossierTemplateId(), loadedUpdatedConfig);

        var reloadedConfig = fileAttributeConfigClient.getFileAttributesConfiguration(dossier.getDossierTemplateId());
        assertThat(reloadedConfig.getFileAttributeConfigs()).hasSize(3);
        FileAttributeConfig verifiedPrimary = reloadedConfig.getFileAttributeConfigs().stream()
                .filter(FileAttributeConfig::isPrimaryAttribute)
                .findFirst()
                .orElseThrow(() -> new AssertionError("No primary attribute found after reapplying configuration"));
        assertThat(verifiedPrimary.getLabel()).isEqualTo("Attribute B");
    }


}
