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

import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.BaseDictionaryEntry;
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.DictionaryEntryEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.DictionaryFalsePositiveEntryEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.DictionaryFalseRecommendationEntryEntity;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.TypeRepository;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.EntryRepository;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.FalsePositiveEntryRepository;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.FalseRecommendationEntryRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType;
import com.knecon.fforesight.databasetenantcommons.providers.utils.JDBCWriteUtils;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

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

@Service
@Slf4j
@RequiredArgsConstructor
public class EntryPersistenceService {

    private final EntryRepository entryRepository;
    private final TypeRepository typeRepository;
    private final FalsePositiveEntryRepository falsePositiveEntryRepository;
    private final FalseRecommendationEntryRepository falseRecommendationEntryRepository;
    private final JDBCWriteUtils jdbcWriteUtils;


    public List<?> getAllEntriesInDossierTemplate(String dossierTemplateTypeId, String value, DictionaryEntryType dictionaryEntryType) {

        switch (dictionaryEntryType) {
            case ENTRY -> {
                return entryRepository.findByTypeIdContainsAndValue(dossierTemplateTypeId, value);
            }
            case FALSE_POSITIVE -> {
                return falsePositiveEntryRepository.findByTypeIdContainsAndValue(dossierTemplateTypeId, value);
            }
            case FALSE_RECOMMENDATION -> {
                return falseRecommendationEntryRepository.findByTypeIdContainsAndValue(dossierTemplateTypeId, value);
            }
            default -> {
                return new ArrayList<>();
            }
        }
    }

    @Transactional
    public void insertDeleteEntries(String typeId, Set<String> values, long version, DictionaryEntryType dictionaryEntryType) {

        switch (dictionaryEntryType) {
            case ENTRY -> entryRepository.deleteAllByTypeIdAndVersionAndValueIn(typeId, values, version);
            case FALSE_POSITIVE ->
                    falsePositiveEntryRepository.deleteAllByTypeIdAndVersionAndValueIn(typeId, values, version);
            case FALSE_RECOMMENDATION ->
                    falseRecommendationEntryRepository.deleteAllByTypeIdAndVersionAndValueIn(typeId, values, version);
        }
    }


    @Transactional
    public void deleteEntries(String typeId, Set<String> values, long version, DictionaryEntryType dictionaryEntryType) {

        switch (dictionaryEntryType) {
            case ENTRY -> entryRepository.deleteAllByTypeIdAndVersionAndValueIn(typeId, values, version);
            case FALSE_POSITIVE ->
                    falsePositiveEntryRepository.deleteAllByTypeIdAndVersionAndValueIn(typeId, values, version);
            case FALSE_RECOMMENDATION ->
                    falseRecommendationEntryRepository.deleteAllByTypeIdAndVersionAndValueIn(typeId, values, version);
        }
    }


    @Transactional
    public void setVersion(String typeId, long version, DictionaryEntryType dictionaryEntryType) {

        switch (dictionaryEntryType) {
            case ENTRY -> entryRepository.updateVersionWhereTypeId(version, typeId);
            case FALSE_POSITIVE -> falsePositiveEntryRepository.updateVersionWhereTypeId(version, typeId);
            case FALSE_RECOMMENDATION -> falseRecommendationEntryRepository.updateVersionWhereTypeId(version, typeId);
        }
    }


    public List<? extends BaseDictionaryEntry> getEntries(String typeId, DictionaryEntryType dictionaryEntryType, Long fromVersion) {

        return switch (dictionaryEntryType) {
            case ENTRY ->
                    entryRepository.findByTypeIdAndVersionGreaterThan(typeId, fromVersion != null ? fromVersion : -1);
            case FALSE_POSITIVE ->
                    falsePositiveEntryRepository.findByTypeIdAndVersionGreaterThan(typeId, fromVersion != null ? fromVersion : -1);
            case FALSE_RECOMMENDATION ->
                    falseRecommendationEntryRepository.findByTypeIdAndVersionGreaterThan(typeId, fromVersion != null ? fromVersion : -1);
        };
    }


    @Transactional
    public void deleteAllEntriesForTypeId(String typeId, long version, DictionaryEntryType dictionaryEntryType) {

        switch (dictionaryEntryType) {
            case ENTRY -> entryRepository.deleteAllEntriesForTypeId(typeId, version);
            case FALSE_POSITIVE -> falsePositiveEntryRepository.deleteAllEntriesForTypeId(typeId, version);
            case FALSE_RECOMMENDATION -> falseRecommendationEntryRepository.deleteAllEntriesForTypeId(typeId, version);
        }
    }

    @Transactional
    public void addEntries(String typeId, Set<String> entries, long version, DictionaryEntryType dictionaryEntryType) {
        addEntries(typeId, entries, version, dictionaryEntryType, false);
    }

    @Transactional
    public void addDeleteEntries(String typeId, Set<String> entries, long version, DictionaryEntryType dictionaryEntryType) {
        addEntries(typeId, entries, version, dictionaryEntryType, true);
    }

    @Transactional
    public void addEntries(String typeId, Set<String> entries, long version, DictionaryEntryType dictionaryEntryType, boolean deleted) {

        var type = typeRepository.getById(typeId);

        switch (dictionaryEntryType) {
            case ENTRY -> {
                var undeletedEntries = entryRepository.undeleteEntries(typeId, entries, version);

                undeletedEntries.forEach(entries::remove);

                var entryEntities = entries.stream().map(e -> {
                    DictionaryEntryEntity entry = new DictionaryEntryEntity();
                    entry.setVersion(version);
                    entry.setValue(e);
                    entry.setTypeId(type.getId());
                    entry.setDeleted(deleted);
                    return entry;

                }).collect(Collectors.toList());

                jdbcWriteUtils.saveBatch(entryEntities);
            }
            case FALSE_POSITIVE -> {
                var undeletedEntries = falsePositiveEntryRepository.undeleteEntries(typeId, entries, version);
                undeletedEntries.forEach(entries::remove);

                var entryEntities = entries.stream().map(e -> {
                    DictionaryFalsePositiveEntryEntity entry = new DictionaryFalsePositiveEntryEntity();
                    entry.setVersion(version);
                    entry.setValue(e);
                    entry.setTypeId(type.getId());
                    entry.setDeleted(deleted);
                    return entry;

                }).collect(Collectors.toList());
                jdbcWriteUtils.saveBatch(entryEntities);
            }
            case FALSE_RECOMMENDATION -> {
                var undeletedEntries = falseRecommendationEntryRepository.undeleteEntries(typeId, entries, version);
                undeletedEntries.forEach(entries::remove);

                var entryEntities = entries.stream().map(e -> {
                    DictionaryFalseRecommendationEntryEntity entry = new DictionaryFalseRecommendationEntryEntity();
                    entry.setVersion(version);
                    entry.setValue(e);
                    entry.setTypeId(type.getId());
                    entry.setDeleted(deleted);
                    return entry;

                }).collect(Collectors.toList());
                jdbcWriteUtils.saveBatch(entryEntities);
            }
        }
    }


    public void cloneEntries(String originalTypeId, String newTypeId) {

        entryRepository.cloneEntries(originalTypeId, newTypeId);
        falseRecommendationEntryRepository.cloneEntries(originalTypeId, newTypeId);
        falsePositiveEntryRepository.cloneEntries(originalTypeId, newTypeId);
    }

}
