package auth

import "sync/atomic"

// roleMatrix is the DB-managed role glob set (role_permissions table, ERP
// Role Management). It is the ONLY role-permission source: a role absent
// from it — or the matrix never loaded — resolves to NO permissions
// (explicit deny by omission). Admin and owner bypass separately in Can()
// and publish "*" in EffectivePermissions/EffectiveRoleSet.
var roleMatrix atomic.Pointer[map[Role][]string]

// SetRoleMatrix installs DB-managed role globs (multi-tenant §6: centralized
// role management). Loaded at boot and hot-reloaded after every ERP Role
// Management mutation.
func SetRoleMatrix(m map[Role][]string) { roleMatrix.Store(&m) }

// RoleMatrix returns the active matrix (nil = nothing loaded, deny-all).
func RoleMatrix() map[Role][]string {
	if m := roleMatrix.Load(); m != nil {
		return *m
	}
	return nil
}

// globsFor returns DB-managed globs for a role when present, else nothing.
// A role listed with an empty set gets NO permissions; so does a role
// missing from the matrix entirely.
func globsFor(r Role) []string {
	if m := roleMatrix.Load(); m != nil {
		if g, ok := (*m)[r]; ok {
			return g
		}
	}
	return nil
}

// EffectiveRoleSet resolves one role's allow-set with the SAME resolution
// User.EffectivePermissions uses: the DB row set when the role has rows,
// else deny-all. Admin and owner keep the "*" wildcard parity publish.
func EffectiveRoleSet(role Role, rows []string, hasRows bool) map[string]bool {
	var globs []string
	if hasRows {
		globs = rows
	}
	m := expandGlobs(globs)
	if role == RoleAdmin || role == RoleOwner {
		m["*"] = true
	}
	return m
}
