package com.atlassian.bitbucket.internal.mirroring.mirror.sync;

import com.atlassian.bitbucket.internal.mirroring.mirror.ExternalProject;
import com.atlassian.bitbucket.internal.mirroring.mirror.MinimalExternalRepository;
import com.atlassian.bitbucket.mirroring.mirror.SyncLevel;
import com.atlassian.bitbucket.mirroring.mirror.UpstreamServer;
import com.atlassian.bitbucket.repository.RefChange;

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

/**
 * A helper to synchronize a mirror with its upstream
 */
public interface MirrorSynchronizationHelper {

    /**
     * Creates a local repository matching the external repository if one does not already exist and if
     * the upstream settings specify the external repository's project should be mirrored.
     *
     * @param upstream the upstream server
     * @param externalRepository the external repository
     */
    void createLocalRepository(@Nonnull UpstreamServer upstream, @Nonnull MinimalExternalRepository externalRepository);

    /**
     * Immediately deletes and unmaps the local repository corresponding to the specified external repository, if one exists.
     *
     * @param upstream the upstream server
     * @param externalRepository the external repository
     */
    void deleteLocalRepository(@Nonnull UpstreamServer upstream, @Nonnull MinimalExternalRepository externalRepository);

    /**
     * Returns the currently configured maximum number of consecutive failed fetches on a repository before the helper
     * gives up trying to synchronize it.
     */
    int getMaxFailedSyncCount();

    /**
     * Commences synchronization of all external repositories for the specified upstream server in a background task. At
     * some point after commencement, the corresponding local repository will be brought into sync. This includes
     * creating, deleting or renaming the local repository or its project and fetching the contents of the
     * external repository.
     *
     * @param upstream the upstream server
     * @param syncLevel the level of synchronization required
     */
    void startFullSynchronization(@Nonnull UpstreamServer upstream, @Nonnull SyncLevel syncLevel);

    /**
     * Commences synchronization of the specified external repository in a background task. At some point after commencement,
     * the corresponding local repository will be brought into sync. This includes creating, deleting or renaming the local
     * repository or its project and fetching the contents of the external repository.
     *
     * @param upstream the upstream server
     * @param externalRepository the external repository
     * @param changes the changes reported by the upstream server
     */
    void startRepositorySynchronization(@Nonnull UpstreamServer upstream, @Nonnull MinimalExternalRepository externalRepository,
                                        @Nonnull List<RefChange> changes);

    /**
     * Commences synchronization of the specified external repository in a background task. At some point after commencement,
     * the corresponding local repository will be brought into sync. This includes creating, deleting or renaming the local
     * repository or its project and fetching the contents of the external repository.
     *
     * @param upstream the upstream server
     * @param externalRepositoryId ID of the external repository
     * @param syncLevel the level of synchronization required
     */
    void startRepositorySynchronization(@Nonnull UpstreamServer upstream, @Nonnull String externalRepositoryId,
                                        @Nonnull SyncLevel syncLevel);


    /**
     * Updates the the local project that mirrors the specified external project. If a local project does not yet exist
     * it is not created.
     *
     * @param upstream the upstream server
     * @param externalProject the external project
     */
    void updateLocalProject(@Nonnull UpstreamServer upstream, @Nonnull ExternalProject externalProject);

    /**
     * Updates the the local repository that mirrors the specified external repository. If a local repository does not
     * yet exist it is not created.
     *
     * @param upstream the upstream server
     * @param externalRepository the external repository
     */
    void updateLocalRepository(@Nonnull UpstreamServer upstream, @Nonnull MinimalExternalRepository externalRepository);
}
