package policy

// IAMPolicyDocument renders a policy document for IAM
type IAMPolicyDocument struct {
	Version   string               `json:"Version,omitempty"`
	Statement []IAMPolicyStatement `json:"Statement,omitempty"`
	// IsInvalid is True when the ammount of attached RolePolicies != 1
	IsInvalid error `json:"IsInvalid,omitempty"`
}

// IAMPolicyStatement describes a single set of permissions
type IAMPolicyStatement struct {
	Action    interface{}           `json:"Action,omitempty"`
	Resource  interface{}           `json:"Resource,omitempty"`
	Effect    string                `json:"Effect,omitempty"`
	Condition IAMStatementCondition `json:"Condition,omitempty"`
	Sid       string                `json:"Sid,omitempty"`
	Principal map[string][]string   `json:"Principal,omitempty"`
}

// IAMAssumeRolePolicy is basically an IAMPolicyDocument but holds an
// IAMAssumeRoleStatement, used for trust relationships.
type IAMAssumeRolePolicy struct {
	Version   string                   `json:"Version,omitempty"`
	Statement []IAMAssumeRoleStatement `json:"Statement,omitempty"`
}

// IAMAssumeRoleStatement is a special snowflake because IAM will change your
// data structures. i.e. if you pass a map[string][]string with slice
// containing one value it will be silently updated to a map[string]string
type IAMAssumeRoleStatement struct {
	Effect    string                 `json:"Effect,omitempty"`
	Action    string                 `json:"Action,omitempty"`
	Principal map[string]interface{} `json:"Principal,omitempty"`
	Resource  interface{}            `json:"Resource,omitempty"`
	Sid       string                 `json:"Sid,omitempty"`
	Condition IAMStatementCondition  `json:"Condition,omitempty"`
}

// IAMStatementCondition is the Condition element in an IAMPolicyStatement
type IAMStatementCondition map[string]map[string]interface{}

// DocumentVersion is the default version
const DocumentVersion = "2012-10-17"

// Sids for statements
const (
	SecretsTableSid   = "DynamoDBSecretsTable"
	NamespaceIndexSid = "DynamoDBNamespaceIndex"
	NamespaceTableSid = "DynamoDBNamespaceTable"
)

// ExtractPolicySecretKeys retrieves secret key names from provided IAMPolicyDocument
func ExtractPolicySecretKeys(doc IAMPolicyDocument) (keys []string) {
	for _, v := range doc.Statement {
		if v.Sid == SecretsTableSid {
			var ok bool
			var leadingKeys interface{}
			if leadingKeys, ok = v.Condition["ForAllValues:StringLike"]["dynamodb:LeadingKeys"]; ok {
				switch leadingKeys := leadingKeys.(type) {
				default:
				case []interface{}:
					for _, v := range leadingKeys {
						if k, ok := v.(string); ok {
							keys = append(keys, k)
						}
					}
				case []string:
					keys = append(keys, leadingKeys...)
				}
			}

			if leadingKeys, ok = v.Condition["ForAllValues:StringEquals"]["dynamodb:LeadingKeys"]; ok {
				switch leadingKeys := leadingKeys.(type) {
				default:
				case []interface{}:
					for _, v := range leadingKeys {
						if k, ok := v.(string); ok {
							keys = append(keys, k)
						}
					}
				case []string:
					keys = append(keys, leadingKeys...)
				}
			}
		}
	}
	return
}
