package v4a

import (
	
	
	
	
	
	

	
	
)

// Credentials is Context, ECDSA, and Optional Session Token that can be used
// to sign requests using SigV4a
type Credentials struct {
	Context      string
	PrivateKey   *ecdsa.PrivateKey
	SessionToken string

	// Time the credentials will expire.
	CanExpire bool
	Expires   time.Time
}

// Expired returns if the credentials have expired.
func ( Credentials) () bool {
	if .CanExpire {
		return !.Expires.After(sdk.NowTime())
	}

	return false
}

// HasKeys returns if the credentials keys are set.
func ( Credentials) () bool {
	return len(.Context) > 0 && .PrivateKey != nil
}

// SymmetricCredentialAdaptor wraps a SigV4 AccessKey/SecretKey provider and adapts the credentials
// to a ECDSA PrivateKey for signing with SiV4a
type SymmetricCredentialAdaptor struct {
	SymmetricProvider aws.CredentialsProvider

	asymmetric atomic.Value
	m          sync.Mutex
}

// Retrieve retrieves symmetric credentials from the underlying provider.
func ( *SymmetricCredentialAdaptor) ( context.Context) (aws.Credentials, error) {
	,  := .retrieveFromSymmetricProvider()
	if  != nil {
		return aws.Credentials{}, 
	}

	if  := .getCreds();  == nil {
		return , nil
	}

	.m.Lock()
	defer .m.Unlock()

	 := .getCreds()
	if  == nil {
		return , nil
	}

	// if the context does not match the access key id clear it
	if .Context != .AccessKeyID {
		.asymmetric.Store((*Credentials)(nil))
	}

	return , nil
}

// RetrievePrivateKey returns credentials suitable for SigV4a signing
func ( *SymmetricCredentialAdaptor) ( context.Context) (Credentials, error) {
	if  := .getCreds();  != nil {
		return *, nil
	}

	.m.Lock()
	defer .m.Unlock()

	if  := .getCreds();  != nil {
		return *, nil
	}

	,  := .retrieveFromSymmetricProvider()
	if  != nil {
		return Credentials{}, fmt.Errorf("failed to retrieve symmetric credentials: %v", )
	}

	,  := deriveKeyFromAccessKeyPair(.AccessKeyID, .SecretAccessKey)
	if  != nil {
		return Credentials{}, fmt.Errorf("failed to derive assymetric key from credentials")
	}

	 := Credentials{
		Context:      .AccessKeyID,
		PrivateKey:   ,
		SessionToken: .SessionToken,
		CanExpire:    .CanExpire,
		Expires:      .Expires,
	}

	.asymmetric.Store(&)

	return , nil
}

func ( *SymmetricCredentialAdaptor) () *Credentials {
	 := .asymmetric.Load()

	if  == nil {
		return nil
	}

	 := .(*Credentials)
	if  != nil && .HasKeys() && !.Expired() {
		return 
	}

	return nil
}

func ( *SymmetricCredentialAdaptor) ( context.Context) (aws.Credentials, error) {
	,  := .SymmetricProvider.Retrieve()
	if  != nil {
		return aws.Credentials{}, 
	}

	return , nil
}

// CredentialsProvider is the interface for a provider to retrieve credentials
// to sign requests with.
type CredentialsProvider interface {
	RetrievePrivateKey(context.Context) (Credentials, error)
}