package bearer

import (
	
	

	
	smithyhttp 
)

// Message is the middleware stack's request transport message value.
type Message interface{}

// Signer provides an interface for implementations to decorate a request
// message with a bearer token. The signer is responsible for validating the
// message type is compatible with the signer.
type Signer interface {
	SignWithBearerToken(context.Context, Token, Message) (Message, error)
}

// AuthenticationMiddleware provides the Finalize middleware step for signing
// an request message with a bearer token.
type AuthenticationMiddleware struct {
	signer        Signer
	tokenProvider TokenProvider
}

// AddAuthenticationMiddleware helper adds the AuthenticationMiddleware to the
// middleware Stack in the Finalize step with the options provided.
func ( *middleware.Stack,  Signer,  TokenProvider) error {
	return .Finalize.Add(
		NewAuthenticationMiddleware(, ),
		middleware.After,
	)
}

// NewAuthenticationMiddleware returns an initialized AuthenticationMiddleware.
func ( Signer,  TokenProvider) *AuthenticationMiddleware {
	return &AuthenticationMiddleware{
		signer:        ,
		tokenProvider: ,
	}
}

const authenticationMiddlewareID = "BearerTokenAuthentication"

// ID returns the resolver identifier
func ( *AuthenticationMiddleware) () string {
	return authenticationMiddlewareID
}

// HandleFinalize implements the FinalizeMiddleware interface in order to
// update the request with bearer token authentication.
func ( *AuthenticationMiddleware) (
	 context.Context,  middleware.FinalizeInput,  middleware.FinalizeHandler,
) (
	 middleware.FinalizeOutput,  middleware.Metadata,  error,
) {
	,  := .tokenProvider.RetrieveBearerToken()
	if  != nil {
		return , , fmt.Errorf("failed AuthenticationMiddleware wrap message, %w", )
	}

	,  := .signer.SignWithBearerToken(, , .Request)
	if  != nil {
		return , , fmt.Errorf("failed AuthenticationMiddleware sign message, %w", )
	}

	.Request = 
	return .HandleFinalize(, )
}

// SignHTTPSMessage provides a bearer token authentication implementation that
// will sign the message with the provided bearer token.
//
// Will fail if the message is not a smithy-go HTTP request or the request is
// not HTTPS.
type SignHTTPSMessage struct{}

// NewSignHTTPSMessage returns an initialized signer for HTTP messages.
func () *SignHTTPSMessage {
	return &SignHTTPSMessage{}
}

// SignWithBearerToken returns a copy of the HTTP request with the bearer token
// added via the "Authorization" header, per RFC 6750, https://datatracker.ietf.org/doc/html/rfc6750.
//
// Returns an error if the request's URL scheme is not HTTPS, or the request
// message is not an smithy-go HTTP Request pointer type.
func (SignHTTPSMessage) ( context.Context,  Token,  Message) (Message, error) {
	,  := .(*smithyhttp.Request)
	if ! {
		return nil, fmt.Errorf("expect smithy-go HTTP Request, got %T", )
	}

	if !.IsHTTPS() {
		return nil, fmt.Errorf("bearer token with HTTP request requires HTTPS")
	}

	 := .Clone()
	.Header.Set("Authorization", "Bearer "+.Value)

	return , nil
}