package accesscontrol

import (
	"context"
	"strings"
)

// Metadata contains user accesses for a given resource
// Ex: map[string]bool{"create":true, "delete": true}
type Metadata map[string]bool

// GetResourcesMetadata returns a map of accesscontrol metadata, listing for each resource, users available actions
func GetResourcesMetadata(ctx context.Context, permissions map[string][]string, prefix string, resourceIDs map[string]bool) map[string]Metadata {
	_, span := tracer.Start(ctx, "accesscontrol.GetResourcesMetadata")
	defer span.End()

	wildcards := WildcardsFromPrefix(prefix)

	// index of the prefix in the scope
	prefixIndex := len(prefix)

	// Loop through permissions once
	result := map[string]Metadata{}

	for action, scopes := range permissions {
		for _, scope := range scopes {
			if wildcards.Contains(scope) {
				for id := range resourceIDs {
					result = addActionToMetadata(result, action, id)
				}
				break
			}
			if len(scope) > prefixIndex && strings.HasPrefix(scope, prefix) && resourceIDs[scope[prefixIndex:]] {
				// Add action to a specific resource
				result = addActionToMetadata(result, action, scope[prefixIndex:])
			}
		}
	}

	return result
}

func addActionToMetadata(allMetadata map[string]Metadata, action, id string) map[string]Metadata {
	metadata, initialized := allMetadata[id]
	if !initialized {
		metadata = Metadata{action: true}
	} else {
		metadata[action] = true
	}
	allMetadata[id] = metadata
	return allMetadata
}

// MergeMeta will merge actions matching prefix of second metadata into first
func MergeMeta(prefix string, first Metadata, second Metadata) Metadata {
	if first == nil {
		first = Metadata{}
	}

	for key := range second {
		if strings.HasPrefix(key, prefix) {
			first[key] = true
		}
	}
	return first
}
