package policy

import (
	"encoding/json"
	"fmt"

	"code.justin.tv/systems/sandstorm/manager"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/iam"
)

// Create creates a role and policy
func (pg *IAMPolicyGenerator) Create(
	request *CreateRoleRequest,
	auth Authorizer,
	secrets SecretsManager,
) (response *CreateRoleResponse, err error) {
	// Validate input
	if request.Name == "" || len(request.Owners) == 0 || len(request.AllowedArns) == 0 {
		return nil, manager.InvalidRequestError{Message: fmt.Errorf("Name,Owners,or AllowedARNS in invalid state. All are required")}
	}

	err = auth.AuthorizeSecretKeys(request.SecretKeys)
	if err != nil {
		return
	}

	namespaces, err := ValidateNamespaces(request.SecretKeys, secrets) //need full namespace for policy document creation
	if err != nil {
		return
	}

	assumeRolePolicyDocument := pg.AssumeRolePolicyDocument(request.AllowedArns)
	assumeRoleDoc, err := json.Marshal(assumeRolePolicyDocument)
	if err != nil {
		pg.Logger.Errorf("policy: error marshalling assume role policy doc: %s", err.Error())
		return
	}

	createRoleInput := &iam.CreateRoleInput{
		RoleName:                 aws.String(request.Name),
		AssumeRolePolicyDocument: aws.String(string(assumeRoleDoc)),
		Path: aws.String(pg.PathPrefix(IAMRolePathSuffix)),
	}

	createRoleResponse, err := pg.IAM.CreateRole(createRoleInput)
	if err != nil {
		pg.Logger.Errorf("policy: error creating role: %s", err.Error())
		return
	}

	policyDoc := pg.PolicyDocument(request.SecretKeys, namespaces, request.WriteAccess, aws.StringValue(createRoleResponse.Role.Arn))
	policyDocBytes, err := json.Marshal(policyDoc)
	if err != nil {
		pg.Logger.Errorf("policy: error marshalling policy document: %s", err.Error())
		return
	}

	createPolicyInput := &iam.CreatePolicyInput{
		Path:           aws.String(pg.PathPrefix(IAMPolicyPathSuffix)),
		PolicyDocument: aws.String(string(policyDocBytes)),
		PolicyName:     aws.String(request.Name),
		Description:    aws.String(IAMPolicyDescription),
	}

	createPolicyResponse, err := pg.IAM.CreatePolicy(createPolicyInput)
	if err != nil {
		pg.Logger.Errorf("policy: error creating policy document: %s", err.Error())
		return
	}

	attachPolicyInput := &iam.AttachRolePolicyInput{
		RoleName:  createRoleResponse.Role.RoleName,
		PolicyArn: createPolicyResponse.Policy.Arn,
	}

	_, err = pg.IAM.AttachRolePolicy(attachPolicyInput)
	if err != nil {
		pg.Logger.Errorf("policy: error attaching role policy: %s", err.Error())
		return
	}

	err = pg.attachAuxPolicy(request.Name, request.WriteAccess)
	if err != nil {
		pg.Logger.Errorf("policy: error attaching aux policy: %s", err.Error())
		return
	}

	owners, err := pg.CreateRoleOwners(request.Name, request.Owners, auth)
	if err != nil {
		return
	}

	response = &CreateRoleResponse{
		RoleArn:          aws.StringValue(createRoleResponse.Role.Arn),
		RoleName:         aws.StringValue(createRoleResponse.Role.RoleName),
		AllowedArns:      request.AllowedArns,
		Policy:           policyDoc,
		AssumeRolePolicy: pg.ExternalAssumeRolePolicyDocument(aws.StringValue(createRoleResponse.Role.Arn)),
		AuxPolicyArn:     pg.auxPolicyArn(request.WriteAccess),
		WriteAccess:      request.WriteAccess,
		Owners:           owners,
	}
	return
}
