package accesscontrol

import (
	"context"
	"sync"

	rbac "github.com/rancher/wrangler/v3/pkg/generated/controllers/rbac/v1"
	"github.com/rancher/wrangler/v3/pkg/kv"
	rbacv1 "k8s.io/api/rbac/v1"
)

type roleRevisionIndex struct {
	roleRevisions sync.Map
}

func newRoleRevision(ctx context.Context, rbac rbac.Interface) *roleRevisionIndex {
	r := &roleRevisionIndex{}
	rbac.Role().OnChange(ctx, "role-revision-indexer", r.onRoleChanged)
	rbac.ClusterRole().OnChange(ctx, "role-revision-indexer", r.onClusterRoleChanged)
	return r
}

func (r *roleRevisionIndex) roleRevision(namespace, name string) string {
	val, _ := r.roleRevisions.Load(roleKey{
		name:      name,
		namespace: namespace,
	})
	revision, _ := val.(string)
	return revision
}

func (r *roleRevisionIndex) onClusterRoleChanged(key string, cr *rbacv1.ClusterRole) (role *rbacv1.ClusterRole, err error) {
	if cr == nil {
		r.roleRevisions.Delete(roleKey{
			name: key,
		})
	} else {
		r.roleRevisions.Store(roleKey{
			name: key,
		}, cr.ResourceVersion)
	}
	return cr, nil
}

func (r *roleRevisionIndex) onRoleChanged(key string, cr *rbacv1.Role) (role *rbacv1.Role, err error) {
	if cr == nil {
		namespace, name := kv.Split(key, "/")
		r.roleRevisions.Delete(roleKey{
			name:      name,
			namespace: namespace,
		})
	} else {
		r.roleRevisions.Store(roleKey{
			name:      cr.Name,
			namespace: cr.Namespace,
		}, cr.ResourceVersion)
	}
	return cr, nil
}