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

import com.fasterxml.jackson.databind.ObjectMapper;
import com.iqser.red.service.peristence.v1.server.integration.client.DictionaryClient;
import com.iqser.red.service.peristence.v1.server.integration.client.FileClient;
import com.iqser.red.service.peristence.v1.server.integration.client.InternalDictionaryClient;
import com.iqser.red.service.peristence.v1.server.integration.client.ManualRedactionClient;
import com.iqser.red.service.peristence.v1.server.integration.service.*;
import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest;
import com.iqser.red.service.persistence.management.v1.processor.service.DictionaryManagementService;
import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService;
import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.EntryPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.redactionlog.RedactionRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.Dictionary;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Rectangle;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionRequestModel;
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationRequestModel;
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequestModel;
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequestModel;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry;
import feign.FeignException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;

public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {

    @Autowired
    private FileTesterAndProvider fileTesterAndProvider;

    @Autowired
    private DossierTesterAndProvider dossierTesterAndProvider;

    @Autowired
    private DossierTemplateTesterAndProvider dossierTemplateTesterAndProvider;

    @Autowired
    private TypeProvider typeProvider;

    @Autowired
    private ManualRedactionClient manualRedactionClient;

    @Autowired
    private DictionaryClient dictionaryClient;

    @Autowired
    private FileManagementStorageService fileManagementStorageService;

    @Autowired
    private FileStatusPersistenceService fileStatusPersistenceService;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private FileClient fileClient;

    @Autowired
    private UserProvider userProvider;

    @Autowired
    private InternalDictionaryClient internalDictionaryClient;

    @Autowired
    private RedactionLogService redactionLogService;

    @Autowired
    private DictionaryManagementService dictionaryManagementService;

    @Autowired
    private EntryPersistenceService entryPersistenceService;


    @Test
    public void testRemoveToDossierTemplateWithDossierDictionaryOnlyTrue() {

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

        var type = typeProvider.testAndProvideType(dossierTemplate, null, "type", true);
        assertThat(type.isDossierDictionaryOnly()).isTrue();

        dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), false, dossier.getDossierId(), DictionaryEntryType.ENTRY);

        var redactionLog = new RedactionLog(1,
                1,
                List.of(RedactionLogEntry.builder().id("AnnotationId").type(type.getType()).value("Luke Skywalker").isDictionaryEntry(true).build()),
                null,
                0,
                0,
                0,
                0);
        fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog);

        when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog);

        Assertions.assertThrows(FeignException.Forbidden.class,
                () -> manualRedactionClient.removeRedactionBulk(dossier.getId(),
                        file.getId(),
                        Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())));//.get(0);

        var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId()), null);
        assertThat(dossierTemplateDictionary.getEntries().size()).isZero();

    }


    @Test
    public void testAddToDossierTemplateWithDossierDictionaryOnlyTrue() {

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

        var type = typeProvider.testAndProvideType(dossierTemplate, null, "type", true);
        assertThat(type.isDossierDictionaryOnly()).isTrue();
        Assertions.assertThrows(FeignException.Forbidden.class, () ->

                manualRedactionClient.addRedactionBulk(dossier.getId(),
                        file.getId(),
                        Set.of(AddRedactionRequestModel.builder()
                                .positions(List.of(Rectangle.builder().topLeftY(1).topLeftX(1).height(1).width(1).build()))
                                .section("section test")
                                .addToDictionary(true)
                                .addToAllDossiers(true)
                                .type(type.getType())
                                .reason("1")
                                .value("Luke Skywalker")
                                .legalBasis("1")
                                .sourceId("SourceId")
                                .build())));

        var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId()), null);
        assertThat(dossierTemplateDictionary.getEntries().size()).isZero();

    }


    @Test
    public void testAddToAllDossiersIfDeletedInOneDossier() {

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

        var type = typeProvider.testAndProvideType(dossierTemplate);

        dictionaryClient.deleteEntries(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), dossier.getDossierId(), DictionaryEntryType.ENTRY);

        var dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId(), dossier.getDossierId()), null);
        assertThat(dossierDictionary.getEntries().size()).isEqualTo(1);
        assertThat(dossierDictionary.getEntries().get(0).isDeleted()).isTrue();

        manualRedactionClient.addRedactionBulk(dossier.getId(),
                file.getId(),
                Set.of(AddRedactionRequestModel.builder()
                        .positions(List.of(Rectangle.builder().topLeftY(1).topLeftX(1).height(1).width(1).build()))
                        .section("section test")
                        .addToDictionary(true)
                        .addToAllDossiers(true)
                        .dictionaryEntryType(DictionaryEntryType.ENTRY)
                        .type(type.getType())
                        .reason("1")
                        .value("Luke Skywalker")
                        .legalBasis("1")
                        .sourceId("SourceId")
                        .build()));

        dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId(), dossier.getDossierId()), null);
        assertThat(dossierDictionary.getEntries().size()).isEqualTo(1);
        assertThat(dossierDictionary.getEntries().get(0).isDeleted()).isFalse();

        var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId()), null);
        assertThat(dossierTemplateDictionary.getEntries().size()).isEqualTo(1);
        assertThat(dossierTemplateDictionary.getEntries().get(0).isDeleted()).isFalse();

    }


    @Test
    public void testAddToDossierDictionary() {

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

        var type = typeProvider.testAndProvideType(dossierTemplate);

        manualRedactionClient.addRedactionBulk(dossier.getId(),
                file.getId(),
                Set.of(AddRedactionRequestModel.builder()
                        .positions(List.of(Rectangle.builder().topLeftY(1).topLeftX(1).height(1).width(1).build()))
                        .section("section test")
                        .addToDictionary(true)
                        .addToAllDossiers(false)
                        .type(type.getType())
                        .reason("1")
                        .value("Luke Skywalker")
                        .legalBasis("1")
                        .sourceId("SourceId")
                        .build()));

        var dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId(), dossier.getDossierId()), null);
        assertThat(dossierDictionary.getEntries().size()).isEqualTo(1);
        assertThat(dossierDictionary.getEntries().get(0).isDeleted()).isFalse();

        var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId()), null);
        assertThat(dossierTemplateDictionary.getEntries().isEmpty()).isTrue();
    }


    @Test
    public void testManualRemoveFromAllDossiersAndUndo() {

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

        var type = typeProvider.testAndProvideType(dossierTemplate);

        var entries = new ArrayList<String>();
        entries.add("Luke Skywalker");
        entries.add("Darth Vader");
        dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), entries, false, null, DictionaryEntryType.ENTRY);

        dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), false, dossier.getDossierId(), DictionaryEntryType.ENTRY);

        Dictionary dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null);
        assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder("Luke Skywalker", "Darth Vader");

        Dictionary dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId());
        assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrder("Luke Skywalker");

        var redactionLog = new RedactionLog(1,
                1,
                List.of(RedactionLogEntry.builder().id("AnnotationId").type("test").value("Luke Skywalker").isDictionaryEntry(true).build()),
                null,
                0,
                0,
                0,
                0);
        fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog);

        when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog);

        manualRedactionClient.removeRedactionBulk(dossier.getId(),
                file.getId(),
                Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build()));

        dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null);
        assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder("Darth Vader");
        dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId());
        assertThat(dossierDictionary.getEntries()).isEmpty();

        manualRedactionClient.undo(dossier.getDossierId(), file.getFileId(), Set.of("AnnotationId"));

        dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null);
        assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder("Luke Skywalker", "Darth Vader");
        dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId());
        assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrder("Luke Skywalker");
    }


    @Test
    public void testRemoveFromDossierIfOnlyDossierTemplateEntryExists() {

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

        var type = typeProvider.testAndProvideType(dossierTemplate);

        var entries = new ArrayList<String>();
        entries.add("Luke Skywalker");
        entries.add("Darth Vader");
        dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), entries, false, null, DictionaryEntryType.ENTRY);

        //FIXME should be created on the fly.
//        CreateTypeValue dossierDictionaryType = MagicConverter.convert(type, CreateTypeValue.class);
//        dictionaryClient.addType(dossierDictionaryType, dossier.getDossierId());

        var redactionLog = new RedactionLog(1,
                1,
                List.of(RedactionLogEntry.builder().id("AnnotationId").type("test").value("Luke Skywalker").isDictionaryEntry(true).build()),
                null,
                0,
                0,
                0,
                0);
        fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog);

        when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog);

        manualRedactionClient.removeRedactionBulk(dossier.getId(),
                file.getId(),
                Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).build())).get(0);

        var dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId(), dossier.getDossierId()), null);

        var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId()), null);
        assertThat(dossierTemplateDictionary.getEntries().size()).isEqualTo(2);
        assertThat(dossierTemplateDictionary.getEntries().stream().filter(e -> e.getValue().equals("Luke Skywalker")).findFirst().get().isDeleted()).isFalse();

        assertThat(dossierDictionary.getEntries().size()).isEqualTo(1);
        assertThat(dossierDictionary.getEntries().get(0).isDeleted()).isTrue();
    }


    @Test
    public void testRemoveFromAllDossiersIfOnlyDossierEntryExists() {

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

        var type = typeProvider.testAndProvideType(dossierTemplate);

        //FIXME should be created on the fly.
//        CreateTypeValue dossierDictionaryType = MagicConverter.convert(type, CreateTypeValue.class);
//        dictionaryClient.addType(dossierDictionaryType, dossier.getDossierId());
        dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), false, dossier.getDossierId(), DictionaryEntryType.ENTRY);

        var redactionLog = new RedactionLog(1,
                1,
                List.of(RedactionLogEntry.builder().id("AnnotationId").type("test").value("Luke Skywalker").isDictionaryEntry(true).isDossierDictionaryEntry(true).build()),
                null,
                0,
                0,
                0,
                0);
        fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog);

        when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog);

        manualRedactionClient.removeRedactionBulk(dossier.getId(),
                file.getId(),
                Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())).get(0);

        var dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId(), dossier.getDossierId()), null);
        assertThat(dossierDictionary.getEntries().size()).isEqualTo(1);
        assertThat(dossierDictionary.getEntries().get(0).isDeleted()).isTrue();

        var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId()), null);
        assertThat(dossierTemplateDictionary.getEntries().size()).isEqualTo(0);
    }


    @Test
    public void testEnlargeResizeRedactionInDossierDictionaryWithAddToAllDossiers() {

        // preparíng prerequisites
        var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();

        var dossier1 = dossierTesterAndProvider.provideTestDossier(dossierTemplate, "Dossier 1");
        var dossier2 = dossierTesterAndProvider.provideTestDossier(dossierTemplate, "Dossier 2");

        var file1 = fileTesterAndProvider.testAndProvideFile(dossier1);
        var file2 = fileTesterAndProvider.testAndProvideFile(dossier2);

        var typeDosDict = typeProvider.testAndProvideType(dossierTemplate, null, "typeDosDict", false, 99);
        var typeDosTempDict = typeProvider.testAndProvideType(dossierTemplate, null, "typeDosTempDict", false, 101);

        var userId = userProvider.getUserId();

        var redactionDos = AddRedactionRequestModel.builder()
                .positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build()))
                .section("section test")
                .addToDictionary(true)
                .addToAllDossiers(false)
                .type(typeDosDict.getType())
                .dictionaryEntryType(DictionaryEntryType.ENTRY)
                .reason("1")
                .value("test redaction in dossier")
                .legalBasis("1")
                .rectangle(false)
                .sourceId("SourceId")
                .build();

        var redactionDosTempDict = AddRedactionRequestModel.builder()
                .positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build()))
                .section("section test")
                .addToDictionary(true)
                .addToAllDossiers(true)
                .type(typeDosTempDict.getType())
                .dictionaryEntryType(DictionaryEntryType.ENTRY)
                .reason("1")
                .value("test redaction in dossier template")
                .legalBasis("1")
                .rectangle(false)
                .sourceId("SourceId")
                .build();

        var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getDossierId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict));
        var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId());

        var redactionLog1 = new RedactionLog(1,
                1,
                List.of(RedactionLogEntry.builder()
                                .id(addRedactions.get(0).getAnnotationId())
                                .type(typeDosDict.getType())
                                .value("test redaction in dossier")
                                .isDossierDictionaryEntry(true)
                                .build(),
                        RedactionLogEntry.builder()
                                .id(addRedactions.get(1).getAnnotationId())
                                .type(typeDosTempDict.getType())
                                .value("test redaction in dossier template")
                                .isDictionaryEntry(true)
                                .build()),
                null,
                0,
                0,
                0,
                0);
        fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.REDACTION_LOG, redactionLog1);
        var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build();
        when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId())).thenReturn(redactionLog1);

        var redactionLog2 = new RedactionLog(1,
                1,
                List.of(RedactionLogEntry.builder()
                        .id(addRedactions.get(1).getAnnotationId())
                        .type(typeDosTempDict.getType())
                        .value("test redaction in dossier template")
                        .isDictionaryEntry(true)
                        .build()),
                null,
                0,
                0,
                0,
                0);
        fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.REDACTION_LOG, redactionLog2);
        var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build();
        when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId())).thenReturn(redactionLog2);

        // resize redaction in dossier 1
        var resizeRedactionDosAndAddToAllDos = ResizeRedactionRequestModel.builder()
                .annotationId(addRedactions.get(0).getAnnotationId())
                .comment("resized dossier redaction")
                .value("test redaction in dossier dictionary")
                .updateDictionary(true)
                .addToAllDossiers(true)
                .build();

        manualRedactionClient.resizeRedactionBulk(dossier1.getDossierId(), file1.getFileId(), Set.of(resizeRedactionDosAndAddToAllDos));

        loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId());

        assertThat(loadedRedactionsFile1.getResizeRedactions()).hasSize(1);
        assertThat(loadedRedactionsFile1.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier dictionary");

        var dictEntries = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getDossierTemplateId(), "test redaction in dossier dictionary", DictionaryEntryType.ENTRY);
        assertThat(dictEntries.stream().filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier dictionary"))).isNotEmpty();

        var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId());
        assertThat(dictionaryOfTypeDosDictInDossier1.getEntries()).hasSize(1);
        assertThat(dictionaryOfTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier");

        var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId());
        assertThat(dictionaryOfTypeDosDictInDossier2.getEntries()).isEmpty();

        var dictionaryOfTypeDosDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossierTemplate.getDossierTemplateId(), null);
        assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries()).hasSize(1);
        assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier dictionary");

        var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId());
        assertThat(dictionaryOfTypeDosTempDictInDossier1.getEntries()).isEmpty();

        var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId());
        assertThat(dictionaryOfTypeDosTempDictInDossier2.getEntries()).isEmpty();

        var dictionaryOfTypeDosTempDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossierTemplate.getDossierTemplateId(), null);
        assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries()).hasSize(1);
        assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier template");

        var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId());
        assertThat(mergedDictForTypeDosDictInDossier1.getEntries()).hasSize(2);
        assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier");
        assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(1)).isEqualTo("test redaction in dossier dictionary");

        var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId());
        assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries()).hasSize(1);
        assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier template");

        var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId());
        assertThat(mergedDictForTypeDosDictInDossier2.getEntries()).hasSize(1);
        assertThat(mergedDictForTypeDosDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier dictionary");

        var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId());
        assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries()).hasSize(1);
        assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier template");
    }


    @Test
    public void testShrinkResizeRedactionInDossierDictionaryWithAddToAllDossiers() {

        // preparíng prerequisites
        var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();

        var dossier1 = dossierTesterAndProvider.provideTestDossier(dossierTemplate, "Dossier 1");
        var dossier2 = dossierTesterAndProvider.provideTestDossier(dossierTemplate, "Dossier 2");

        var file1 = fileTesterAndProvider.testAndProvideFile(dossier1);
        var file2 = fileTesterAndProvider.testAndProvideFile(dossier2);

        var typeDosDict = typeProvider.testAndProvideType(dossierTemplate, null, "typeDosDict", false, 99);
        var typeDosTempDict = typeProvider.testAndProvideType(dossierTemplate, null, "typeDosTempDict", false, 101);

        var userId = userProvider.getUserId();

        var redactionDos = AddRedactionRequestModel.builder()
                .positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build()))
                .section("section test")
                .addToDictionary(true)
                .addToAllDossiers(false)
                .type(typeDosDict.getType())
                .dictionaryEntryType(DictionaryEntryType.ENTRY)
                .reason("1")
                .value("test redaction in dossier yayy")
                .legalBasis("1")
                .rectangle(false)
                .sourceId("SourceId")
                .build();

        var redactionDosTempDict = AddRedactionRequestModel.builder()
                .positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build()))
                .section("section test")
                .addToDictionary(true)
                .addToAllDossiers(true)
                .type(typeDosTempDict.getType())
                .dictionaryEntryType(DictionaryEntryType.ENTRY)
                .reason("1")
                .value("test redaction in dossier template yayy")
                .legalBasis("1")
                .rectangle(false)
                .sourceId("SourceId")
                .build();

        var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getDossierId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict));
        var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId());

        var redactionLog1 = new RedactionLog(1,
                1,
                List.of(RedactionLogEntry.builder()
                                .id(addRedactions.get(0).getAnnotationId())
                                .type(typeDosDict.getType())
                                .value("test redaction in dossier yayy")
                                .isDossierDictionaryEntry(true)
                                .build(),
                        RedactionLogEntry.builder()
                                .id(addRedactions.get(1).getAnnotationId())
                                .type(typeDosTempDict.getType())
                                .value("test redaction in dossier template yayy")
                                .isDictionaryEntry(true)
                                .build()),
                null,
                0,
                0,
                0,
                0);
        fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.REDACTION_LOG, redactionLog1);
        var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build();
        when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId())).thenReturn(redactionLog1);

        var redactionLog2 = new RedactionLog(1,
                1,
                List.of(RedactionLogEntry.builder()
                        .id(addRedactions.get(1).getAnnotationId())
                        .type(typeDosTempDict.getType())
                        .value("test redaction in dossier template yayy")
                        .isDictionaryEntry(true)
                        .build()),
                null,
                0,
                0,
                0,
                0);
        fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.REDACTION_LOG, redactionLog2);
        var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build();
        when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId())).thenReturn(redactionLog2);

        // resize redaction in dossier 1
        var resizeRedactionDosAndAddToAllDos = ResizeRedactionRequestModel.builder()
                .annotationId(addRedactions.get(0).getAnnotationId())
                .comment("resized dossier redaction")
                .value("test redaction in dossier")
                .updateDictionary(true)
                .addToAllDossiers(true)
                .build();

        manualRedactionClient.resizeRedactionBulk(dossier1.getDossierId(), file1.getFileId(), Set.of(resizeRedactionDosAndAddToAllDos));

        loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId());

        assertThat(loadedRedactionsFile1.getResizeRedactions()).hasSize(1);
        assertThat(loadedRedactionsFile1.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier");

        var dictEntriesOldValue = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getDossierTemplateId(), "test redaction in dossier yayy", DictionaryEntryType.ENTRY);
        assertThat(dictEntriesOldValue.stream().filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier yayy") && dictionaryEntry.isDeleted())).hasSize(1);
        assertThat(dictEntriesOldValue.stream().filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier yayy") && !dictionaryEntry.isDeleted())).hasSize(1);
        var dictEntriesNewValue = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getDossierTemplateId(), "test redaction in dossier", DictionaryEntryType.ENTRY);
        assertThat(dictEntriesNewValue.stream().filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier"))).isNotEmpty();

        var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId());
        assertThat(dictionaryOfTypeDosDictInDossier1.getEntries()).hasSize(1);
        assertThat(dictionaryOfTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier yayy");

        var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId());
        assertThat(dictionaryOfTypeDosDictInDossier2.getEntries()).isEmpty();

        var dictionaryOfTypeDosDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossierTemplate.getDossierTemplateId(), null);
        assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries()).hasSize(1);
        assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier");

        var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId());
        assertThat(dictionaryOfTypeDosTempDictInDossier1.getEntries()).isEmpty();

        var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId());
        assertThat(dictionaryOfTypeDosTempDictInDossier2.getEntries()).isEmpty();

        var dictionaryOfTypeDosTempDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossierTemplate.getDossierTemplateId(), null);
        assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries()).hasSize(1);
        assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier template yayy");

        var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId());
        assertThat(mergedDictForTypeDosDictInDossier1.getEntries()).hasSize(2);
        assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier");
        assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(1)).isEqualTo("test redaction in dossier yayy");

        var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId());
        assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries()).hasSize(1);
        assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier template yayy");

        var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId());
        assertThat(mergedDictForTypeDosDictInDossier2.getEntries()).hasSize(1);
        assertThat(mergedDictForTypeDosDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier");

        var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId());
        assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries()).hasSize(1);
        assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier template yayy");
    }


    @Test
    public void testEnlargeResizeRedactionInDossierTemplateDictionaryWithAddToAllDossiers() {

        // preparíng prerequisites
        var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();

        var dossier1 = dossierTesterAndProvider.provideTestDossier(dossierTemplate, "Dossier 1");
        var dossier2 = dossierTesterAndProvider.provideTestDossier(dossierTemplate, "Dossier 2");

        var file1 = fileTesterAndProvider.testAndProvideFile(dossier1);
        var file2 = fileTesterAndProvider.testAndProvideFile(dossier2);

        var typeDosDict = typeProvider.testAndProvideType(dossierTemplate, null, "typeDosDict", false, 99);
        var typeDosTempDict = typeProvider.testAndProvideType(dossierTemplate, null, "typeDosTempDict", false, 101);

        var userId = userProvider.getUserId();

        var redactionDos = AddRedactionRequestModel.builder()
                .positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build()))
                .section("section test")
                .addToDictionary(true)
                .addToAllDossiers(false)
                .type(typeDosDict.getType())
                .dictionaryEntryType(DictionaryEntryType.ENTRY)
                .reason("1")
                .value("test redaction in dossier")
                .legalBasis("1")
                .rectangle(false)
                .sourceId("SourceId")
                .build();

        var redactionDosTempDict = AddRedactionRequestModel.builder()
                .positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build()))
                .section("section test")
                .addToDictionary(true)
                .addToAllDossiers(true)
                .type(typeDosTempDict.getType())
                .dictionaryEntryType(DictionaryEntryType.ENTRY)
                .reason("1")
                .value("test redaction in dossier template")
                .legalBasis("1")
                .rectangle(false)
                .sourceId("SourceId")
                .build();

        var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getDossierId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict));

        var redactionLog1 = new RedactionLog(1,
                1,
                List.of(RedactionLogEntry.builder()
                                .id(addRedactions.get(0).getAnnotationId())
                                .type(typeDosDict.getType())
                                .value("test redaction in dossier")
                                .isDossierDictionaryEntry(true)
                                .build(),
                        RedactionLogEntry.builder()
                                .id(addRedactions.get(1).getAnnotationId())
                                .type(typeDosTempDict.getType())
                                .value("test redaction in dossier template")
                                .isDictionaryEntry(true)
                                .build()),
                null,
                0,
                0,
                0,
                0);
        fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.REDACTION_LOG, redactionLog1);
        var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build();
        when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId())).thenReturn(redactionLog1);

        var redactionLog2 = new RedactionLog(1,
                1,
                List.of(RedactionLogEntry.builder()
                        .id(addRedactions.get(1).getAnnotationId())
                        .type(typeDosTempDict.getType())
                        .value("test redaction in dossier template")
                        .isDictionaryEntry(true)
                        .build()),
                null,
                0,
                0,
                0,
                0);
        fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.REDACTION_LOG, redactionLog2);
        var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build();
        when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId())).thenReturn(redactionLog2);

        // resize redaction in dossier dict
        var resizeRedactionDosTemp = ResizeRedactionRequestModel.builder()
                .annotationId(addRedactions.get(1).getAnnotationId())
                .comment("resized dossier template redaction")
                .value("test redaction in dossier template dictionary")
                .updateDictionary(true)
                .addToAllDossiers(true)
                .build();

        var resizeRedactions = manualRedactionClient.resizeRedactionBulk(dossier2.getDossierId(), file2.getFileId(), Set.of(resizeRedactionDosTemp));

        var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getDossierId(), file2.getFileId());

        assertThat(loadedRedactionsFile2.getResizeRedactions()).hasSize(1);
        assertThat(loadedRedactionsFile2.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier template dictionary");

        var dictEntries = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getDossierTemplateId(), "test redaction in dossier template dictionary", DictionaryEntryType.ENTRY);
        assertThat(dictEntries.stream().filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier template dictionary"))).hasSize(1);

        var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId());
        assertThat(dictionaryOfTypeDosDictInDossier1.getEntries()).hasSize(1);
        assertThat(dictionaryOfTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier");

        var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId());
        assertThat(dictionaryOfTypeDosDictInDossier2.getEntries()).isEmpty();

        var dictionaryOfTypeDosDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossierTemplate.getDossierTemplateId(), null);
        assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries()).isEmpty();

        var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId());
        assertThat(dictionaryOfTypeDosTempDictInDossier1.getEntries()).isEmpty();

        var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId());
        assertThat(dictionaryOfTypeDosTempDictInDossier2.getEntries()).isEmpty();

        var dictionaryOfTypeDosTempDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossierTemplate.getDossierTemplateId(), null);
        assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries()).hasSize(2);
        assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier template");
        assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries().get(1)).isEqualTo("test redaction in dossier template dictionary");

        var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId());
        assertThat(mergedDictForTypeDosDictInDossier1.getEntries()).hasSize(1);
        assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier");

        var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId());
        assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries()).hasSize(2);
        assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier template");
        assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries().get(1)).isEqualTo("test redaction in dossier template dictionary");

        var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId());
        assertThat(mergedDictForTypeDosDictInDossier2.getEntries()).isEmpty();

        var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId());
        assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries()).hasSize(2);
        assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier template");
        assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries().get(1)).isEqualTo("test redaction in dossier template dictionary");
    }


    @Test
    public void testShrinkResizeRedactionInDossierTemplateDictionaryWithAddToAllDossiers() {

        // preparíng prerequisites
        var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();

        var dossier1 = dossierTesterAndProvider.provideTestDossier(dossierTemplate, "Dossier 1");
        var dossier2 = dossierTesterAndProvider.provideTestDossier(dossierTemplate, "Dossier 2");

        var file1 = fileTesterAndProvider.testAndProvideFile(dossier1);
        var file2 = fileTesterAndProvider.testAndProvideFile(dossier2);

        var typeDosDict = typeProvider.testAndProvideType(dossierTemplate, null, "typeDosDict", false, 99);
        var typeDosTempDict = typeProvider.testAndProvideType(dossierTemplate, null, "typeDosTempDict", false, 101);

        var userId = userProvider.getUserId();

        var redactionDos = AddRedactionRequestModel.builder()
                .positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build()))
                .section("section test")
                .addToDictionary(true)
                .addToAllDossiers(false)
                .type(typeDosDict.getType())
                .dictionaryEntryType(DictionaryEntryType.ENTRY)
                .reason("1")
                .value("test redaction in dossier yayy")
                .legalBasis("1")
                .rectangle(false)
                .sourceId("SourceId")
                .build();

        var redactionDosTempDict = AddRedactionRequestModel.builder()
                .positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build()))
                .section("section test")
                .addToDictionary(true)
                .addToAllDossiers(true)
                .type(typeDosTempDict.getType())
                .dictionaryEntryType(DictionaryEntryType.ENTRY)
                .reason("1")
                .value("test redaction in dossier template yayy")
                .legalBasis("1")
                .rectangle(false)
                .sourceId("SourceId")
                .build();

        var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getDossierId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict));

        var redactionLog1 = new RedactionLog(1,
                1,
                List.of(RedactionLogEntry.builder()
                                .id(addRedactions.get(0).getAnnotationId())
                                .type(typeDosDict.getType())
                                .value("test redaction in dossier yayy")
                                .isDossierDictionaryEntry(true)
                                .build(),
                        RedactionLogEntry.builder()
                                .id(addRedactions.get(1).getAnnotationId())
                                .type(typeDosTempDict.getType())
                                .value("test redaction in dossier template yayy")
                                .isDictionaryEntry(true)
                                .build()),
                null,
                0,
                0,
                0,
                0);
        fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.REDACTION_LOG, redactionLog1);
        var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build();
        when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId())).thenReturn(redactionLog1);

        var redactionLog2 = new RedactionLog(1,
                1,
                List.of(RedactionLogEntry.builder()
                        .id(addRedactions.get(1).getAnnotationId())
                        .type(typeDosTempDict.getType())
                        .value("test redaction in dossier template yayy")
                        .isDictionaryEntry(true)
                        .build()),
                null,
                0,
                0,
                0,
                0);
        fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.REDACTION_LOG, redactionLog2);
        var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build();
        when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId())).thenReturn(redactionLog2);

        // resize redaction in dossier dict
        var resizeRedactionDosTemp = ResizeRedactionRequestModel.builder()
                .annotationId(addRedactions.get(1).getAnnotationId())
                .comment("resized dossier template redaction")
                .value("test redaction in dossier template")
                .updateDictionary(true)
                .addToAllDossiers(true)
                .build();

        var resizeRedactions = manualRedactionClient.resizeRedactionBulk(dossier2.getDossierId(), file2.getFileId(), Set.of(resizeRedactionDosTemp));

        var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getDossierId(), file2.getFileId());

        assertThat(loadedRedactionsFile2.getResizeRedactions()).hasSize(1);
        assertThat(loadedRedactionsFile2.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier template");

        var dictEntriesOldValue = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getDossierTemplateId(), "test redaction in dossier template yayy", DictionaryEntryType.ENTRY);
        assertThat(dictEntriesOldValue.stream()
                .filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier template yayy") && dictionaryEntry.isDeleted())).hasSize(3);
        assertThat(dictEntriesOldValue.stream()
                .filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier template yayy") && !dictionaryEntry.isDeleted())).isEmpty();
        var dictEntriesNewValue = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getDossierTemplateId(), "test redaction in dossier template", DictionaryEntryType.ENTRY);
        assertThat(dictEntriesNewValue.stream().filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier template"))).isNotEmpty();

        var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId());
        assertThat(dictionaryOfTypeDosDictInDossier1.getEntries()).hasSize(1);
        assertThat(dictionaryOfTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier yayy");

        var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId());
        assertThat(dictionaryOfTypeDosDictInDossier2.getEntries()).isEmpty();

        var dictionaryOfTypeDosDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossierTemplate.getDossierTemplateId(), null);
        assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries()).isEmpty();

        var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId());
        assertThat(dictionaryOfTypeDosTempDictInDossier1.getEntries()).isEmpty();

        var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId());
        assertThat(dictionaryOfTypeDosTempDictInDossier2.getEntries()).isEmpty();

        var dictionaryOfTypeDosTempDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossierTemplate.getDossierTemplateId(), null);
        assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries()).hasSize(1);
        assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier template");

        var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId());
        assertThat(mergedDictForTypeDosDictInDossier1.getEntries()).hasSize(1);
        assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier yayy");

        var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId());
        assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries()).hasSize(1);
        assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier template");

        var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId());
        assertThat(mergedDictForTypeDosDictInDossier2.getEntries()).isEmpty();

        var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId());
        assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries()).hasSize(1);
        assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier template");
    }

    @Test
    public void testManualRecategorizeAndUndo() {

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

        var type = typeProvider.testAndProvideType(dossierTemplate);
        var type2 = typeProvider.testAndProvideType(dossierTemplate, dossier, "test2", false, 66);

        var entries = new ArrayList<String>();

        var lukeSkywalker = "Luke Skywalker";
        var darthVader = "Darth Vader";
        entries.add(lukeSkywalker);
        entries.add(darthVader);
        dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), entries, false, null, DictionaryEntryType.ENTRY);

        dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of(lukeSkywalker), false, dossier.getDossierId(), DictionaryEntryType.ENTRY);

        Dictionary dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null);
        assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker, darthVader);
        Dictionary dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId());
        assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker);

        Dictionary dossierTemplateDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), null);
        assertThat(dossierTemplateDictionary2.getEntries()).isEmpty();
        Dictionary dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getDossierId());
        assertThat(dossierDictionary2.getEntries()).isEmpty();

        var annotationId = "AnnotationId";
        var redactionLog = new RedactionLog(1,
                1,
                List.of(RedactionLogEntry.builder().id(annotationId).type(type.getType()).value(lukeSkywalker).isDictionaryEntry(true).build()),
                null,
                0,
                0,
                0,
                0);
        fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog);

        when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog);

        manualRedactionClient.recategorizeBulk(dossier.getId(),
                file.getId(),
                Set.of(RecategorizationRequestModel.builder().type(type2.getType()).annotationId(annotationId).addToDictionary(true).addToAllDossiers(true).build()));

        dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null);
        assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(darthVader);
        dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId());
        assertThat(dossierDictionary.getEntries()).isEmpty();

        dossierTemplateDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), null);
        assertThat(dossierTemplateDictionary2.getEntries()).containsExactlyInAnyOrder(lukeSkywalker);
        dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getDossierId());
        assertThat(dossierDictionary2.getEntries()).isEmpty();

        manualRedactionClient.undo(dossier.getDossierId(), file.getFileId(), Set.of(annotationId));

        dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null);
        assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker, darthVader);
        dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId());
        assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker);

        dossierTemplateDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), null);
        assertThat(dossierTemplateDictionary2.getEntries()).isEmpty();
        dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getDossierId());
        assertThat(dossierDictionary2.getEntries()).isEmpty();
    }
}
