package manager

import (
	"encoding/base64"
	"fmt"
	"strconv"
	"strings"

	"code.justin.tv/common/ddbmetrics"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/dynamodb"
)

// Put will take a plaintext secret, encrypt and then insert it into DynamoDB
func (m *Manager) Put(secret *Secret) error {
	// Create the newest version of the secret and persist it
	if err := m.Seal(secret); err != nil {
		return err
	}
	return m.put(secret)
}

func (m *Manager) put(secret *Secret) error {
	putInput := m.inputForPut(secret)
	putOutput, err := m.DynamoDB.PutItem(putInput)
	if err != nil {
		return fmt.Errorf("Error writing to %s: %s", *putInput.TableName, err)
	}
	m.metrics.Report(ddbmetrics.Write, putOutput.ConsumedCapacity)

	auditPutInput := putInput
	auditPutInput.TableName = aws.String(m.AuditTableName())
	auditPutOutput, err := m.DynamoDB.PutItem(auditPutInput)
	if err != nil {
		return fmt.Errorf("Error writing to %s: %s", *putInput.TableName, err)
	}
	m.metrics.Report(ddbmetrics.Write, auditPutOutput.ConsumedCapacity)

	nsInput := m.inputForNamespacePut(SecretNameToNamespace(secret.Name))
	nsOutput, err := m.DynamoDB.PutItem(nsInput)
	if err != nil {
		return fmt.Errorf("Error writing to %s: %s", *nsInput.TableName, err)
	}
	m.metrics.Report(ddbmetrics.Write, nsOutput.ConsumedCapacity)

	return nil
}

// SecretNameToNamespace strips the namespace from a secret's Name
func SecretNameToNamespace(secretName string) string {
	splitSecret := strings.SplitN(secretName, "/", 2)
	return splitSecret[0]
}

func (m *Manager) inputForPut(secret *Secret) *dynamodb.PutItemInput {
	return &dynamodb.PutItemInput{
		Item: map[string]*dynamodb.AttributeValue{
			"name":             &dynamodb.AttributeValue{S: aws.String(secret.Name)},
			"namespace":        &dynamodb.AttributeValue{S: aws.String(SecretNameToNamespace(secret.Name))},
			"updated_at":       &dynamodb.AttributeValue{N: aws.String(strconv.FormatInt(secret.UpdatedAt, 10))},
			"key":              &dynamodb.AttributeValue{S: aws.String(base64.StdEncoding.EncodeToString(secret.key))},
			"value":            &dynamodb.AttributeValue{S: aws.String(base64.StdEncoding.EncodeToString(secret.ciphertext))},
			"do_not_broadcast": &dynamodb.AttributeValue{BOOL: aws.Bool(secret.DoNotBroadcast)},
			"key_arn":          &dynamodb.AttributeValue{S: aws.String(secret.KeyARN)},
		},
		ReturnConsumedCapacity: aws.String("INDEXES"),
		TableName:              aws.String(m.Config.TableName),
	}
}

func (m *Manager) inputForNamespacePut(namespace string) *dynamodb.PutItemInput {
	return &dynamodb.PutItemInput{
		Item: map[string]*dynamodb.AttributeValue{
			"namespace": {S: aws.String(namespace)},
		},
		TableName:              aws.String(m.NamespaceTableName()),
		ReturnConsumedCapacity: aws.String("INDEXES"),
	}
}
