package com.iqser.red.persistence.service.v1.external.api.impl.controller;

import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.ADD_COMMENT;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.DELETE_COMMENT;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.DELETE_MANUAL_REDACTION;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.DO_MANUAL_REDACTION;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_MANUAL_REDACTIONS;
import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId;

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

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
import com.iqser.red.service.persistence.management.v1.processor.service.DossierManagementService;
import com.iqser.red.service.persistence.management.v1.processor.service.ManualRedactionService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.external.resource.ManualRedactionResource;
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
import com.iqser.red.service.persistence.service.v1.api.shared.model.CommentResponse;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.CommentRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualAddResponse;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.IdRemoval;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualForceRedaction;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualImageRecategorization;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualLegalBasisChange;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualRedactionEntry;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualResizeRedaction;
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddCommentRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ForceRedactionRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ImageRecategorizationRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ManualRedactionWrapper;
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequest;
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestController
@RequiredArgsConstructor
public class ManualRedactionController implements ManualRedactionResource {

    private static final String FILE_ID = "fileId";
    private static final String DOSSIER_ID = "dossierId";
    private static final String ANNOTATION_ID = "annotationId";
    private final ManualRedactionService manualRedactionService;
    private final DossierManagementService dossierManagementService;
    private final AuditPersistenceService auditPersistenceService;
    private final AccessControlService accessControlService;



    private ManualRedactionWrapper getLatestManualRedactionForAnnotationId(ManualRedactions manualRedactions, String annotationId) {

        final List<ManualRedactionWrapper> manualRedactionWrappers = new ArrayList<>();

        manualRedactions.getEntriesToAdd()
                .stream()
                .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
                .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item)));

        manualRedactions.getImageRecategorization()
                .stream()
                .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
                .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item)));

        manualRedactions.getIdsToRemove()
                .stream()
                .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
                .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item)));

        manualRedactions.getForceRedactions()
                .stream()
                .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
                .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item)));

        manualRedactions.getLegalBasisChanges()
                .stream()
                .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
                .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item)));

        manualRedactions.getResizeRedactions()
                .stream()
                .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
                .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item)));

        var sortedManualRedactionWrappers = manualRedactionWrappers.stream()
                .sorted(Comparator.comparing(ManualRedactionWrapper::getDate, Comparator.nullsLast(Comparator.reverseOrder())))
                .collect(Collectors.toList());

        return sortedManualRedactionWrappers.isEmpty() ? null : sortedManualRedactionWrappers.get(0);
    }


    @Override
    @PreAuthorize("hasAuthority('" + DELETE_MANUAL_REDACTION + "')")
    public void undo(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody Set<String> annotationIds) {

        accessControlService.verifyFileIsNotApproved(dossierId, fileId);
        accessControlService.verifyUserIsApprover(dossierId);

        ManualRedactions manualRedactions = manualRedactionService.getManualRedactions(fileId);

        Map<String, ManualRedactionWrapper> manualRedactionWrappers = getLatestManualRedactionsForAnnotationIds(manualRedactions, annotationIds);

        if (manualRedactionWrappers.isEmpty()) {
            throw new NotFoundException(String.format("ManualRedaction with annotationIds %s could not be found.", annotationIds));
        }

        List<String> manualRedactionEntries = manualRedactionWrappers.values()
                .stream()
                .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualRedactionEntry)
                .map(ManualRedactionWrapper::getId)
                .collect(Collectors.toList());
        if (!manualRedactionEntries.isEmpty()) {
            manualRedactionService.deleteAddRedaction(dossierId, fileId, manualRedactionEntries);
            manualRedactionEntries.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder()
                    .userId(KeycloakSecurity.getUserId())
                    .objectId(fileId)
                    .category(AuditCategory.DOCUMENT.name())
                    .message("Undo of manual add redaction was done.")
                    .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
                    .build()));
        }

        List<String> idRemovals = manualRedactionWrappers.values()
                .stream()
                .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof IdRemoval)
                .map(ManualRedactionWrapper::getId)
                .collect(Collectors.toList());
        if (!idRemovals.isEmpty()) {

            manualRedactionService.deleteRemoveRedaction(dossierId, fileId, idRemovals);
            idRemovals.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder()
                    .userId(KeycloakSecurity.getUserId())
                    .objectId(fileId)
                    .category(AuditCategory.DOCUMENT.name())
                    .message("Undo of manual remove redaction was done.")
                    .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
                    .build()));
        }

        List<String> manualForceRedactions = manualRedactionWrappers.values()
                .stream()
                .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualForceRedaction)
                .map(ManualRedactionWrapper::getId)
                .collect(Collectors.toList());
        if (!manualForceRedactions.isEmpty()) {

            manualRedactionService.deleteForceRedaction(dossierId, fileId, manualForceRedactions);
            manualForceRedactions.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder()
                    .userId(KeycloakSecurity.getUserId())
                    .objectId(fileId)
                    .category(AuditCategory.DOCUMENT.name())
                    .message("Undo of manual force redaction was done.")
                    .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
                    .build()));
        }

        List<String> manualImageRecategorizations = manualRedactionWrappers.values()
                .stream()
                .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualImageRecategorization)
                .map(ManualRedactionWrapper::getId)
                .collect(Collectors.toList());
        if (!manualImageRecategorizations.isEmpty()) {

            manualRedactionService.deleteImageRecategorization(dossierId, fileId, manualImageRecategorizations);
            manualImageRecategorizations.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder()
                    .userId(KeycloakSecurity.getUserId())
                    .objectId(fileId)
                    .category(AuditCategory.DOCUMENT.name())
                    .message("Undo of manual image recategorization was done.")
                    .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
                    .build()));
        }

        List<String> manualLegalBasisChanges = manualRedactionWrappers.values()
                .stream()
                .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualLegalBasisChange)
                .map(ManualRedactionWrapper::getId)
                .collect(Collectors.toList());
        if (!manualLegalBasisChanges.isEmpty()) {

            manualRedactionService.deleteLegalBasisChange(dossierId, fileId, manualLegalBasisChanges);
            manualLegalBasisChanges.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder()
                    .userId(KeycloakSecurity.getUserId())
                    .objectId(fileId)
                    .category(AuditCategory.DOCUMENT.name())
                    .message("Undo of legal basis change was done.")
                    .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
                    .build()));
        }

        List<String> manualResizeRedactions = manualRedactionWrappers.values()
                .stream()
                .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualResizeRedaction)
                .map(ManualRedactionWrapper::getId)
                .collect(Collectors.toList());
        if (!manualResizeRedactions.isEmpty()) {

            manualRedactionService.deleteResizeRedaction(dossierId, fileId, manualResizeRedactions);
            manualResizeRedactions.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder()
                    .userId(KeycloakSecurity.getUserId())
                    .objectId(fileId)
                    .category(AuditCategory.DOCUMENT.name())
                    .message("Undo of manual resize redaction was done.")
                    .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
                    .build()));
        }
    }


    private Map<String, ManualRedactionWrapper> getLatestManualRedactionsForAnnotationIds(ManualRedactions manualRedactions, Set<String> annotationIds) {

        Map<String, ManualRedactionWrapper> result = new HashMap<>();
        annotationIds.forEach(annotationId -> {
            var last = getLatestManualRedactionForAnnotationId(manualRedactions, annotationId);
            if (last != null) {
                result.put(annotationId, last);
            }
        });

        return result;
    }


    @Override
    @PreAuthorize("hasAuthority('" + DELETE_COMMENT + "')")
    public void undoComment(@PathVariable(DOSSIER_ID) String dossierId,
                            @PathVariable(FILE_ID) String fileId,
                            @PathVariable(ANNOTATION_ID) String annotationId,
                            @PathVariable(COMMENT_ID) String commentId) {

        accessControlService.verifyFileIsNotApproved(dossierId, fileId);
        accessControlService.verifyUserIsReviewerOrApprover(dossierId, fileId);

        auditPersistenceService.audit(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(fileId)
                .category(AuditCategory.DOCUMENT.name())
                .message("Comment was removed.")
                .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
                .build());
        manualRedactionService.deleteComment(fileId, List.of(Long.valueOf(commentId)));

    }


    @Override
    @PreAuthorize("hasAuthority('" + READ_MANUAL_REDACTIONS + "')")
    public ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {

        return manualRedactionService.getManualRedactions(fileId);
    }


    @Override
    @PreAuthorize("hasAuthority('" + ADD_COMMENT + "')")
    public CommentResponse addComment(@PathVariable(DOSSIER_ID) String dossierId,
                                      @PathVariable(FILE_ID) String fileId,
                                      @PathVariable(ANNOTATION_ID) String annotationId,
                                      @RequestBody AddCommentRequest addCommentRequest) {

        accessControlService.verifyFileIsNotApproved(dossierId, fileId);
        accessControlService.verifyUserIsReviewerOrApprover(dossierId, fileId);

        var response = manualRedactionService.addComment(fileId,
                annotationId,
                CommentRequest.builder().user(KeycloakSecurity.getUserId()).text(addCommentRequest.getText()).build());

        auditPersistenceService.audit(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(fileId)
                .category(AuditCategory.DOCUMENT.name())
                .message("Comment was added.")
                .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
                .build());

        return new CommentResponse(String.valueOf(response.getId()));
    }


    @Override
    @PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
    public List<ManualAddResponse> addRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
                                                    @PathVariable(FILE_ID) String fileId,
                                                    @RequestBody Set<AddRedactionRequest> addRedactionRequests) {

        var dossier = dossierManagementService.getDossierById(dossierId, false, false);

        accessControlService.verifyFileIsNotApproved(dossierId, fileId);
        if(addRedactionRequests.stream().anyMatch(AddRedactionRequest::isAddToAllDossiers)){
            accessControlService.verifyUserIsApprover(dossierId);
        } else {
            accessControlService.verifyUserIsMemberOrApprover(dossierId);
        }

        List<com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AddRedactionRequest> requests = new ArrayList<>();

        for (var addRedactionRequest : addRedactionRequests) {

            var addRedactionRequestBuilder = com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AddRedactionRequest.builder()
                    .value(addRedactionRequest.getValue())
                    .legalBasis(addRedactionRequest.getLegalBasis())
                    .user(KeycloakSecurity.getUserId())
                    .dossierTemplateTypeId(toTypeId(addRedactionRequest.getType(), dossier.getDossierTemplateId()))
                    .reason(addRedactionRequest.getReason())
                    .addToDictionary(addRedactionRequest.isAddToDictionary())
                    .status(AnnotationStatus.APPROVED)
                    .comment(addRedactionRequest.getComment() != null ? addRedactionRequest.getComment().getText() : null)
                    .section(addRedactionRequest.getSection())
                    .rectangle(addRedactionRequest.isRectangle())
                    .addToAllDossiers(addRedactionRequest.isAddToAllDossiers())
                    .forceAddToDictionary(addRedactionRequest.isForceAddToDictionary())
                    .positions(addRedactionRequest.getPositions())
                    .sourceId(addRedactionRequest.getSourceId())
                    .dossierId(dossierId)
                    .dictionaryEntryType(addRedactionRequest.getDictionaryEntryType());

            requests.add(addRedactionRequestBuilder.build());
        }
        List<ManualAddResponse> responseList = manualRedactionService.addAddRedaction(dossierId, fileId, requests);
        responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(fileId)
                .category(AuditCategory.DOCUMENT.name())
                .message("Manual redaction was added.")
                .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
                .build()));
        return responseList;
    }


    @PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
    public List<ManualAddResponse> removeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
                                                       @PathVariable(FILE_ID) String fileId,
                                                       @RequestBody Set<RemoveRedactionRequest> removeRedactionRequests) {

        accessControlService.verifyFileIsNotApproved(dossierId, fileId);
        if(removeRedactionRequests.stream().anyMatch(RemoveRedactionRequest::isRemoveFromAllDossiers)){
            accessControlService.verifyUserIsApprover(dossierId);
        } else {
            accessControlService.verifyUserIsMemberOrApprover(dossierId);
        }

        List<com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RemoveRedactionRequest> requests = new ArrayList<>();

        for (var removeRedactionRequest : removeRedactionRequests) {
            var removeRedactionRequestBuilder = com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RemoveRedactionRequest.builder()
                    .annotationId(removeRedactionRequest.getAnnotationId())
                    .user(KeycloakSecurity.getUserId())
                    .status(AnnotationStatus.APPROVED)
                    .removeFromDictionary(removeRedactionRequest.isRemoveFromDictionary())
                    .removeFromAllDossiers(removeRedactionRequest.isRemoveFromAllDossiers());

            if (removeRedactionRequest.getComment() != null) {
                removeRedactionRequestBuilder.comment(removeRedactionRequest.getComment());
            }

            requests.add(removeRedactionRequestBuilder.build());
        }
        List<ManualAddResponse> responseList = manualRedactionService.addRemoveRedaction(dossierId, fileId, requests);

        responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(fileId)
                .category(AuditCategory.DOCUMENT.name())
                .message("Redaction was manually removed")
                .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
                .build()));

        return responseList;
    }


    @PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
    public List<ManualAddResponse> forceRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
                                                      @PathVariable(FILE_ID) String fileId,
                                                      @RequestBody Set<ForceRedactionRequest> forceRedactionRequests) {

        accessControlService.verifyFileIsNotApproved(dossierId, fileId);
        accessControlService.verifyUserIsMemberOrApprover(dossierId);

        List<com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ForceRedactionRequest> requests = forceRedactionRequests.stream()
                .map(forceRedactionRequest -> com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ForceRedactionRequest.builder()
                        .annotationId(forceRedactionRequest.getAnnotationId())
                        .user(KeycloakSecurity.getUserId())
                        .status(AnnotationStatus.APPROVED)
                        .legalBasis(forceRedactionRequest.getLegalBasis())
                        .comment(forceRedactionRequest.getComment())
                        .build())
                .collect(Collectors.toList());
        List<ManualAddResponse> responseList = manualRedactionService.addForceRedaction(dossierId, fileId, requests);

        responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(fileId)
                .category(AuditCategory.DOCUMENT.name())
                .message("Skipped redaction was forced to be redacted")
                .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
                .build()));

        return responseList;
    }


    @PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
    public List<ManualAddResponse> legalBasisChangeBulk(@PathVariable(DOSSIER_ID) String dossierId,
                                                        @PathVariable(FILE_ID) String fileId,
                                                        @RequestBody Set<LegalBasisChangeRequest> legalBasisChangeRequests) {

        accessControlService.verifyFileIsNotApproved(dossierId, fileId);
        accessControlService.verifyUserIsMemberOrApprover(dossierId);

        List<com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.LegalBasisChangeRequest> requests = legalBasisChangeRequests.stream()
                .map(legalBasisChangeRequest -> com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.LegalBasisChangeRequest.builder()
                        .annotationId(legalBasisChangeRequest.getAnnotationId())
                        .user(KeycloakSecurity.getUserId())
                        .status(AnnotationStatus.APPROVED)
                        .section(legalBasisChangeRequest.getSection())
                        .legalBasis(legalBasisChangeRequest.getLegalBasis())
                        .comment(legalBasisChangeRequest.getComment())
                        .value(legalBasisChangeRequest.getValue())
                        .build())
                .collect(Collectors.toList());

        List<ManualAddResponse> responseList = manualRedactionService.addLegalBasisChange(dossierId, fileId, requests);

        responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(fileId)
                .category(AuditCategory.DOCUMENT.name())
                .message("Legal basis reason was changed")
                .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
                .build()));

        return responseList;
    }


    @PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
    public List<ManualAddResponse> recategorizeImageBulk(@PathVariable(DOSSIER_ID) String dossierId,
                                                         @PathVariable(FILE_ID) String fileId,
                                                         @RequestBody Set<ImageRecategorizationRequest> imageRecategorizationRequests) {

        var dossier = dossierManagementService.getDossierById(dossierId, false, false);
        accessControlService.verifyFileIsNotApproved(dossierId, fileId);
        accessControlService.verifyUserIsMemberOrApprover(dossierId);

        List<com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ImageRecategorizationRequest> requests = imageRecategorizationRequests.stream()
                .map(imageRecategorizationRequest -> com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ImageRecategorizationRequest.builder()
                        .annotationId(imageRecategorizationRequest.getAnnotationId())
                        .user(KeycloakSecurity.getUserId())
                        .status(AnnotationStatus.APPROVED)
                        .typeId(toTypeId(imageRecategorizationRequest.getType(), dossier.getDossierTemplateId()))
                        .comment(imageRecategorizationRequest.getComment())
                        .build())
                .collect(Collectors.toList());

        List<ManualAddResponse> responseList = manualRedactionService.addImageRecategorization(dossierId, fileId, requests);

        responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(fileId)
                .category(AuditCategory.DOCUMENT.name())
                .message("Image was recategorized")
                .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
                .build()));

        return responseList;
    }


    @PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
    public List<ManualAddResponse> resizeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
                                                       @PathVariable(FILE_ID) String fileId,
                                                       @RequestBody Set<ResizeRedactionRequest> resizeRedactionRequests) {
        accessControlService.verifyFileIsNotApproved(dossierId, fileId);
        accessControlService.verifyUserIsMemberOrApprover(dossierId);

        List<com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ResizeRedactionRequest> requests = resizeRedactionRequests.stream()
                .map(resizeRedactionRequest -> com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ResizeRedactionRequest.builder()
                        .annotationId(resizeRedactionRequest.getAnnotationId())
                        .user(KeycloakSecurity.getUserId())
                        .status(AnnotationStatus.APPROVED)
                        .positions(resizeRedactionRequest.getPositions())
                        .value(resizeRedactionRequest.getValue())
                        .comment(resizeRedactionRequest.getComment())
                        .updateDictionary(resizeRedactionRequest.getUpdateDictionary())
                        .addToAllDossiers(resizeRedactionRequest.isAddToAllDossiers())
                        .build())
                .collect(Collectors.toList());

        List<ManualAddResponse> responseList = manualRedactionService.addResizeRedaction(dossierId, fileId, requests);

        responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(fileId)
                .category(AuditCategory.DOCUMENT.name())
                .message("Skipped redaction was resized to be redacted")
                .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
                .build()));

        return responseList;
    }

}
