package asiimov

import (
	"code.justin.tv/systems/guardian/guardian"
	"fmt"
)

// isElement checks if any group in groups is in the set
func isElement(groups []string, set map[string]struct{}) bool {
	for _, group := range groups {
		if _, ok := set[group]; ok {
			return true
		}
	}
	return false
}

// DefaultVerifyAccess will check against allowedGroups and disAllowedGroups (if either defined)
// to determine whether access can be granted
func (a *Asiimov) DefaultVerifyAccess(user *guardian.User) error {
	var membership bool

	if a.disallowedGroups != nil && len(a.disallowedGroups) > 0 {
		if membership = isElement(user.Groups, a.disallowedGroups); membership {
			return fmt.Errorf("asiimov: User is member of a disallowed group")
		}
	}

	if a.allowedGroups != nil && len(a.allowedGroups) > 0 {
		if membership = isElement(user.Groups, a.allowedGroups); !membership {
			return fmt.Errorf("asiimov: User's groups are not represented in allowed groups")
		}
	}
	return nil
}

// AllowGroups allows for a list of valid groups for verification with DefaultVerify
func (a *Asiimov) AllowGroups(groups []string) error {
	if len(groups) == 0 {
		return fmt.Errorf("asiimov: empty []string passed to AddAllowedGroups")
	}
	if a.allowedGroups == nil {
		a.allowedGroups = make(map[string]struct{})
	}
	for _, group := range groups {
		if a.disallowedGroups != nil {
			if _, ok := a.disallowedGroups[group]; ok {
				return fmt.Errorf("asiimov: Attempting to allow a group that has been disallowed: %s", group)
			}
		}
		a.allowedGroups[group] = struct{}{}
	}
	return nil
}

// DisallowGroups adds a list of disallowed groups to Asiimov
func (a *Asiimov) DisallowGroups(groups []string) error {
	if len(groups) == 0 {
		return fmt.Errorf("asiimov: empty []string passed to AddDisallowedGroups")
	}
	if a.disallowedGroups == nil {
		a.disallowedGroups = make(map[string]struct{})
	}
	for _, group := range groups {
		if a.allowedGroups != nil {
			if _, ok := a.allowedGroups[group]; ok {
				return fmt.Errorf("asiimov: Attempting to disallow a group that has been allowed: %v", group)
			}
		}

		a.disallowedGroups[group] = struct{}{}
	}
	return nil
}
