package com.atlassian.stash.internal.build.util;

import com.atlassian.sal.api.auth.OAuthRequestVerifierFactory;
import com.atlassian.bitbucket.auth.AuthenticationContext;
import com.atlassian.bitbucket.permission.Permission;
import com.atlassian.bitbucket.user.SecurityService;
import com.atlassian.bitbucket.util.Operation;

// At some point we may want to extract this to somewhere more common
public class OAuthHelper {

    private final AuthenticationContext authenticationContext;
    private final OAuthRequestVerifierFactory oauthRequestVerifierFactory;
    private final SecurityService securityService;

    public OAuthHelper(AuthenticationContext authenticationContext,
                       OAuthRequestVerifierFactory oauthRequestVerifierFactory, SecurityService securityService) {
        this.authenticationContext = authenticationContext;
        this.oauthRequestVerifierFactory = oauthRequestVerifierFactory;
        this.securityService = securityService;
    }

    /**
     * Escalate the given {@code op} with the provided permission if the current request is over 2LO <i>and</i> is
     * anonymous.
     *
     * @param permission the permission to run with if the above conditions are met
     * @param op         the operation to perform
     * @return the result of performing {@code op}
     */
    public <T, E extends Throwable> T withPermissionIfAnonymous2LO(Permission permission, Operation<T, E> op) throws E {
        // This checks the very specific case that we have a verified oauth request, but no user
        boolean isOauth2LO = oauthRequestVerifierFactory.getInstance(null).isVerified() &&
                // For 3LO or 2LOi then respect the user
                !authenticationContext.isAuthenticated();
        if (isOauth2LO) {
            return securityService.withPermission(permission, "Escalated permission for anonymous 2LO").call(op);
        } else {
            return op.perform();
        }
    }
}
