package euls

import (
	"errors"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/service/cognitoidentity"
)

// CognitoIdentityProvider is implements credentials.Provider by using an
// Cognito Identity Pool to create guest user credentials.
type CognitoIdentityProvider struct {
	Svc            *cognitoidentity.CognitoIdentity
	AccountID      string
	IdentityPoolID string
	cachedCreds    *cognitoidentity.Credentials
}

// Retrieve retrieves credentials using the specificed Account and Identity Pool.
// Credentials are cached after the first call.
func (p *CognitoIdentityProvider) Retrieve() (credentials.Value, error) {
	if p.cachedCreds == nil {
		// Retreive new creds
		if err := p.retrieveAndCache(); err != nil {
			return credentials.Value{}, err
		}
	}

	// TODO: check expiration

	return credentials.Value{
		AccessKeyID:     *p.cachedCreds.AccessKeyId,
		SecretAccessKey: *p.cachedCreds.SecretKey,
		SessionToken:    *p.cachedCreds.SessionToken,
		ProviderName:    "CognitoIdentity",
	}, nil
}

// IsExpired determines if credentials exist in the provider.
func (p *CognitoIdentityProvider) IsExpired() bool {
	// Oddly, this is what the other credentials do. They don't check for expiration?
	return p.cachedCreds == nil
}

func (p *CognitoIdentityProvider) retrieveAndCache() error {
	if p.Svc == nil {
		return errors.New("cognito identity service is nil")
	}

	idOutput, err := p.Svc.GetId(&cognitoidentity.GetIdInput{
		AccountId:      aws.String(p.AccountID),
		IdentityPoolId: aws.String(p.IdentityPoolID),
	})
	if err != nil {
		return err
	}

	creds, err := p.Svc.GetCredentialsForIdentity(&cognitoidentity.GetCredentialsForIdentityInput{
		IdentityId: idOutput.IdentityId,
	})
	if err != nil {
		return err
	}

	p.cachedCreds = creds.Credentials
	return nil
}
