package resource

import (
	"net/http"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/endpoints"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sts"
)

// DefaultAWSConfigurer is the default AWSConfigurer
var defaultAWSConfigurer = AWSConfigurer{
	Region: "us-west-2",
}

// AWSConfigurer configures aws sessions
type AWSConfigurer struct {
	Region     string
	HTTPClient *http.Client
}

func (a AWSConfigurer) baseAWSConfig(awsCfg *aws.Config) *aws.Config {
	if awsCfg == nil {
		awsCfg = new(aws.Config)
	}
	return awsCfg.
		WithRegion(a.Region).
		WithEndpointResolver(AWSEndpointResolver{}).
		WithHTTPClient(a.HTTPClient).
		WithSTSRegionalEndpoint(endpoints.RegionalSTSEndpoint)
}

// BaseAWSCredentials returns base credentials if a profile is provided
func (a AWSConfigurer) BaseAWSCredentials(profile string) *credentials.Credentials {
	if profile == "" {
		return nil
	}

	return credentials.NewSharedCredentials("", profile)
}

// AWSCredentials returns credentials with an assume role chain
func (a AWSConfigurer) AWSCredentials(creds *credentials.Credentials, roleArns ...string) *credentials.Credentials {
	for _, roleArn := range roleArns {
		if roleArn == "" {
			continue
		}
		creds = stscreds.NewCredentials(session.New(
			a.baseAWSConfig(nil).WithCredentials(creds)), roleArn)
	}
	return creds
}

// AWSConfig returns a config with an assume role chain
func (a AWSConfigurer) AWSConfig(creds *credentials.Credentials, roleArns ...string) *aws.Config {
	return a.baseAWSConfig(nil).
		WithCredentials(a.AWSCredentials(creds, roleArns...))
}

// STSSession returns a session client with an assume role chain
func (a AWSConfigurer) STSSession(creds *credentials.Credentials, roleArns ...string) *session.Session {
	return session.New(a.AWSConfig(creds, roleArns...))
}

// GetAWSIdentity returns the identity after a role chain
func (a AWSConfigurer) GetAWSIdentity(creds *credentials.Credentials, roleArns ...string) string {
	identity, err := sts.New(a.STSSession(creds, roleArns...)).
		GetCallerIdentity(&sts.GetCallerIdentityInput{})
	if err != nil {
		return "unknown-user-arn"
	}

	return aws.StringValue(identity.Arn)
}
