package com.iqser.red.service.persistence.service.v1.api.shared.mongo.repository;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;

import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType;
import com.iqser.red.service.persistence.service.v1.api.shared.mongo.document.EntityLogEntryDocument;

import jakarta.validation.constraints.NotNull;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.experimental.FieldDefaults;

@Repository
@AllArgsConstructor
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class EntityLogEntryDocumentCustomRepositoryImpl implements EntityLogEntryDocumentCustomRepository {

    MongoTemplate mongoTemplate;


    @Override
    public List<EntityLogEntryDocument> findEntryIdsByValueWithFilters(String entityLogId,
                                                                       String value,
                                                                       boolean caseSensitive,
                                                                       Set<String> originTypes,
                                                                       Set<String> originLegalBases,
                                                                       Set<Integer> pageNumbers) {

        Query query = new Query();
        List<Criteria> criteriaList = new ArrayList<>();
        criteriaList.add(Criteria.where("entryType").ne(EntryType.AREA));

        if (caseSensitive) {
            criteriaList.add(Criteria.where("value").is(value));
        } else {
            criteriaList.add(Criteria.where("value").regex(Pattern.compile("^" + Pattern.quote(value) + "$", Pattern.CASE_INSENSITIVE)));
        }

        addCommonCriteria(entityLogId, originTypes, originLegalBases, pageNumbers, criteriaList);

        Criteria mergedCriteria = new Criteria().andOperator(criteriaList.toArray(new Criteria[0]));
        query.addCriteria(mergedCriteria);

        return mongoTemplate.find(query, EntityLogEntryDocument.class);
    }


    @Override
    public List<EntityLogEntryDocument> findEntryIdsByMatchingPositionWithFilters(String entityLogId,
                                                                                  float[] rectangle,
                                                                                  Set<String> originTypes,
                                                                                  Set<String> originLegalBases,
                                                                                  Set<Integer> pageNumbers) {

        Query query = new Query();
        List<Criteria> criteriaList = new ArrayList<>();
        criteriaList.add(Criteria.where("entryType").is(EntryType.AREA));

        criteriaList.add(Criteria.where("positions").elemMatch(Criteria.where("rectangle").is(rectangle)));

        addCommonCriteria(entityLogId, originTypes, originLegalBases, pageNumbers, criteriaList);

        Criteria mergedCriteria = new Criteria().andOperator(criteriaList.toArray(new Criteria[0]));
        query.addCriteria(mergedCriteria);

        return mongoTemplate.find(query, EntityLogEntryDocument.class);
    }


    @NotNull
    private void addCommonCriteria(String entityLogId, Set<String> originTypes, Set<String> originLegalBases, Set<Integer> pageNumbers, List<Criteria> criteriaList) {

        criteriaList.add(Criteria.where("entityLogId").is(entityLogId));

        if (originTypes != null && !originTypes.isEmpty()) {
            criteriaList.add(Criteria.where("type").in(originTypes));
        }

        if (originLegalBases != null && !originLegalBases.isEmpty()) {
            criteriaList.add(Criteria.where("legalBasis").in(originLegalBases));
        }

        if (pageNumbers != null && !pageNumbers.isEmpty()) {
            Criteria positionsCriteria = Criteria.where("positions").elemMatch(Criteria.where("pageNumber").in(pageNumbers));
            criteriaList.add(positionsCriteria);
        }
    }



}
