package com.atlassian.bitbucket.mesh.git.ref;

import com.atlassian.bitbucket.mesh.git.exception.InvalidRefNameException;
import com.atlassian.bitbucket.mesh.git.exception.NoDefaultBranchException;
import com.atlassian.bitbucket.mesh.git.exception.RefNameTooLongException;
import com.atlassian.bitbucket.mesh.repository.Repository;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;

public interface RefManager {

    /**
     * Checks the format of the provided {@code refId} to ensure it is valid.
     *
     * @param refId the ref ID to check
     */
    void checkFormat(@Nonnull String refId);

    /**
     * Creates a new branch.
     *
     * @param parameters parameters describing the branch to create
     * @return the created branch
     */
    @Nonnull
    Branch createBranch(@Nonnull CreateBranchParameters parameters);

    /**
     * Creates a new tag.
     *
     * @param parameters parameters describing the tag to create
     * @return the created tag
     */
    @Nonnull
    Tag createTag(@Nonnull CreateTagParameters parameters);

    /**
     * Deletes a branch.
     *
     * @param parameters parameters describing the branch to delete
     */
    void deleteBranch(@Nonnull DeleteBranchParameters parameters);

    /**
     * Deletes a tag.
     *
     * @param parameters parameters describing the tag to delete
     */
    void deleteTag(@Nonnull DeleteTagParameters parameters);

    /**
     * Resolves the repository's configured default branch.
     *
     * @param repository the repository to retrieve the default branch for
     * @return the default branch
     * @throws NoDefaultBranchException if the configured default branch does not exist
     */
    @Nonnull
    Branch resolveDefaultBranch(@Nonnull Repository repository);

    /**
     * Resolves the requested refs and returns a map from the IDs to the refs that were resolved. If any of the
     * requested refs are not resolved, their IDs will not be include in the returned map.
     *
     * @param parameters parameters describing the refs to resolve
     * @return the resolved refs, mapped by the IDs used to request them
     */
    @Nonnull
    Map<String, Ref> resolveRefs(@Nonnull ResolveRefsParameters parameters);

    /**
     * Given a set of {@link StreamAnnotatedTagsParameters#getTagIds tag IDs}, resolves any annotated tags among
     * them and streams their details to the provided callback.
     *
     * @param parameters parameters describing the tags to resolve and stream
     * @param callback   a callback to receive annotated tags
     */
    void streamAnnotatedTags(@Nonnull StreamAnnotatedTagsParameters parameters, @Nonnull AnnotatedTagCallback callback);

    /**
     * Applies a single ref update.
     *
     * @param parameters parameters describing the ref to update
     */
    void updateRef(@Nonnull UpdateRefParameters parameters);

    /**
     * Applies a series of ref updates, either individually or as a single transaction.
     * <p>
     * For {@link UpdateRefsParameters#isTransactional transactional} updates, an exception will be thrown if any
     * of the updates can't be applied and so the returned list will always be empty. Non-transactional updates
     * are applied individually, so individual errors cannot be thrown; instead, the IDs of refs that could not
     * be updated are returned.
     *
     * @param parameters parameters describing the ref to update
     * @return a list containing zero or more ref IDs for which updates failed
     */
    @Nonnull
    List<String> updateRefs(@Nonnull UpdateRefsParameters parameters);

    /**
     * Validates the format of a ref ID.
     *
     * @param refId the ref ID to validate
     * @return a fully-qualified version of the ref ID
     * @throws InvalidRefNameException if the format of the ref ID is not valid
     * @throws RefNameTooLongException if the ref ID is too long
     */
    @Nonnull
    String validateId(@Nullable String refId);
}
