package com.atlassian.stash.internal.repository.ref.restriction.dao;

import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.repository.ref.restriction.RefMatcher;
import com.atlassian.bitbucket.repository.ref.restriction.RefMatcherType;
import com.atlassian.bitbucket.repository.ref.restriction.RefRestrictionType;
import com.atlassian.bitbucket.util.Page;
import com.atlassian.bitbucket.util.PageRequest;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;

/**
 * A DAO for managing {@link AoRefRestriction ref restrictions}.
 *
 * @since 3.9
 */
public interface RefRestrictionDao {

    /**
     * Creates a new {@link AoRefRestriction} for a matcher
     *
     * @param repositoryId the repository ID
     * @param refMatcher the restriction matcher
     * @param groups the groups to create access grants for
     * @param userIds the user IDs to create access grants for
     * @return the existing {@link AoRefRestriction} if it already existed. Otherwise the newly created instance.
     *
     * @since 4.0
     */
    @Nonnull
    AoRefRestriction create(int repositoryId, @Nonnull RefRestrictionType refRestrictionType,
                            @Nonnull RefMatcher refMatcher, @Nonnull Iterable<String> groups,
                            @Nonnull Iterable<Integer> userIds);

    /**
     * @param repositoryId the repository ID
     * @return the number of {@link AoRefRestriction ref restrictions} defined for the repository
     */
    int count(int repositoryId);

    /**
     * Deletes a ref restriction
     *
     * @param restriction the restriction to delete
     */
    void delete(@Nonnull AoRefRestriction restriction);

    /**
     * Revokes all granted access to all ref restrictions for a group
     *
     * @param group the group name
     */
    void deleteForGroup(@Nonnull String group);

    /**
     * Deletes all {@link AoRefRestriction} and {@link AoAccessGrant} for a given repository
     *
     * @param repositoryId the repository ID
     */
    void deleteForRepository(int repositoryId);

    /**
     * Revokes all granted access to all ref restrictions for a user
     *
     * @param userId the user ID
     */
    void deleteForUser(int userId);

    /**
     * @param repositoryId the ID of the {@link Repository repository} to find restrictions for
     * @param types a {@link Collection collection} of {@link RefRestrictionType restriction types} to include in the
     *              results.
     * @param matcher a {@link RefMatcher matcher} which constrains the results to only include restrictions for this
     *                matcher.
     * @param matcherTypes a {@link Collection collection} of {@link RefMatcherType matcher types} which constrain the
     *                     results to only include restrictions for these matcher types.
     * @param pageRequest the page request containing the maximum number of results to retrieve. Note that only
     *                    {@code start} values of 0 are supported.
     * @return a {@link Page} of {@link AoRefRestriction ref restrictions} defined for the repository
     */
    @Nonnull
    Page<AoRefRestriction> find(int repositoryId,
                                @Nullable Collection<RefRestrictionType> types,
                                @Nullable RefMatcher matcher,
                                Collection<? extends RefMatcherType> matcherTypes,
                                @Nonnull PageRequest pageRequest);

    /**
     * Retrieve a restriction by repository, type and matcher
     *
     * @param repositoryId the ID of the {@link Repository repository}
     * @param refRestrictionType the restriction type to match
     * @param matcher the matcher type and ID to match
     * @return the restriction if found. Otherwise {@code null}
     */
    @Nullable
    AoRefRestriction get(int repositoryId, @Nonnull RefRestrictionType refRestrictionType, @Nonnull RefMatcher matcher);

    /**
     * @param restrictionId the ref restriction ID
     * @return the {@link AoRefRestriction ref restriction}
     */
    @Nullable
    AoRefRestriction getById(int restrictionId);

    /**
     * Updates the access grants for an existing restriction
     *
     * @param restriction the restriction to update
     * @param groups the groups to create access grants for
     * @param userIds the user IDs to create access grants for
     * @return the updated restriction
     */
    @Nonnull
    AoRefRestriction setAccessGrants(@Nonnull AoRefRestriction restriction, @Nonnull Iterable<String> groups,
                                     @Nonnull Iterable<Integer> userIds);
}
