package com.atlassian.bitbucket.ssh;

import com.atlassian.bitbucket.project.Project;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.util.Page;
import com.atlassian.bitbucket.util.PageRequest;

import javax.annotation.Nonnull;
import java.util.Optional;
import java.util.Set;

/**
 * Manages {@link SshAccessKey SSH access keys} and their access to {@link Project projects} and
 * {@link Repository repositories}
 *
 * @since 4.3
 */
public interface SshAccessKeyService {

    /**
     * @param project the project to query
     * @return {@code true} if any SSH access keys have been defined for the provided project
     */
    boolean existsForProject(@Nonnull Project project);

    /**
     * @param repository the repository to query
     * @return {@code true} if any SSH access keys have been defined for the provided repository
     */
    boolean existsForRepository(@Nonnull Repository repository);

    /**
     * Finds {@link SshAccessKey SSH access keys} for projects accessible to the current user for the supplied
     * {@link SshKey key}'s ID
     *
     * @param sshKeyId the key ID to search for
     * @param pageRequest the page request
     *
     * @return a page of matching access keys
     */
    @Nonnull
    Page<SshAccessKey> findByKeyForProjects(int sshKeyId, @Nonnull PageRequest pageRequest);

    /**
     * Finds {@link SshAccessKey SSH access keys} for repositories accessible to the current user for the
     * supplied {@link SshKey key}'s ID
     *
     * @param sshKeyId the key ID to search for
     * @param pageRequest the page request
     *
     * @return a page of matching access keys
     */
    @Nonnull
    Page<SshAccessKey> findByKeyForRepositories(int sshKeyId, @Nonnull PageRequest pageRequest);

    /**
     * Finds {@link SshAccessKey SSH access keys} for the supplied {@link Project project}
     *
     * @param project the project to search by
     * @param pageRequest the page request
     *
     * @return a page of matching access keys
     */
    @Nonnull
    Page<SshAccessKey> findByProject(@Nonnull Project project, @Nonnull PageRequest pageRequest);

    /**
     * Finds {@link SshAccessKey SSH access keys} for the supplied {@link Repository repository}
     *
     * @param repository the repository to search by
     * @param pageRequest the page request
     *
     * @return a page of matching access keys
     */
    @Nonnull
    Page<SshAccessKey> findByRepository(@Nonnull Repository repository, @Nonnull PageRequest pageRequest);

    /**
     * Retrieves the {@link SshAccessKey access key} with SSH key ID {@code sshKeyId} for the provided {@code project}
     *
     * @param sshKeyId the ID of the SSH key
     * @param project the project
     * @return the {@link SshAccessKey access key}, or {@link Optional#empty()} if the provided key does not have
     *         access to the project
     */
    @Nonnull
    Optional<SshAccessKey> getByKeyAndProject(int sshKeyId, @Nonnull Project project);

    /**
     * Retrieves the {@link SshAccessKey access key} with SSH key ID {@code sshKeyId} for the provided
     * {@code repository}
     *
     * @param sshKeyId the ID of the SSH key
     * @param repository the repository
     * @return the {@link SshAccessKey access key}, or {@link Optional#empty()} if the provided key does not have
     *         access to the repository
     */
    @Nonnull
    Optional<SshAccessKey> getByKeyAndRepository(int sshKeyId, @Nonnull Repository repository);

    /**
     * Revokes access for the provided {@link SshKey SSH key} to the {@link Project project}
     *
     * @param sshKeyId id of the SSH key
     * @param project the project
     */
    void revoke(int sshKeyId, @Nonnull Project project);

    /**
     * Revokes access for the provided {@link SshKey SSH key} to the {@link Repository repository}
     *
     * @param sshKeyId id of the SSH key
     * @param repository the repository
     */
    void revoke(int sshKeyId, @Nonnull Repository repository);

    /**
     * Revokes all access for the provided {@link SshKey SSH key} to the supplied {@link Repository repositories}
     * and {@link Project projects}
     *
     * @param sshKeyId id of the SSH key
     * @param projects the repositories
     * @param repositories the repositories
     */
    void revoke(int sshKeyId, @Nonnull Set<Repository> repositories, @Nonnull Set<Project> projects);

    /**
     * Creates a new {@link SshAccessKey access key} or updates the access level of an existing
     * {@link SshAccessKey access key} on a {@link Project} or {@link Repository}
     *
     * @param request the request detailing the desired access level
     *
     * @return a {@link SshAccessKey} instance representing the created or updated access key
     */
    @Nonnull
    SshAccessKey set(@Nonnull SetSshAccessKeyRequest request);
}
