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

import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
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.ManualLegalBasisChangeEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.LegalBasisChangeRepository;
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.LegalBasisChangeRequest;

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

@Slf4j
@Service
@RequiredArgsConstructor
public class LegalBasisChangePersistenceService {

    private final int SECTION_MAX_LENGTH = 1024;
    private final LegalBasisChangeRepository legalBasisChangeRepository;


    public ManualLegalBasisChangeEntity insert(String fileId, LegalBasisChangeRequest legalBasisChangeRequest) {

        ManualLegalBasisChangeEntity manualLegalBasisChange = new ManualLegalBasisChangeEntity();
        manualLegalBasisChange.setId(new AnnotationEntityId(legalBasisChangeRequest.getAnnotationId(), fileId));
        checkSection(legalBasisChangeRequest.getSection());
        BeanUtils.copyProperties(legalBasisChangeRequest, manualLegalBasisChange);
        manualLegalBasisChange.setRequestDate(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));

        if (legalBasisChangeRequest.getStatus() == AnnotationStatus.APPROVED) {
            manualLegalBasisChange.setProcessedDate(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
        }

        return legalBasisChangeRepository.saveAndFlush(manualLegalBasisChange);

    }

    private void checkSection(String section) {

        if (!StringUtils.isEmpty(section) && section.length() > SECTION_MAX_LENGTH) {
            throw new BadRequestException(String.format("The section is too long (%s), max length %s", section.length(), SECTION_MAX_LENGTH));
        }
    }


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

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


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

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


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

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


    @Transactional
    public void updateStatus(String fileId, String annotationId, AnnotationStatus annotationStatus) {

        legalBasisChangeRepository.updateStatus(new AnnotationEntityId(annotationId, fileId), annotationStatus, OffsetDateTime.now());
    }


    public ManualLegalBasisChangeEntity findLegalBasisChange(String fileId, String annotationId) {

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


    public Set<ManualLegalBasisChangeEntity> findLegalBasisChanges(String fileId, boolean includeDeletions) {

        return legalBasisChangeRepository.findByFileIdIncludeDeletions(fileId, includeDeletions).stream().collect(Collectors.toSet());

    }


    public void markAsProcessed(String annotationId, String fileId) {

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

}
