package com.atlassian.stash.internal.backup;

import com.atlassian.bitbucket.NoSuchEntityException;
import com.atlassian.bitbucket.validation.ArgumentValidationException;
import com.atlassian.stash.internal.maintenance.MaintenanceTaskMonitor;
import com.atlassian.bitbucket.util.Page;
import com.atlassian.bitbucket.util.PageRequest;

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

/**
 * Defines a service for creating and managing system backups.
 * <p>
 * Note: Backups cannot be restored by the system; they must be restored externally.
 *
 * @since 1.1
 */
public interface BackupService {

    /**
     * Creates a new backup containing a snapshot of the current system state.
     * <p>
     * In an attempt to strike a balance between server downtime and implementation complexity, backing up the system
     * does <i>not</i> include repository data. A standalone backup client performs the repository backup, coordinating
     * the system backup performed by this method to produce a final, unified backup which contains synchronised state
     * for the database <i>and</i> the repositories.
     *
     * @return a handle to the backup task
     * @throws BackupException if the processing to create the backup fails
     */
    @Nonnull
    MaintenanceTaskMonitor backup();

    /**
     * Attempts to delete the specified backup on disk and returns a flag to indicate the outcome.
     *
     * @param backup the backup to delete
     * @return {@code true} if the backup existed and was successfully deleted; otherwise, {@code false} if no such
     *         backup existed or it could not be removed
     * @throws ArgumentValidationException if the {@link Backup#getName() backup name}
     *                                                                   describes a relative path, or does not follow
     *                                                                   the expected pattern
     * @throws NullPointerException if the provided {@link Backup} or its {@link Backup#getName() name} is {@code null}
     */
    boolean delete(@Nonnull Backup backup);

    /**
     * Prepares the system for backup, by locking DB access and draining all DB and SCM connections
     * <p>
     * Although the current backup solution is arguably generic it seems that there are more efficient
     * backup options in some installations. What this task does is lock the DB and drain all connections
     * to the DB and repositories, preparing the system for external out of process backup. It waits for
     * the external process to report progress in fashion similar to {@link #backup() backup} and
     * once 100 percent progress is reported it unlocks the DB and repository access.
     *
     * @return a handle to the task
     *
     * @since 2.12
     */
    @Nonnull
    MaintenanceTaskMonitor externalBackup();

    /**
     * Retrieves a page of {@link Backup backups}, as described by the provided {@link PageRequest request}.
     *
     * @param pageRequest describes the start and limit of the page to retrieve
     * @return a page of backups, which may be empty but never {@code null}
     * @throws NullPointerException if the provided {@link PageRequest} is {@code null}
     */
    @Nonnull
    Page<Backup> findAll(@Nonnull PageRequest pageRequest);

    /**
     * Finds a backup with the specified name, if one exists.
     *
     * @param name the <i>exact</i> name of the backup
     * @return the named backup, if it exists, or {@code null} if it doesn't
     * @throws ArgumentValidationException if the provided {@code name} describes a
     *                                                                   relative path, or does not follow the
     *                                                                   expected pattern
     * @throws NullPointerException if the provided {@code name} is {@code null}
     */
    @Nullable
    Backup findByName(@Nonnull String name);

    /**
     * Retrieves the backup with the specified name.
     *
     * @param name the <i>exact</i> name of the backup
     * @return the named backup
     * @throws ArgumentValidationException if the provided {@code name} describes a
     *                                                                   relative path, or does not follow the
     *                                                                   expected pattern
     * @throws NoSuchEntityException if no backup exists with the specified {@code name}
     * @throws NullPointerException if the provided {@code name} is {@code null}
     */
    @Nonnull
    Backup getByName(@Nonnull String name);

    /**
     * Retrieves a list of backup features, in order for the backup client to determine whether a backup or restore is possible.
     *
     * @return the backup features
     */
    @Nonnull
    List<BackupFeature> getFeatures();

    /**
     * Retrieves the most recent backup.
     *
     * @return the most recent backup
     * @throws NoSuchEntityException if no backups exist
     */
    @Nonnull
    Backup getLatest();

    /**
     * Informs the running backup task the percentage complete of the backup client.
     *
     * @param percentage the percentage complete of the backup client
     * @throws NoSuchEntityException if a backup is not currently in progress
     */
    void updateClientProgress(int percentage);
}
