package rbac

type Permission string

const (
	Read  Permission = "read"
	Write Permission = "write"
	// Root is the high-impact tier: destructive or irreversible operations
	// (reboot, shutdown, account deletion, firewall flush, …) that callers
	// should be able to grant separately from routine writes.
	Root Permission = "root"
	All  Permission = "*" // wildcard: matches any permission
)

// Wildcard is the module-key value that matches all modules in a Role's grants.
const Wildcard = "*"

type Role struct {
	Name         string
	ModuleGrants map[string][]Permission // module ID (or "*") -> permissions (each may be "*")
}

type RBAC struct {
	roles     map[string]Role
	userRoles map[string][]string
}

func New() *RBAC {
	return &RBAC{
		roles:     make(map[string]Role),
		userRoles: make(map[string][]string),
	}
}

func (r *RBAC) DefineRole(role Role) {
	r.roles[role.Name] = role
}

// RoleExists reports whether a role with the given name has been defined.
func (r *RBAC) RoleExists(name string) bool {
	_, ok := r.roles[name]
	return ok
}

func (r *RBAC) AssignRole(username, roleName string) {
	r.userRoles[username] = append(r.userRoles[username], roleName)
}

// Can checks whether the user holds any role granting (module, perm),
// honoring "*" wildcards on both the module key and inside the permission list.
func (r *RBAC) Can(username, module string, perm Permission) bool {
	for _, roleName := range r.userRoles[username] {
		role, ok := r.roles[roleName]
		if !ok {
			continue
		}
		// Check the exact module key AND the wildcard module key.
		for _, key := range []string{module, Wildcard} {
			grants, ok := role.ModuleGrants[key]
			if !ok {
				continue
			}
			for _, p := range grants {
				if p == perm || p == All {
					return true
				}
			}
		}
	}
	return false
}
