package com.atlassian.bitbucket.internal.scm.check;

import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.scm.ScmRequest;
import com.atlassian.bitbucket.scm.ScmRequestCheck;
import com.atlassian.bitbucket.permission.Permission;
import com.atlassian.bitbucket.permission.PermissionService;

import javax.annotation.Nonnull;
import java.io.IOException;

/**
 * Checks that the context user has permission to perform the requested type of action on the repository.
 *
 * @since 1.1
 */
public class RepositoryAuthorisationCheck implements ScmRequestCheck {

    private final I18nService i18nService;
    private final PermissionService permissionService;

    public RepositoryAuthorisationCheck(I18nService i18nService,
                                        PermissionService permissionService) {
        this.i18nService = i18nService;
        this.permissionService = permissionService;
    }

    @Override
    public boolean check(@Nonnull ScmRequest request) throws IOException {
        Repository repository = request.getRepository();
        if (isAuthorised(repository, request.isWrite())) {
            return true;
        }

        if (request.isWrite() && permissionService.isRepositoryAccessible(repository)) {
            // The user is trying to push to a read-only (for them) repository
            request.sendError(
                    i18nService.getMessage("bitbucket.scm.insufficient.permissions"),
                    i18nService.getMessage("bitbucket.scm.insufficient.permissions.detail",
                            repository.getProject().getKey(), repository.getSlug())
            );
        }

        return false;
    }

    private boolean isAuthorised(Repository repository, boolean write) {
        if (write) {
            // REPO_WRITE cannot be granted anonymously, so this implicitly checks that a user is authenticated
            return permissionService.hasRepositoryPermission(repository, Permission.REPO_WRITE);
        }
        // This check automatically handles anonymous access (public repositories), which have implicit REPO_READ
        // access always available, whether the caller is authenticated or not
        return permissionService.isRepositoryAccessible(repository);
    }
}
