package resource

import (
	"fmt"
	"strings"
)

// NewLocalStack returns a stack created by the sandstorm cloudformation template in a
// user's account
func NewLocalStack(accountNumber, awsRegion, stackName string) (Stack, error) {
	stack := localStack{
		accountNumber: accountNumber,
		awsRegion:     awsRegion,
		stackName:     stackName,
	}

	if err := stack.validate(); err != nil {
		return nil, err
	}

	return stack, nil
}

type localStack struct {
	// AWS account number the stack is in (required)
	accountNumber string
	// AWS Region of the stack (required)
	awsRegion string

	// Name of the stack - defaults to sandstorm (optional)
	stackName string
}

func (ls localStack) validate() error {
	missing := make([]string, 0)

	for _, attr := range []struct {
		Name  string
		Value string
	}{
		{"AccountNumber", ls.accountNumber},
		{"AWSRegion", ls.awsRegion},
	} {
		if attr.Value == "" {
			missing = append(missing, attr.Name)
		}
	}

	if len(missing) > 0 {
		return fmt.Errorf("LocalStack requires the following attributes: %s", strings.Join(missing, ","))
	}

	return nil
}

func (ls localStack) StackName() string {
	if ls.stackName == "" {
		return "sandstorm"
	}
	return ls.stackName
}

func (ls localStack) resourcePrefix() string {
	return strings.Join([]string{ls.StackName(), ls.AWSRegion()}, "-")
}

func (ls localStack) awsRegionArn(service, suffix string) string {
	return strings.Join([]string{"arn:aws", service, ls.awsRegion, ls.accountNumber, suffix}, ":")
}

func (ls localStack) iamArn(suffix string) string {
	return strings.Join([]string{"arn:aws:iam", "", ls.accountNumber, suffix}, ":")
}

func (ls localStack) iamRoleArn(name string) string {
	return ls.iamArn(strings.Join([]string{
		"role",
		strings.Join([]string{ls.resourcePrefix(), name}, "-"),
	}, "/"))
}

func (ls localStack) dynamoTableName(name string) string {
	return ls.resourceName(name)
}

func (ls localStack) resourceName(name ...string) string {
	return strings.Join(append([]string{ls.resourcePrefix()}, name...), "-")
}

func (ls localStack) AccountID() string {
	return ls.accountNumber
}

func (ls localStack) AgentTestingRoleARN() string {
	return ls.AdminRoleARN()
}

func (ls localStack) AdminRoleARN() string {
	return ls.iamRoleArn("admin")
}

func (ls localStack) AWSRegion() string {
	return ls.awsRegion
}

func (ls localStack) CloudwatchRoleARN() string {
	return ""
}

func (ls localStack) HeartbeatsTableName() string {
	return ls.dynamoTableName("heartbeats")
}

func (ls localStack) KMSKeys() []KMSKey {
	return []KMSKey{ls.KMSPrimaryKey()}
}

func (ls localStack) KMSPrimaryKey() KMSKey {
	return KMSKey{
		Region: ls.awsRegion,
		KeyARN: strings.Join([]string{"alias", ls.resourcePrefix()}, "/"),
	}
}

func (ls localStack) InventoryAdminRoleARN() string {
	return ls.AdminRoleARN()
}

func (ls localStack) InventoryRoleARN() string {
	// should be able to report to inventory without assuming another role
	return ""
}

func (ls localStack) InventoryStatusURL() string {
	return ""
}

func (ls localStack) ProxyURL() string {
	return "http://proxy.internal.justin.tv:9797/"
}

func (ls localStack) SecretsQueueNamePrefix() string {
	return ls.stackName
}

func (ls localStack) SecretsTableName() string {
	return ls.dynamoTableName("secrets")
}

func (ls localStack) SecretsTopicArn() string {
	return strings.Join(
		[]string{
			"arn:aws:sns",
			ls.awsRegion,
			ls.accountNumber,
			ls.resourceName("secrets"),
		}, ":")
}

func (ls localStack) AuditTableName() string {
	return ls.dynamoTableName("audits")
}

func (ls localStack) NamespaceTableName() string {
	return ls.dynamoTableName("namespaces")
}

func (ls localStack) PutHeartbeatLambdaFunctionName() string {
	return ls.resourceName("report-inventory")
}

func (ls localStack) Environment() string {
	return ls.stackName
}
