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

import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.AnnotationEntityId;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRecategorizationEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.RecategorizationRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RecategorizationRequest;

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

@Slf4j
@Service
@RequiredArgsConstructor
public class RecategorizationPersistenceService {

    private final RecategorizationRepository recategorizationRepository;


    public ManualRecategorizationEntity createOrUpdate(String fileId, RecategorizationRequest request) {

        AnnotationEntityId id = new AnnotationEntityId(request.getAnnotationId(), fileId);

        ManualRecategorizationEntity entity = recategorizationRepository.findById(id)
                .orElse(buildEntity(id));

        entity.setUser(request.getUser());

        if (request.getDictionaryTypeId() != null) {
            entity.setTypeId(request.getDictionaryTypeId());
        }

        entity.setRequestDate(OffsetDateTime.now());
        entity.setPage(request.getPage());
        entity.setAddToDictionary(request.isAddToDictionary());
        entity.setAddToAllDossiers(request.isAddToAllDossiers());

        if (request.getLegalBasis() != null) {
            entity.setLegalBasis(request.getLegalBasis());
        }

        if (request.getSection() != null) {
            entity.setSection(request.getSection());
        }

        if (request.getValue() != null) {
            entity.setValue(request.getValue());
        }
        entity.setProcessedDate(null);
        entity.setSoftDeletedTime(null);
        return entity;
    }


    private static ManualRecategorizationEntity buildEntity(AnnotationEntityId id) {

        var e = new ManualRecategorizationEntity();
        e.setId(id);
        return e;
    }


    @Transactional
    public void hardDelete(String fileId, String annotationId) {

        recategorizationRepository.deleteByIdIs(new AnnotationEntityId(annotationId, fileId));
    }


    @Transactional
    public void softDelete(String fileId, String annotationId, OffsetDateTime softDeleteTime) {

        recategorizationRepository.updateSoftDelete(new AnnotationEntityId(annotationId, fileId), softDeleteTime);
    }


    @Transactional
    public void undelete(String fileId, String annotationId) {

        recategorizationRepository.updateSoftDelete(new AnnotationEntityId(annotationId, fileId), null);
    }


    public ManualRecategorizationEntity findRecategorization(String fileId, String annotationId) {

        return recategorizationRepository.findByIdAndNotSoftDeleted(new AnnotationEntityId(annotationId, fileId))
                .orElseThrow(() -> new NotFoundException("Unknown file/annotation combination: " + fileId + "/" + annotationId));
    }


    public List<ManualRecategorizationEntity> findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) {

        if (options.getAnnotationIds().isEmpty()) {
            return recategorizationRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges());
        }
        return recategorizationRepository.findByFileIdAndOptionsAndAnnotationIds(fileId,
                                                                                 options.isIncludeDeletions(),
                                                                                 options.isIncludeOnlyUnprocessed(),
                                                                                 options.isIncludeDictChanges(),
                                                                                 options.getAnnotationIds());
    }


    public int softDeleteByFileIds(List<String> fileIds, OffsetDateTime softDeletionTime) {

        return recategorizationRepository.softDeleteByFileIds(fileIds, softDeletionTime);
    }


    public int deleteByFileIds(List<String> fileIds) {

        return recategorizationRepository.deleteByFileIds(fileIds);
    }


    @Transactional
    public void markAsProcessed(String annotationId, String fileId) {

        recategorizationRepository.markAsProcessed(new AnnotationEntityId(annotationId, fileId), OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
    }


    @Transactional
    public void saveAndFlush(ManualRecategorizationEntity recategorizationEntity) {

        recategorizationRepository.saveAndFlush(recategorizationEntity);
    }


    public void undeleteByFileId(String fileId, OffsetDateTime deletionTime) {

        recategorizationRepository.undeleteByFileId(fileId, deletionTime);
    }

}
