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

import java.util.Collection;
import java.util.List;
import java.util.Optional;

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.stereotype.Repository;

import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Position;
import com.iqser.red.service.persistence.service.v1.api.shared.mongo.document.EntityLogEntryDocument;
import com.iqser.red.service.persistence.service.v1.api.shared.mongo.repository.projections.EntryWithManualChangesProjection;

@Repository
public interface EntityLogEntryDocumentRepository extends MongoRepository<EntityLogEntryDocument, String> {

    @Query("{ 'entityLogId' : ?0, 'manualChanges' : { $exists: true, $ne: [] } }")
    List<EntityLogEntryDocument> findByEntityLogIdAndManualChangesNotEmpty(String entityLogId);


    @Query("{ 'entityLogId' : ?0, 'changes.analysisNumber' : ?1 }")
    List<EntityLogEntryDocument> findByEntityLogIdAndChangesAnalysisNumberEquals(String entityLogId, Integer analysisNumber);


    @Query("{ 'entityLogId' : ?0, 'changes.analysisNumber' : { $gte: ?1, $lte: ?2 } }")
    List<EntityLogEntryDocument> findByEntityLogIdAndChangesAnalysisNumberBetween(String entityLogId, Integer analysisNumberStart, Integer analysisNumberEnd);


    @Query("{ 'entityLogId' : ?0}")
    List<EntityLogEntryDocument> findByEntityLogId(String entityLogId);


    @Query("{ 'entityLogId' : ?0, 'containingNodeId' : { $exists: true, $ne: [] } }")
    List<EntityLogEntryDocument> findByEntityLogIdAndContainingNodeIdNotEmpty(String entityLogId);


    @Query("{ 'entityLogId' : ?0 , 'containingNodeId' : { $exists: true, $eq: [] } }")
    List<EntityLogEntryDocument> findByEntityLogIdAndContainingNodeIdEmpty(String entityLogId);


    @Query(value = "{ 'id' : { $in: ?0 }, 'containingNodeId' : { $exists: true, $ne: [] } }", fields = "{ 'containingNodeId': 1 }")
    List<EntityLogEntryDocument> findContainingNodeIdForAllByIdAndContainingNodeIdNotEmpty(List<String> ids);


    @Query("{ 'entityLogId' : ?0, $or: [ { 'containingNodeId' : { $exists: true, $eq: [] } }, { 'containingNodeId.0' : { $in: ?1 } } ] }")
    List<EntityLogEntryDocument> findByEntityLogIdAndNotContainedOrFirstContainedByElementInList(String entityLogId, Collection<Integer> containingNodeIds);


    @Query("{'entityLogId' : ?0, 'positions': { $elemMatch: { 'pageNumber': { $in: ?1 } } } }")
    List<EntityLogEntryDocument> findByEntityLogIdAndPositionsPageNumberIn(String entityLogId, List<Integer> pageNumbers);


    @Query(value = "{ 'entityLogId': ?0, 'type': { '$nin': ?1 } }")
    List<EntityLogEntryDocument> findEntityLogDocumentByIdAndExcludedTypes(String entityLogId, List<String> excludedTypes);


    @Query(value = "{ 'entityLogId': ?0, 'entryId': ?1 }")
    Optional<EntityLogEntryDocument> findEntityLogEntryDocumentByEntryId(String entityLogId, String entryId);


    @Query(value = "{ 'entityLogId': ?0, 'entryId': { $in: ?1 } }")
    List<EntityLogEntryDocument> findEntityLogEntryDocumentsByEntryIds(String entityLogId, List<String> entryIds);


    @Query(value = "{ 'entityLogId' : ?0}", delete = true)
    void deleteByEntityLogId(String entityLogId);


    @Query(value = "{ 'entityLogId': ?0, 'engines': 'IMPORTED' }", exists = true)
    boolean existsByEntityLogIdAndEngineImported(String entityLogId);


    @Query(value = "{ 'value': ?0, 'engines': 'MANUAL' }", fields = "{ 'entryId': 1, 'id': 0 }")
    List<String> findEntryIdsByValueAndEngineManual(String value);


    @Query(value = "{ 'positions': { $elemMatch: { 'pageNumber': ?0, 'rectangle': ?1 } }, 'engines': 'MANUAL' }", fields = "{ 'entryId': 1, 'id': 0 }")
    List<String> findEntryIdsByMatchingFullPositionAndEngineManual(int pageNumber, float[] rectangle);


    @Query(value = "{ 'positions': { $elemMatch: { 'rectangle': ?0 } }, 'engines': 'MANUAL' }", fields = "{ 'entryId': 1, 'id': 0 }")
    List<String> findEntryIdsByMatchingPositionAndEngineManual(float[] rectangle);

    @Query(value = """
        {
         'entryType': 'ENTITY',
         'state': 'APPLIED',
         $or: [{ 'legalBasis': null },
               { 'legalBasis': '' }
            ]}
        """, fields = "{ 'entryId': 1, 'entityLogId': 1, 'state': 1, 'entryType': 1 , 'manualChanges': 1}")
    List<EntryWithManualChangesProjection> findAppliedEntitiesWhereLegalBasisEmpty();

    @Query("{ 'entityLogId': ?0," +
           "  'value': ?1, " +
           "  '$or': [ { 'dictionaryEntry': true }, { 'dossierDictionaryEntry': true } ], " +
           "  'positions': { $in: ?2 } " +
           "}")
    List<EntityLogEntryDocument> findDictionaryEntityLogEntriesByValueAndPositions(String entityLogId,
                                                                                   String value,
                                                                                   List<List<Position>> positionsList);

}
