package com.iqser.red.service.persistence.management.v1.processor.service.manualredactions;

import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId;

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

import org.springframework.stereotype.Service;

import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AddRedactionRequest;
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.ForceRedactionRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.LegalBasisChangeRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RecategorizationRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RemoveRedactionRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ResizeRedactionRequest;
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.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.ForceRedactionRequestModel;
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequestModel;
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 com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;

import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;

@Service
@RequiredArgsConstructor
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class ManualRedactionMapper {

    RedactionLogService redactionLogService;


    public List<AddRedactionRequest> toAddRedactionRequestList(String dossierId, Set<AddRedactionRequestModel> addRedactionRequests, Dossier dossier) {

        return addRedactionRequests.stream()
                .map(addRedactionRequest -> toAddRedactionRequest(dossierId, dossier.getDossierTemplateId(), addRedactionRequest))
                .collect(Collectors.toList());
    }


    public AddRedactionRequest toAddRedactionRequest(String dossierId, String dossierTemplateId, AddRedactionRequestModel addRedactionRequest) {

        return AddRedactionRequest.builder()
                .value(StringCleaningUtility.cleanString(addRedactionRequest.getValue()))
                .legalBasis(addRedactionRequest.getLegalBasis())
                .user(KeycloakSecurity.getUserId())
                .dossierTemplateTypeId(toTypeId(addRedactionRequest.getType(), dossierTemplateId))
                .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() != null ? addRedactionRequest.getDictionaryEntryType() : DictionaryEntryType.ENTRY)
                .build();
    }


    public List<RemoveRedactionRequest> toRemoveRedactionRequestList(String dossierId,
                                                                     String fileId,
                                                                     String dossierTemplateId,
                                                                     Set<RemoveRedactionRequestModel> removeRedactionRequests) {

        List<RemoveRedactionRequest> requests = new ArrayList<>();
        RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId);
        for (var removeRedactionRequest : removeRedactionRequests) {
            RedactionLogEntry redactionLogEntry = getRedactionLogEntry(redactionLog, removeRedactionRequest.getAnnotationId());
            var removeRedactionRequestBuilder = RemoveRedactionRequest.builder()
                    .annotationId(removeRedactionRequest.getAnnotationId())
                    .user(KeycloakSecurity.getUserId())
                    .status(AnnotationStatus.APPROVED)
                    .removeFromDictionary(removeRedactionRequest.isRemoveFromDictionary())
                    .removeFromAllDossiers(removeRedactionRequest.isRemoveFromAllDossiers())
                    .value(redactionLogEntry.getValue())
                    .dictionaryEntryType(getDictionaryEntryType(redactionLogEntry))
                    .typeToRemove(redactionLogEntry.getType())
                    .dossierId(dossierId)
                    .dossierTemplateId(dossierTemplateId);

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

            requests.add(removeRedactionRequestBuilder.build());
        }
        return requests;
    }


    public List<ForceRedactionRequest> toForceRedactionRequestList(Set<ForceRedactionRequestModel> forceRedactionRequests) {

        return forceRedactionRequests.stream()
                .map(forceRedactionRequest -> ForceRedactionRequest.builder()
                        .annotationId(forceRedactionRequest.getAnnotationId())
                        .user(KeycloakSecurity.getUserId())
                        .status(AnnotationStatus.APPROVED)
                        .legalBasis(forceRedactionRequest.getLegalBasis())
                        .comment(forceRedactionRequest.getComment())
                        .build())
                .collect(Collectors.toList());
    }


    public List<LegalBasisChangeRequest> toLegalBasisChangeRequestList(Set<LegalBasisChangeRequestModel> legalBasisChangeRequests) {

        return legalBasisChangeRequests.stream()
                .map(legalBasisChangeRequest -> 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());
    }


    public List<RecategorizationRequest> toRecategorizationRequestList(String dossierId,
                                                                       String fileId,
                                                                       String dossierTemplateId,
                                                                       Set<RecategorizationRequestModel> recategorizationRequests) {

        RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId);
        List<RecategorizationRequest> requests = new ArrayList<>();
        for (RecategorizationRequestModel recategorizationRequest : recategorizationRequests) {
            RedactionLogEntry redactionLogEntry = getRedactionLogEntry(redactionLog, recategorizationRequest.getAnnotationId());
            RecategorizationRequest build = RecategorizationRequest.builder()
                    .annotationId(recategorizationRequest.getAnnotationId())
                    .user(KeycloakSecurity.getUserId())
                    .status(AnnotationStatus.APPROVED)
                    .dossierTemplateId(dossierTemplateId)
                    .comment(recategorizationRequest.getComment())
                    .dossierId(dossierId)
                    .addToDictionary(recategorizationRequest.isAddToDictionary())
                    .addToAllDossiers(recategorizationRequest.isAddToAllDossiers())
                    .dictionaryEntryType(getDictionaryEntryType(redactionLogEntry))
                    .value(redactionLogEntry.getValue())
                    .typeToRemove(redactionLogEntry.getType())
                    .dossierTemplateTypeId(toTypeId(recategorizationRequest.getType(), dossierTemplateId))
                    .build();
            requests.add(build);
        }

        return requests;
    }


    public List<ResizeRedactionRequest> toResizeRedactionRequestList(Set<ResizeRedactionRequestModel> resizeRedactionRequests) {

        return resizeRedactionRequests.stream()
                .map(resizeRedactionRequest -> ResizeRedactionRequest.builder()
                        .annotationId(resizeRedactionRequest.getAnnotationId())
                        .user(KeycloakSecurity.getUserId())
                        .status(AnnotationStatus.APPROVED)
                        .positions(resizeRedactionRequest.getPositions())
                        .value(StringCleaningUtility.cleanString(resizeRedactionRequest.getValue()))
                        .comment(resizeRedactionRequest.getComment())
                        .updateDictionary(resizeRedactionRequest.getUpdateDictionary())
                        .addToAllDossiers(resizeRedactionRequest.isAddToAllDossiers())
                        .build())
                .collect(Collectors.toList());
    }


    private RedactionLogEntry getRedactionLogEntry(RedactionLog redactionLog, String annotationId) {

        return redactionLog.getRedactionLogEntry()
                .stream()
                .filter(entry -> entry.getId().equals(annotationId))
                .findFirst()
                .orElseThrow(() -> new NotFoundException("Annotation does not exist in redaction log."));
    }


    private DictionaryEntryType getDictionaryEntryType(RedactionLogEntry redactionLogEntry) {

        if (redactionLogEntry.isRecommendation() && redactionLogEntry.isFalsePositive()) {
            return DictionaryEntryType.FALSE_RECOMMENDATION;
        } else if (redactionLogEntry.isFalsePositive()) {
            return DictionaryEntryType.FALSE_POSITIVE;
        } else {
            return DictionaryEntryType.ENTRY;
        }
    }

}
