package guardian

import (
	"code.justin.tv/systems/guardian/cfg"
	"code.justin.tv/systems/guardian/osin"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/dynamodb"
)

// Storage implements osin.Storage for DynamoDB
type Storage struct {
	DB         *dynamodb.DynamoDB
	Config     *cfg.DBConfig
	Identifier Identifier
}

// Clone returns itself
func (db *Storage) Clone() (storage osin.Storage) {
	storage = db
	return
}

// Close is a noop for dynamodb
func (db *Storage) Close() {
	return
}

// CreateClientsTable creates clients table in dynamodb based on parameters
// defined in cfg.DBConfig.
func (db *Storage) CreateClientsTable() (err error) {
	params := &dynamodb.CreateTableInput{
		AttributeDefinitions: []*dynamodb.AttributeDefinition{
			{
				AttributeName: aws.String("id"),
				AttributeType: aws.String(dynamodb.ScalarAttributeTypeS),
			},
		},
		ProvisionedThroughput: &dynamodb.ProvisionedThroughput{
			ReadCapacityUnits:  aws.Int64(50),
			WriteCapacityUnits: aws.Int64(50),
		},
		KeySchema: []*dynamodb.KeySchemaElement{
			{
				AttributeName: aws.String("id"),
				KeyType:       aws.String(dynamodb.KeyTypeHash),
			},
		},
		TableName: aws.String(db.Config.ClientsTable),
	}
	_, err = db.DB.CreateTable(params)
	if err != nil {
		return
	}
	return
}

// CreateAuthorizationsTable creates clients table in dynamodb based on
// parameters defined in cfg.DBConfig.
func (db *Storage) CreateAuthorizationsTable() (err error) {
	params := &dynamodb.CreateTableInput{
		AttributeDefinitions: []*dynamodb.AttributeDefinition{
			{
				AttributeName: aws.String("token_hash"),
				AttributeType: aws.String(dynamodb.ScalarAttributeTypeS),
			},
		},
		ProvisionedThroughput: &dynamodb.ProvisionedThroughput{
			ReadCapacityUnits:  aws.Int64(50),
			WriteCapacityUnits: aws.Int64(50),
		},
		KeySchema: []*dynamodb.KeySchemaElement{
			{
				AttributeName: aws.String("token_hash"),
				KeyType:       aws.String(dynamodb.KeyTypeHash),
			},
		},
		TableName: aws.String(db.Config.AuthorizationsTable),
	}
	_, err = db.DB.CreateTable(params)
	if err != nil {
		return
	}
	return
}

// CreateTables creates both clients and authorizations tables required for
// guardian in dynamodb.
func (db *Storage) CreateTables() (err error) {
	err = db.CreateAuthorizationsTable()
	if err != nil {
		return
	}

	err = db.CreateClientsTable()
	if err != nil {
		return
	}
	return
}

// NewDynamoDBStorage returns a new osin.Storage backed by DynamoDB
func NewDynamoDBStorage(c *cfg.Config, identifier Identifier) *Storage {
	return &Storage{
		DB:         dynamodb.New(c.DB.AWSSession),
		Config:     c.DB,
		Identifier: identifier,
	}
}
