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

import org.springframework.stereotype.Service;

import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.RuleSetEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.RuleSetRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;

import jakarta.transaction.Transactional;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
@SuppressWarnings("PMD.TooManyStaticImports")
public class RulesPersistenceService {

    public static final String DEFAULT_RULES = """
            package drools
                
            import static java.lang.String.format;
            import static com.iqser.red.service.redaction.v1.server.utils.RedactionSearchUtility.anyMatch;
            import static com.iqser.red.service.redaction.v1.server.utils.RedactionSearchUtility.exactMatch;
                
            import java.util.List;
            import java.util.LinkedList;
            import java.util.Set;
            import java.util.stream.Collectors;
            import java.util.Collection;
            import java.util.stream.Stream;
            import java.util.Optional;
                
            import com.iqser.red.service.redaction.v1.server.model.document.*;
            import com.iqser.red.service.redaction.v1.server.model.document.TextRange;
            import com.iqser.red.service.redaction.v1.server.model.document.entity.*;
            import com.iqser.red.service.redaction.v1.server.model.document.entity.EntityType;
            import com.iqser.red.service.redaction.v1.server.model.document.entity.MatchedRule;
            import com.iqser.red.service.redaction.v1.server.model.document.entity.TextEntity
            import com.iqser.red.service.redaction.v1.server.model.document.entity.MatchedRule
            import com.iqser.red.service.redaction.v1.server.model.document.nodes.*;
            import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section;
            import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table;
            import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode;
            import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
            import com.iqser.red.service.redaction.v1.server.model.document.nodes.Paragraph;
            import com.iqser.red.service.redaction.v1.server.model.document.nodes.Image;
            import com.iqser.red.service.redaction.v1.server.model.document.nodes.ImageType;
            import com.iqser.red.service.redaction.v1.server.model.document.nodes.Page;
            import com.iqser.red.service.redaction.v1.server.model.document.nodes.Headline;
            import com.iqser.red.service.redaction.v1.server.model.document.nodes.SectionIdentifier;
            import com.iqser.red.service.redaction.v1.server.model.document.nodes.Footer;
            import com.iqser.red.service.redaction.v1.server.model.document.nodes.Header;
            import com.iqser.red.service.redaction.v1.server.model.document.nodes.NodeType;
            import com.iqser.red.service.redaction.v1.server.model.document.textblock.*;
            import com.iqser.red.service.redaction.v1.server.model.document.textblock.TextBlock;
            import com.iqser.red.service.redaction.v1.server.model.document.textblock.TextBlockCollector;
            import com.iqser.red.service.redaction.v1.server.model.document.textblock.AtomicTextBlock;
            import com.iqser.red.service.redaction.v1.server.model.document.textblock.ConcatenatedTextBlock;
            import com.iqser.red.service.redaction.v1.server.model.NerEntities;
            import com.iqser.red.service.redaction.v1.server.model.dictionary.Dictionary;
            import com.iqser.red.service.redaction.v1.server.model.dictionary.DictionaryModel;
            import com.iqser.red.service.redaction.v1.server.service.document.EntityCreationService;
            import com.iqser.red.service.redaction.v1.server.service.ManualChangesApplicationService;
            import com.iqser.red.service.redaction.v1.server.utils.RedactionSearchUtility;
                
            import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttribute;
            import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Engine;
            import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualResizeRedaction;
            import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.IdRemoval;
            import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualForceRedaction;
            import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualRecategorization;
            import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualLegalBasisChange;
            import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus;
                
            global Document document
            global EntityCreationService entityCreationService
            global ManualChangesApplicationService manualChangesApplicationService
            global Dictionary dictionary
                                        
            //------------------------------------ queries ------------------------------------
                
            query "getFileAttributes"
                $fileAttribute: FileAttribute()
                end
                
            //------------------------------------ Local dictionary search rules ------------------------------------
                
            // Rule unit: LocalDictionarySearch.0
            rule "LDS.0.0: run local dictionary search"
                agenda-group "LOCAL_DICTIONARY_ADDS"
                salience -999
                when
                    $dictionaryModel: DictionaryModel(!localEntriesWithMatchedRules.isEmpty()) from dictionary.getDictionaryModels()
                then
                    entityCreationService.bySearchImplementation($dictionaryModel.getLocalSearch(), $dictionaryModel.getType(), EntityType.RECOMMENDATION, document)
                        .forEach(entity ->  {
                            Collection<MatchedRule> matchedRules = $dictionaryModel.getLocalEntriesWithMatchedRules().get(entity.getValue());
                            entity.addMatchedRules(matchedRules);
                        });
                end
            // --------------------------------------- Your rules below this line --------------------------------------------------
            """;

    private final RuleSetRepository ruleSetRepository;


    @Transactional(Transactional.TxType.REQUIRES_NEW)
    public RuleSetEntity getRules(String dossierTemplateId, RuleFileType ruleFileType) {

        return ruleSetRepository.findByDossierTemplateIdAndRuleFileType(dossierTemplateId, ruleFileType.name())
                .orElseThrow(() -> new NotFoundException(String.format("No rule file of type %s found for dossierTemplateId %s", ruleFileType, dossierTemplateId)));
    }


    public long getVersion(String dossierTemplateId, RuleFileType ruleFileType) {

        return ruleSetRepository.findVersionByDossierTemplateIdAndRuleFileType(dossierTemplateId, ruleFileType.name()).orElse(-1L);
    }


    @Transactional
    public void setRules(@NonNull String rules, String dossierTemplateId, RuleFileType ruleFileType) {

        ruleSetRepository.findByDossierTemplateIdAndRuleFileType(dossierTemplateId, ruleFileType.name()).ifPresentOrElse(ruleSet -> {
            ruleSet.setDossierTemplateId(dossierTemplateId);
            ruleSet.setRuleFileType(ruleFileType.name());
            ruleSet.setValue(rules);
            ruleSet.setVersion(ruleSet.getVersion() + 1);
            ruleSet.setTimeoutDetected(false);
        }, () -> {
            RuleSetEntity ruleSet = new RuleSetEntity();
            ruleSet.setDossierTemplateId(dossierTemplateId);
            ruleSet.setRuleFileType(ruleFileType.name());
            ruleSet.setValue(rules);
            ruleSet.setVersion(1);
            ruleSet.setTimeoutDetected(false);
            ruleSetRepository.save(ruleSet);
        });
    }


    @Transactional
    public void setTimeoutDetected(String dossierTemplateId, RuleFileType ruleFileType) {

        ruleSetRepository.updateTimeoutDetected(dossierTemplateId, ruleFileType.name());
    }

}
