package rbac

import (
	"testing"

	"github.com/casbin/casbin/v2"
	fileadapter "github.com/casbin/casbin/v2/persist/file-adapter"
	defaultrolemanager "github.com/casbin/casbin/v2/rbac/default-role-manager"
	"github.com/casbin/casbin/v2/util"
	"github.com/onsi/gomega"
)

func TestValidateRBACModel(t *testing.T) {
	g := gomega.NewWithT(t)

	a := fileadapter.NewAdapter("./testdata/policy.csv")
	e, err := casbin.NewEnforcer("./testdata/rbac_model.conf", a)
	g.Expect(err).To(gomega.Succeed())
	err = e.LoadPolicy()
	g.Expect(err).To(gomega.Succeed())
	e.GetRoleManager().(*defaultrolemanager.RoleManager).AddMatchingFunc("", util.KeyMatch2)
	e.AddNamedDomainMatchingFunc("g", "", util.KeyMatch)
	e.AddFunction("actMatch", ActingMatchFunc)
	e.AddFunction("domMatch", DomainMatchFunc)
	{
		res, err := e.Enforce("alice", "1", "cluster", "read")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeTrue())
	}
	{
		res, err := e.Enforce("alice", "2", "cluster", "read")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeTrue())
	}
	{
		res, err := e.Enforce("alice", "1", "cluster", "analyze")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeTrue())
	}
	{
		res, err := e.Enforce("alice", "2", "cluster", "analyze")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeTrue())
	}
	{
		res, err := e.Enforce("bob", "1", "cluster", "read")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeTrue())
	}
	{
		res, err := e.Enforce("bob", "1", "cluster", "write")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeTrue())
	}
	{
		res, err := e.Enforce("bob", "2", "cluster", "read")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeFalse())
	}
	{
		res, err := e.Enforce("bob", "1", "cluster", "analyze")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeTrue())
	}
	{
		res, err := e.Enforce("bob", "2", "cluster", "analyze")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeFalse())
	}
	{
		res, err := e.Enforce("foo", "1", "cluster", "analyze")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeFalse())
	}
	{
		res, err := e.Enforce("foo", "2", "cluster", "compute")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeFalse())
	}
}

func TestRBACGetRolesAfterDeleteRole(t *testing.T) {
	g := gomega.NewWithT(t)

	a := fileadapter.NewAdapter("./testdata/policy.csv")
	e, err := casbin.NewEnforcer("./testdata/rbac_model.conf", a)
	g.Expect(err).To(gomega.Succeed())
	err = e.LoadPolicy()
	g.Expect(err).To(gomega.Succeed())
	e.GetRoleManager().(*defaultrolemanager.RoleManager).AddMatchingFunc("", util.KeyMatch2)
	e.AddNamedDomainMatchingFunc("g", "", util.KeyMatch)
	e.AddFunction("actMatch", ActingMatchFunc)
	e.AddFunction("domMatch", DomainMatchFunc)

	roles, err := e.GetImplicitRolesForUser("alice", "1")
	g.Expect(err).To(gomega.Succeed())
	t.Log(roles)
	roles, err = e.GetImplicitRolesForUser("alice", "2")
	g.Expect(err).To(gomega.Succeed())
	t.Log(roles)

	ok, err := e.DeleteRoleForUserInDomain("alice", "role/pingcaper", "1")
	g.Expect(err).To(gomega.Succeed())
	t.Log(ok)
	roles, err = e.GetImplicitRolesForUser("alice", "1")
	g.Expect(err).To(gomega.Succeed())
	t.Log(roles)
	roles, err = e.GetImplicitRolesForUser("alice", "2")
	g.Expect(err).To(gomega.Succeed())
	t.Log(roles)
}

func TestRBACGetUsersUnderDomain(t *testing.T) {
	g := gomega.NewWithT(t)

	a := fileadapter.NewAdapter("./testdata/policy.csv")
	e, err := casbin.NewEnforcer("./testdata/rbac_model.conf", a)
	g.Expect(err).To(gomega.Succeed())
	err = e.LoadPolicy()
	g.Expect(err).To(gomega.Succeed())
	e.GetRoleManager().(*defaultrolemanager.RoleManager).AddMatchingFunc("", util.KeyMatch2)
	e.AddNamedDomainMatchingFunc("g", "", util.KeyMatch)
	e.AddFunction("actMatch", ActingMatchFunc)
	e.AddFunction("domMatch", DomainMatchFunc)

	users := e.GetAllUsersByDomain("2")
	t.Log(users)
}

func TestWithoutBuildRoleLinksAgain(t *testing.T) {
	g := gomega.NewWithT(t)

	a := fileadapter.NewAdapter("./testdata/casbin_rule.csv")
	e, err := casbin.NewEnforcer("./testdata/rbac_model.conf", a)
	g.Expect(err).To(gomega.Succeed())
	e.GetRoleManager().(*defaultrolemanager.RoleManager).AddMatchingFunc("", util.KeyMatch2)
	// e.AddNamedDomainMatchingFunc("g", "", DomainMatch)
	e.AddFunction("actMatch", ActingMatchFunc)
	e.AddFunction("domMatch", DomainMatchFunc)
	// make sure internal user has correct permission
	{
		res, err := e.Enforce("user/1", "1", "cluster", "read")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeTrue())
	}
	{
		res, err := e.Enforce("user/1", "2", "cluster", "analyze")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeTrue())
	}
	{
		res, err := e.Enforce("user/1", "2", "cluster", "write")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeFalse())
	}
	// make sure org admin has correct permission
	{
		res, err := e.Enforce("user/123", "8946", "cluster", "analyze")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeTrue())
	}
	{
		res, err := e.Enforce("user/123", "8946", "user", "write")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeTrue())
	}
	{
		res, err := e.Enforce("user/123", "8946", "tenant", "read")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeTrue())
	}
	{
		res, err := e.Enforce("user/143", "8980", "cluster", "analyze")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeTrue())
	}
	{
		res, err := e.Enforce("user/143", "8980", "user", "write")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeTrue())
	}
	{
		res, err := e.Enforce("user/143", "8980", "tenant", "read")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeTrue())
	}
	{
		res, err := e.Enforce("user/143", "2", "tenant", "read")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeFalse())
	}
	{
		res, err := e.Enforce("user/143", "2", "cluster", "read")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeFalse())
	}
	{
		res, err := e.Enforce("user/143", "2", "user", "read")
		g.Expect(err).To(gomega.Succeed())
		g.Expect(res).To(gomega.BeFalse())
	}
}

// Just for debug, not for testing
func TestRbacCheckRoles(t *testing.T) {
	g := gomega.NewWithT(t)

	a := fileadapter.NewAdapter("./testdata/policy2.csv")
	e, err := casbin.NewEnforcer("./testdata/rbac_model.conf", a)
	g.Expect(err).To(gomega.Succeed())
	e.GetRoleManager().(*defaultrolemanager.RoleManager).AddMatchingFunc("", util.KeyMatch2)
	e.AddFunction("actMatch", ActingMatchFunc)
	e.AddFunction("domMatch", DomainMatchFunc)
	// make sure internal user has correct permission
	{
		res, _ := e.Enforce("user/15", "15", "cluster", "read")
		t.Log("user/15", "15", "cluster", "read")
		t.Log(res)
	}
	{
		res, _ := e.Enforce("user/12", "10", "cluster", "read")
		t.Log("user/12", "10", "cluster", "read")
		t.Log(res)
	}
	{
		res, _ := e.Enforce("user/12", "11", "cluster", "read")
		t.Log("user/12", "11", "cluster", "read")
		t.Log(res)
	}
	{
		res, _ := e.Enforce("user/12", "12", "cluster", "read")
		t.Log("user/12", "12", "cluster", "read")
		t.Log(res)
	}
	{
		res, _ := e.Enforce("user/12", "13", "cluster", "read")
		t.Log("user/12", "13", "cluster", "read")
		t.Log(res)
	}
	{
		res, _ := e.Enforce("user/13", "11", "cluster", "read")
		t.Log("user/13", "11", "cluster", "read")
		t.Log(res)
	}
	{
		res, _ := e.Enforce("user/13", "12", "cluster", "read")
		t.Log("user/13", "12", "cluster", "read")
		t.Log(res)
	}
	{
		res, _ := e.Enforce("user/13", "13", "cluster", "read")
		t.Log("user/13", "13", "cluster", "read")
		t.Log(res)
	}
}
