package rbac_test

import (
	"testing"

	"github.com/bluesky-social/indigo/atproto/syntax"
	_ "github.com/mattn/go-sqlite3"
	"github.com/stretchr/testify/assert"
	"tangled.org/core/rbac/v2"
)

func setup(t *testing.T) *rbac.Enforcer {
	enforcer, err := rbac.NewEnforcer(":memory:")
	assert.NoError(t, err)

	return enforcer
}

func TestRepoOwnerPermissions(t *testing.T) {
	var (
		e       = setup(t)
		ok      bool
		err     error
		fooRepo = syntax.DID("did:example:coolrepo")
		fooUser = syntax.DID("did:plc:foo")
	)

	assert.NoError(t, e.SetRepoOwner(fooUser, fooRepo))

	ok, err = e.IsRepoOwner(fooUser, fooRepo)
	assert.NoError(t, err)
	assert.True(t, ok, "repo author should be repo owner")

	ok, err = e.IsRepoCollaborator(fooUser, fooRepo)
	assert.NoError(t, err)
	assert.True(t, ok, "repo owner should inherit role role:collaborator")

	ok, err = e.IsRepoSecretsAllowed(fooUser, fooRepo)
	assert.NoError(t, err)
	assert.True(t, ok, "repo owner should inherit collaborator permissions")
}

func TestRepoTeardown(t *testing.T) {
	var (
		e       = setup(t)
		ok      bool
		err     error
		fooRepo = syntax.DID("did:example:coolrepo")
		fooUser = syntax.DID("did:example:foo")
		barUser = syntax.DID("did:example:bar")
	)

	assert.NoError(t, e.SetRepoOwner(fooUser, fooRepo))
	assert.NoError(t, e.AddRepoCollaborator(barUser, fooRepo))

	ok, err = e.IsRepoOwner(fooUser, fooRepo)
	assert.NoError(t, err)
	assert.True(t, ok, "repo author should be repo owner")

	ok, err = e.IsRepoOwner(barUser, fooRepo)
	assert.NoError(t, err)
	assert.False(t, ok, "repo collaborator should not be repo owner")

	ok, err = e.IsRepoCollaborator(barUser, fooRepo)
	assert.NoError(t, err)
	assert.True(t, ok, "repo collaborator should be repo collaborator")

	assert.NoError(t, e.DeleteRepo(fooRepo))

	ok, err = e.IsRepoOwner(barUser, fooRepo)
	assert.NoError(t, err)
	assert.False(t, ok, "repo owner permission should be deleted after repo deletion")

	ok, err = e.IsRepoCollaborator(barUser, fooRepo)
	assert.NoError(t, err)
	assert.False(t, ok, "repo collaborator permission should be deleted after repo deletion")
}

func TestRepoCollaboratorPermissions(t *testing.T) {
	var (
		e       = setup(t)
		ok      bool
		err     error
		fooRepo = syntax.DID("did:example:coolrepo")
		fooUser = syntax.DID("did:plc:foo")
		barUser = syntax.DID("did:plc:bar")
	)

	assert.NoError(t, e.SetRepoOwner(fooUser, fooRepo))
	assert.NoError(t, e.AddRepoCollaborator(barUser, fooRepo))

	ok, err = e.IsRepoCollaborator(barUser, fooRepo)
	assert.NoError(t, err)
	assert.True(t, ok, "should set repo collaborator")

	ok, err = e.IsRepoSecretsAllowed(barUser, fooRepo)
	assert.NoError(t, err)
	assert.True(t, ok, "repo collaborator should be able to edit repo settings")
}

func TestGetByRole(t *testing.T) {
	var (
		e             = setup(t)
		err           error
		fooRepo       = syntax.DID("did:example:coolrepo")
		owner         = syntax.DID("did:plc:foo")
		collaborator1 = syntax.DID("did:plc:bar")
		collaborator2 = syntax.DID("did:plc:baz")
	)

	assert.NoError(t, e.SetRepoOwner(owner, fooRepo))
	assert.NoError(t, e.AddRepoCollaborator(collaborator1, fooRepo))
	assert.NoError(t, e.AddRepoCollaborator(collaborator2, fooRepo))

	collaborators, err := e.GetRepoCollaborators(fooRepo)
	assert.NoError(t, err)
	assert.ElementsMatch(t, []syntax.DID{
		owner,
		collaborator1,
		collaborator2,
	}, collaborators)
}
