package com.atlassian.bitbucket.mesh.repository;

import javax.annotation.Nonnull;
import java.util.function.BiConsumer;

/**
 * Tracks the state of repository replicas
 */
public interface ReplicaStateRegistry {

    /**
     * Counts the number of replicas registered to be in the provided state. Note that since the registry does not
     * explicitly track {@link ReplicaState#CONSISTENT} repositories (it's the default), calling this method with
     * {@link ReplicaState#CONSISTENT} will always return {@code 0}.
     *
     * @param state the repository replica state
     * @return the number of repository replicas current marked as the requested {@code state}
     */
    int countByState(@Nonnull ReplicaState state);

    /**
     * @param repository the repository
     * @return a {@link RepositoryReplicaDetails} instance containing the state of the local replica of the repository,
     *         the version the state refers to, and the version of the repository
     */
    @Nonnull
    RepositoryReplicaDetails getDetails(@Nonnull Repository repository);

    /**
     * @param repository the repository
     * @return the state of the local replica of the repository
     */
    @Nonnull
    ReplicaState getState(@Nonnull Repository repository);

    /**
     * @param repositoryId the repository ID
     * @return the state of the local replica of the repository
     */
    @Nonnull
    ReplicaState getState(@Nonnull String repositoryId);

    /**
     * Configures the provided repository replicas as inconsistent at the mapped version, as described by
     * {@code parameters}.
     * <p>
     * When the update is {@link MarkInconsistentParameters#isFromControlPlane() initiated by the control plane},
     * the registry will compare the provided set with its current state. If the provided set of inconsistent
     * repositories is the {@link MarkInconsistentParameters#isComplete() complete set} known to the control plane,
     * the registry will report any replica that is {@link ReplicaState#INCONSISTENT} or {@link ReplicaState#UNKNOWN}
     * and not included in {@code parameters} to the control plane.
     * <p>
     * When the update is not from the control plane, the registry will process {@code inconsistentReplicas} and
     * notify the control plane of any replicas that have become {@link ReplicaState#INCONSISTENT} or
     * {@link ReplicaState#UNKNOWN} as a result.
     *
     * @param parameters describes the repository replicas to mark as inconsistent
     */
    void markInconsistent(@Nonnull MarkInconsistentParameters parameters);

    /**
     * Removes the replica state for the provided repository, which effectively marks it as consistent at the
     * repository's current version.
     *
     * @param repositoryId the repository ID
     */
    void remove(@Nonnull String repositoryId);

    /**
     * Sets the local replica state for the provided repository.
     *
     * @param repositoryId the repository ID
     * @param state the state of the local replica of the repository
     * @param version the replica version the state refers to
     * @param force whether the state should be updated, even if the current observed state is for a newer version
     */
    void setState(@Nonnull String repositoryId, @Nonnull ReplicaState state, long version, boolean force);

    /**
     * Streams over all replicas currently marked as {@link ReplicaState#INCONSISTENT}, {@link ReplicaState#MISSING} or
     * {@link ReplicaState#REPAIRING} and provides the repository ID and version it is inconsistent with to the provided
     * callback.
     *
     * @param callback the callback
     * @since 1.3
     */
    void streamInconsistentReplicas(@Nonnull BiConsumer<String, Long> callback);
}
