package com.atlassian.stash.internal.content;

import com.atlassian.bitbucket.idx.IndexSearchRequest;
import com.atlassian.stash.internal.Dao;
import com.atlassian.stash.internal.idx.InternalIndexedCommit;
import com.atlassian.stash.internal.repository.InternalRepository;
import com.atlassian.bitbucket.property.PropertyMap;
import com.atlassian.bitbucket.util.Page;
import com.atlassian.bitbucket.util.PageRequest;

import javax.annotation.Nonnull;
import java.util.Map;
import java.util.Set;

public interface IndexedCommitDao extends Dao<String, InternalIndexedCommit> {

    /**
     * Adds a membership relationship between {@code commit} and {@code repository}
     * @param commit the commit
     * @param repository the repository
     * @return {@code true} if the membership was created, {@code false} if it already existed.
     */
    boolean addMembership(@Nonnull InternalIndexedCommit commit, @Nonnull InternalRepository repository);

    /**
     * Adds a key-value property. If the key-value pair is already associated with {@code commit},
     * this call will have no effect.
     *
     * @param commit the commit
     * @param key the property key
     * @param value the property value
     * @return {@code true} if the property was created in the database, {@code false} if it already existed.
     */
    boolean addProperty(@Nonnull InternalIndexedCommit commit, @Nonnull String key, @Nonnull String value);

    /**
     * Deletes all memberships relationships for {@code repository}
     * @param repository the repository
     */
    void deleteAllMemberships(@Nonnull InternalRepository repository);

    /**
     * Deletes a membership relationship between {@code commit} and {@code repository}
     * @param commitId the commit ID
     * @param repository the repository
     * @return {@code true} if the membership existed and was deleted
     */
    boolean deleteMembership(@Nonnull String commitId, @Nonnull InternalRepository repository);

    /**
     * Retrieves all commits that have an associated property {@code key} - {@code value} pair
     *
     * @param key the property key
     * @param value the property value
     * @param caseSensitive whether the matches against {@code value} should be case-sensitive
     * @param pageRequest the page request
     * @return a page of commits, ordered by authorDate desc, or an empty page if there are no results
     */
    @Nonnull
    Page<InternalIndexedCommit> findByProperty(String key, String value, boolean caseSensitive, PageRequest pageRequest);

    /**
     * Retrieves all properties with the provided {@code propertyKeys} for the provided commit.
     *
     * @param commitId the commit ID
     * @param propertyKeys the property keys to retrieve
     * @return a {@code PropertyMap} containing the requested key-value pairs.
     */
    @Nonnull
    PropertyMap getProperties(String commitId, Iterable<String> propertyKeys);

    /**
     * Retrieves all properties with the provided {@code propertyKeys} associated with the provided {@code commitIds}.
     *
     * @param commitIds the commit IDs
     * @param propertyKeys the property keys to retrieve
     * @return a map of commitIds to properties associated with the commit, or an empty map if there are no
     * results.
     */
    @Nonnull
    Map<String, PropertyMap> getProperties(Iterable<String> commitIds, Iterable<String> propertyKeys);

    /**
     * Retrieves all property values associated with the {@code key) for commit {@code commitId}.
     *
     * @param commitId the commit ID
     * @param key property key
     * @return a set with property values, or an empty list if there are no results.
     */
    @Nonnull
    Set<String> getPropertyValues(String commitId, String key);

    /**
     * @param commitId the commit ID
     * @param repository the repository
     * @return whether {@code commit} is a member of {@code repository}
     */
    boolean isIndexed(@Nonnull String commitId, @Nonnull InternalRepository repository);

    /**
     * Removes a key-value property, if it exists.
     *
     * @param commitId the commit ID
     * @param key the property key
     * @param value the property value
     * @return {@code true} if the property was found and deleted, {@code false} otherwise
     */
    boolean removeProperty(@Nonnull String commitId, @Nonnull String key, @Nonnull String value);

    /**
     * Search the index for any matching commits.
     *
     * @param searchRequest the criteria to match
     * @return a page of {@code InternalIndexedCommit}, possibly empty if no commit in the index matches
     */
    @Nonnull
    Page<InternalIndexedCommit> search(@Nonnull IndexSearchRequest searchRequest, @Nonnull PageRequest pageRequest);
}
