package policy

import (
	"fmt"

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

// DeleteOldestPolicyVersion AWS allows 5 policy version, this method deletes the oldest
// policy version if there are 5 (or more : for whatever reason) policy version.
// The caller can assume that the policy has less than 5 version if no error was returned.
// And it should be able to create a new version of the policy.
// returns the list of attched versions with the policy
func (pg *IAMPolicyGenerator) DeleteOldestPolicyVersion(policyArn string) (*iam.ListPolicyVersionsOutput, error) {

	var policyVersions *iam.ListPolicyVersionsOutput

	policyVersions, err := pg.IAM.ListPolicyVersions(&iam.ListPolicyVersionsInput{
		PolicyArn: aws.String(policyArn),
	})
	if err != nil {
		return nil, err
	}
	// Delete oldest policy if more than 4 versions exist
	// IAM will fail if > 4 versions exist
	if len(policyVersions.Versions) > 4 {
		oldestVersion := policyVersions.Versions[0]
		oldestVersionIndex := 0
		for index, v := range policyVersions.Versions {
			if v.CreateDate.Before(*oldestVersion.CreateDate) {
				oldestVersion = v
				oldestVersionIndex = index
			}
		}

		_, err = pg.DeletePolicyVersion(policyArn, oldestVersion.VersionId)
		if err != nil {
			return nil, err
		}

		policyVersions.Versions = append(policyVersions.Versions[:oldestVersionIndex], policyVersions.Versions[oldestVersionIndex+1:]...)
	}
	return policyVersions, nil
}

//CreateNewPolicyVersion creates a new policy version
func (pg *IAMPolicyGenerator) CreateNewPolicyVersion(policyArn string, policyDocBytes []byte, setAsDefault bool) (*iam.CreatePolicyVersionOutput, error) {
	// Create new policy
	createPolicyVersionInput := &iam.CreatePolicyVersionInput{
		PolicyDocument: aws.String(string(policyDocBytes)),
		PolicyArn:      aws.String(policyArn),
		SetAsDefault:   aws.Bool(setAsDefault),
	}
	return pg.IAM.CreatePolicyVersion(createPolicyVersionInput)
}

// DeletePolicyVersion Delete a policyVersionId associated with policyArn
// Note: Default policy version cannot be deleted using this API
func (pg *IAMPolicyGenerator) DeletePolicyVersion(policyArn string, policyVersionID *string) (*iam.DeletePolicyVersionOutput, error) {
	return pg.IAM.DeletePolicyVersion(&iam.DeletePolicyVersionInput{
		PolicyArn: aws.String(policyArn),
		VersionId: policyVersionID,
	})
}

// DeletePolicyVersions Delete policyVersions associated with policyArn
func (pg *IAMPolicyGenerator) DeletePolicyVersions(policyArn string, policyVersions *iam.ListPolicyVersionsOutput) error {
	// Delete old policies
	for _, v := range policyVersions.Versions {
		_, err := pg.DeletePolicyVersion(policyArn, v.VersionId)
		if err != nil {
			return err
		}
	}
	return nil
}

// DeleteAllPolicyVersions deletes all policyversions associated with a policy except the default version.
func (pg *IAMPolicyGenerator) DeleteAllPolicyVersions(policyArn string) error {
	if policyArn == "" {
		return fmt.Errorf("Please provide policy arn to delete all policy version")
	}

	var policyVersions *iam.ListPolicyVersionsOutput
	policyVersions, err := pg.IAM.ListPolicyVersions(&iam.ListPolicyVersionsInput{
		PolicyArn: aws.String(policyArn),
	})

	if err != nil {
		return fmt.Errorf("Error retrieving policy %s versions: %s", policyArn, err.Error())
	}

	for _, v := range policyVersions.Versions {
		// We cant delete default policy version using func (*IAM) DeletePolicyVersion
		if aws.BoolValue(v.IsDefaultVersion) {
			continue
		}
		_, err = pg.DeletePolicyVersion(policyArn, v.VersionId)
		if err != nil {
			return fmt.Errorf("Error deleting group policy %s version %s: %s", policyArn, aws.StringValue(v.VersionId), err.Error())
		}
	}
	return nil
}
