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

import static com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter.convert;

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

import jakarta.transaction.Transactional;

import org.springframework.stereotype.Service;

import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.LegalBasisEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.LegalBasisMappingEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.LegalBasisMappingRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.legalbasis.LegalBasis;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class LegalBasisMappingPersistenceService {

    private final LegalBasisMappingRepository legalBasisMappingRepository;

    private final int MAX_NAME_LENGTH = 255;
    private final int MAX_LEGAL_BASIS_LENGTH = 4000;


    @Transactional
    public void deleteLegalBasis(String dossierTemplateId, List<String> legalBasisNames) {

        var mapping = getLegalBasisMappingOrCreate(dossierTemplateId);
        var filteredLegalBasis = mapping.getLegalBasis().stream().filter(l -> !legalBasisNames.contains(l.getName())).collect(Collectors.toList());

        mapping.setLegalBasis(filteredLegalBasis);
        mapping.setVersion(mapping.getVersion() + 1);
        legalBasisMappingRepository.save(mapping);

    }


    @Transactional
    public void deleteLegalBasis(String dossierTemplateId) {

        var mapping = getLegalBasisMappingOrCreate(dossierTemplateId);
        mapping.setLegalBasis(Collections.emptyList());
        mapping.setVersion(mapping.getVersion() + 1);
        legalBasisMappingRepository.save(mapping);
    }


    private LegalBasisMappingEntity getLegalBasisMappingOrCreate(String dossierTemplateId) {

        return legalBasisMappingRepository.findById(dossierTemplateId).orElseGet(() -> {
            // create on get if not present
            var lbm = new LegalBasisMappingEntity();
            lbm.setDossierTemplateId(dossierTemplateId);
            lbm.setLegalBasis(new ArrayList<>());
            lbm.setVersion(1);
            return legalBasisMappingRepository.save(lbm);

        });
    }


    @Transactional
    public void addOrUpdateLegalBasis(String dossierTemplateId, LegalBasis legalBasis) {

        validateLegalBasis(legalBasis);
        var mapping = getLegalBasisMappingOrCreate(dossierTemplateId);

        mapping.getLegalBasis().stream().filter(l -> l.getName().equals(legalBasis.getName())).findAny().ifPresentOrElse(existingBasis -> {
                    existingBasis.setReason(legalBasis.getReason());
                    existingBasis.setDescription(legalBasis.getDescription());
                },
                () -> mapping.getLegalBasis()
                        .add(LegalBasisEntity.builder().name(legalBasis.getName()).description(legalBasis.getDescription()).reason(legalBasis.getReason()).build()));

        mapping.setVersion(mapping.getVersion() + 1);
        legalBasisMappingRepository.save(mapping);

    }

    private void validateLegalBasis(LegalBasis legalBasis) {

        if (legalBasis.getName().length() > MAX_NAME_LENGTH) {
            throw new BadRequestException(String.format("The name is too long (%s), max length %s", legalBasis.getName().length(), MAX_NAME_LENGTH));
        }

        if (legalBasis.getDescription().length() > MAX_LEGAL_BASIS_LENGTH) {
            throw new BadRequestException(String.format("The description is too long (%s), max length %s", legalBasis.getDescription().length(), MAX_LEGAL_BASIS_LENGTH));
        }

        if (legalBasis.getReason().length() > MAX_LEGAL_BASIS_LENGTH) {
            throw new BadRequestException(String.format("The legal basis is too long (%s), max length %s", legalBasis.getReason().length(), MAX_LEGAL_BASIS_LENGTH));
        }
    }


    @Transactional
    public void setLegalBasisMapping(String dossierTemplateId, List<LegalBasis> legalBasisMapping) {

        legalBasisMappingRepository.findById(dossierTemplateId).ifPresentOrElse((lbm) -> {
            lbm.setVersion(lbm.getVersion() + 1);
            lbm.setLegalBasis(convert(legalBasisMapping, LegalBasisEntity.class));
            legalBasisMappingRepository.save(lbm);
        }, () -> {
            var lbm = new LegalBasisMappingEntity();
            lbm.setDossierTemplateId(dossierTemplateId);
            lbm.setLegalBasis(convert(legalBasisMapping, LegalBasisEntity.class));
            lbm.setVersion(1);
            legalBasisMappingRepository.save(lbm);
        });

    }


    @Transactional
    public List<LegalBasisEntity> getLegalBasisMapping(String dossierTemplateId) {

        return getLegalBasisMappingOrCreate(dossierTemplateId).getLegalBasis();
    }


    public long getVersion(String dossierTemplateId) {

        return legalBasisMappingRepository.findById(dossierTemplateId).map(LegalBasisMappingEntity::getVersion).orElse(0L);
    }

}
