package com.atlassian.bitbucket.mesh.repository;

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

/**
 * Manages {@link Repository repositories}.
 */
public interface RepositoryManager {

    /**
     * Creates a new repository
     *
     * @param parameters describes where and how the repository should be created
     * @return the created repository
     * @throws RepositoryAlreadyExistsException if the repository already exists
     * @throws CreateRepositoryFailedException  if the repository could not be created for some reason
     */
    @Nonnull
    Repository create(@Nonnull CreateRepositoryParameters parameters);

    /**
     * Deletes the repository identified by {@code parameters}
     *
     * @param parameters describes what repository to delete and optionally how the update impacts remaining
     *                   repositories in the hierarchy
     * @throws RepositoryNotFoundException if the repository can not be found
     */
    void delete(@Nonnull DeleteRepositoryParameters parameters);

    /**
     * Retrieves the repository with the specified {@code id}, if it exists.
     *
     * @param id the ID of the repository to retrieve
     * @return the specified repository, or {@code null} if no repository exists with the requested ID
     */
    @Nullable
    Repository findById(@Nonnull String id);

    /**
     * Retrieves the repository with the specified {@code id}. If the repository in question does not
     * {@link Repository#exists() exist}, an instance is only returned if {@code returnIfNotExists} is set
     * to {@code true}.
     *
     * @param id                the ID of the repository to retrieve
     * @param returnIfNotExists whether to return an instance when the repository does not exist
     * @return the specified repository, or {@code null} if the repository format is not recognized, or no repository
     *         exists with the requested ID and {@code returnIfNotExists} was set to {@code true}
     * @since 1.2
     */
    @Nullable
    Repository findById(@Nonnull String id, boolean returnIfNotExists);

    /**
     * Retrieves the repository with the specified {@code id}.
     *
     * @param id the ID of the repository to retrieve
     * @return the specified repository
     * @throws RepositoryNotFoundException if the repository can't be found in any of the data stores
     */
    @Nonnull
    Repository getById(@Nonnull String id);

    /**
     * Retrieves the configured default branch for the repository, which may not actually exist.
     *
     * @param repository the repository
     * @return the configured default branch, or {@code null} if the default branch could not be determined
     */
    @Nullable
    String getDefaultBranch(@Nonnull Repository repository);

    /**
     * Retrieves the metadata for the specified repository.
     *
     * @param repository the repository for which metadata should be retrieved
     * @return the repository metadata
     */
    @Nonnull
    Map<String, String> getMetadata(@Nonnull Repository repository);

    /**
     * Retrieves the replica details for the provided repository ID
     *
     * @param id the repository ID
     * @return the repository replica details
     */
    @Nonnull
    RepositoryReplicaDetails getReplicaDetails(@Nonnull String id);

    /**
     * Looks up and returns the versions for all managed repositories matching the provided {@code parameters}.
     *
     * @param parameters describes which repositories to search
     * @return a map of repository ID to version
     * @since 1.4
     */
    @Nonnull
    Map<String, Long> getVersions(@Nonnull GetVersionsParameters parameters);

    /**
     * Resets all repositories in the provided hierarchy by deleting their refs, dark refs and reflogs. All
     * objects and packs are left untouched.
     *
     * @param partition   the partition
     * @param hierarchyId the hierarchy to reset
     * @return the number of repositories that was reset
     */
    int resetHierarchy(@Nonnull String partition, @Nonnull String hierarchyId);

    /**
     * Updates the default branch for the provided {@code repository}.
     *
     * @param repository    the repository for which the default branch should be updated
     * @param defaultBranch the optionally qualified branch name to update the default branch to
     */
    void setDefaultBranch(@Nonnull Repository repository, @Nonnull String defaultBranch);

    /**
     * Update the repository metadata stored in repository-config on disk.
     *
     * @param repository the repository for which the metadata should be updated
     * @param metadata   the metadata to update
     */
    void setMetadata(@Nonnull Repository repository, @Nonnull Map<String, String> metadata);
}
