package com.atlassian.bitbucket.mesh.repository;

import javax.annotation.Nonnull;
import java.nio.file.Path;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;

/**
 * Manages the application {@link DataStore data stores}, including calling the {@link DataStore#start()} and
 * {@link DataStore#stop()} lifecycle methods.
 */
public interface DataStoreManager {

    /**
     * Adds a new shard, allowing the system to access additional storage.
     * <p>
     * This is currently only supported if a {@link BitbucketServerDataStore} is available, which means in practice
     * this only works if the "sidecar" profile is active.
     *
     * @param parameters parameters describing the shard to add
     * @return {@code true} if the shard was added; otherwise, {@code false} if no available {@link DataStore} allows
     *         adding more shards, or if the shard's {@link AddShardParameters#getId ID} is already in use
     */
    boolean addShard(@Nonnull AddShardParameters parameters);

    /**
     * Attempts to locate the correct {@link DataStore} for the provided {@link Repository} and attach it, allowing
     * the repository to provide access to its {@link Repository#getPath path on disk} and other related paths.
     * <p>
     * Rather than throwing exceptions for situations like repositories missing on disk, {@code attachStorage} returns
     * a status and leaves it to the <i>caller</i> to decide whether that status is acceptable or not. This allows the
     * caller to throw a more context-aware exception.
     * <p>
     * If storage is {@link StorageStatus#ATTACHED ATTACHED}, path accessors on the {@link Repository} will work and
     * the paths they identify will exist on disk. {@link StorageStatus#NO_STORE NO_STORE} means path accessors
     * <i>will not work</i> because no appropriate {@link DataStore} could be located. Path accessors will work for
     * other statuses, but the paths they identify may not exist--or may not contain valid repository data.
     *
     * @param repository the repository to attach storage to
     * @return the result of attaching storage
     */
    @Nonnull
    StorageStatus attachStorage(@Nonnull Repository repository);

    /**
     * @return information about all configured datastores
     */
    @Nonnull
    List<DataStoreInfo> getInfo();

    /**
     * @return all the <em>root</em> directories for work trees
     */
    @Nonnull
    Set<Path> getWorkTreesDirs();

    /**
     * Finds all repositories in the provided partition and hierarchy and hands them to {@code callback}.
     *
     * @param partition   the partition
     * @param hierarchyId the hierarchy ID
     * @param callback    the callback
     */
    void streamRepositories(@Nonnull String partition, @Nonnull String hierarchyId,
                            @Nonnull Consumer<Repository> callback);
}
