package com.atlassian.bitbucket.mesh.auth;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.security.PublicKey;
import java.util.Optional;

public interface AuthenticationManager {

    /**
     * Retrieves the {@link Principal} that was authenticated when the current request started. If no request is
     * active, or authentication has not yet completed, no principal will be available.
     *
     * @return the authenticated principal, or {@link Optional#empty} if no authenticated request is active
     */
    @Nonnull
    Optional<Principal> getPrincipal();

    /**
     * Retrieves the authenticated {@link Principal} for the current request, or throws an exception if there is
     * no authenticated principal or no active request.
     * <p>
     * <b>Note</b>: Because authentication can be disabled, developers should be careful about what contexts they
     * call this method in. The default is to run with authentication enabled, but it's a configurable setting.
     *
     * @return the authenticated principal
     * @throws IllegalStateException if no principal is authenticated
     */
    @Nonnull
    Principal getPrincipalOrThrow();

    /**
     * Retrieves the node's signing key, which comprises its public and private keys and their fingerprint. The
     * private key is used to sign tokens for outbound requests.
     *
     * @return the node's signing key
     */
    @Nonnull
    SigningKey getSigningKey();

    /**
     * Retrieves a flag indicating whether the node has been {@link #provision provisioned} by the control plane.
     *
     * @return {@code true} if the node has been provisioned; otherwise, {@code false}
     */
    boolean isProvisioned();

    /**
     * Provisions the node, performing the initial exchange of trust. The control plane's public key is recorded,
     * allowing the node to authenticate messages from the control plane, and the node's public key is returned
     * for the control plane to record and broadcast to other nodes along with the topology.
     *
     * @param publicKey the control plane's public key
     * @return the node's public key
     */
    @Nonnull
    PublicKey provision(@Nonnull PublicKey publicKey);

    /**
     * Updates the public keys used to authenticate requests from the control plane and other nodes in the
     * topology.
     *
     * @param parameters describes the public key updates to apply
     */
    void updatePublicKeys(@Nonnull UpdatePublicKeysParameters parameters);

    /**
     * Prepares the {@link #getPrincipal authenticated principal} while the provided {@link PrincipalCallback} is
     * executing.
     *
     * @param principal the authenticated principal
     * @param callback  called with the provided {@code principal}
     * @param <T>       type of the callback return value
     * @return the return value of the callback
     */
    @Nullable
    <T> T withPrincipal(@Nonnull Principal principal, @Nonnull PrincipalCallback<T> callback);
}
