package aws

import (
	"context"
	"fmt"
	"net/http"

	"github.com/fatih/structs"
	"github.com/hashicorp/vault/sdk/framework"
	"github.com/hashicorp/vault/sdk/logical"
)

const (
	pathStaticCreds = "static-creds"

	paramAccessKeyID      = "access_key"
	paramSecretsAccessKey = "secret_key"
)

type awsCredentials struct {
	AccessKeyID     string `json:"access_key" structs:"access_key" mapstructure:"access_key"`
	SecretAccessKey string `json:"secret_key" structs:"secret_key" mapstructure:"secret_key"`
}

func pathStaticCredentials(b *backend) *framework.Path {
	return &framework.Path{
		Pattern: fmt.Sprintf("%s/%s", pathStaticCreds, framework.GenericNameWithAtRegex(paramRoleName)),
		Fields: map[string]*framework.FieldSchema{
			paramRoleName: {
				Type:        framework.TypeString,
				Description: descRoleName,
			},
		},

		Operations: map[logical.Operation]framework.OperationHandler{
			logical.ReadOperation: &framework.PathOperation{
				Callback: b.pathStaticCredsRead,
				Responses: map[int][]framework.Response{
					http.StatusOK: {{
						Description: http.StatusText(http.StatusOK),
						Fields: map[string]*framework.FieldSchema{
							paramAccessKeyID: {
								Type:        framework.TypeString,
								Description: descAccessKeyID,
							},
							paramSecretsAccessKey: {
								Type:        framework.TypeString,
								Description: descSecretAccessKey,
							},
						},
					}},
				},
			},
		},

		HelpSynopsis:    pathStaticCredsHelpSyn,
		HelpDescription: pathStaticCredsHelpDesc,
	}
}

func (b *backend) pathStaticCredsRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
	roleName, ok := data.GetOk(paramRoleName)
	if !ok {
		return nil, fmt.Errorf("missing %q parameter", paramRoleName)
	}

	entry, err := req.Storage.Get(ctx, formatCredsStoragePath(roleName.(string)))
	if err != nil {
		return nil, fmt.Errorf("failed to read credentials for role %q: %w", roleName, err)
	}
	if entry == nil {
		return nil, nil
	}

	var credentials awsCredentials
	if err := entry.DecodeJSON(&credentials); err != nil {
		return nil, fmt.Errorf("failed to decode credentials: %w", err)
	}

	return &logical.Response{
		Data: structs.New(credentials).Map(),
	}, nil
}

func formatCredsStoragePath(roleName string) string {
	return fmt.Sprintf("%s/%s", pathStaticCreds, roleName)
}

const pathStaticCredsHelpSyn = `Retrieve static credentials from the named role.`

const pathStaticCredsHelpDesc = `
This path reads AWS credentials for a certain static role. The keys are rotated
periodically according to their configuration, and will return the same password
until they are rotated.`

const (
	descAccessKeyID     = "The access key of the AWS Credential"
	descSecretAccessKey = "The secret key of the AWS Credential"
)
