package native

import (
	"context"
	"errors"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"
	"github.com/tech/sendico/pkg/auth/internal/native/nstructures"
	"github.com/tech/sendico/pkg/db/repository/builder"
	"github.com/tech/sendico/pkg/merrors"
	factory "github.com/tech/sendico/pkg/mlogger/factory"
	"github.com/tech/sendico/pkg/model"
	"go.mongodb.org/mongo-driver/v2/bson"
)

// Mock implementations for testing
type MockPoliciesDB struct {
	mock.Mock
}

func (m *MockPoliciesDB) PoliciesForPermissionAction(ctx context.Context, roleRef, permissionRef bson.ObjectID, action model.Action) ([]nstructures.PolicyAssignment, error) {
	args := m.Called(ctx, roleRef, permissionRef, action)
	return args.Get(0).([]nstructures.PolicyAssignment), args.Error(1)
}

func (m *MockPoliciesDB) PoliciesForRole(ctx context.Context, roleRef bson.ObjectID) ([]nstructures.PolicyAssignment, error) {
	args := m.Called(ctx, roleRef)
	return args.Get(0).([]nstructures.PolicyAssignment), args.Error(1)
}

func (m *MockPoliciesDB) PoliciesForRoles(ctx context.Context, roleRefs []bson.ObjectID, action model.Action) ([]nstructures.PolicyAssignment, error) {
	args := m.Called(ctx, roleRefs, action)
	return args.Get(0).([]nstructures.PolicyAssignment), args.Error(1)
}

func (m *MockPoliciesDB) Policies(ctx context.Context, object model.PermissionBoundStorable, action model.Action) ([]nstructures.PolicyAssignment, error) {
	args := m.Called(ctx, object, action)
	return args.Get(0).([]nstructures.PolicyAssignment), args.Error(1)
}

func (m *MockPoliciesDB) Remove(ctx context.Context, policy *model.RolePolicy) error {
	args := m.Called(ctx, policy)
	return args.Error(0)
}

// Template DB methods - implement as needed for testing
func (m *MockPoliciesDB) Create(ctx context.Context, assignment *nstructures.PolicyAssignment) error {
	args := m.Called(ctx, assignment)
	return args.Error(0)
}

func (m *MockPoliciesDB) Get(ctx context.Context, id bson.ObjectID, assignment *nstructures.PolicyAssignment) error {
	args := m.Called(ctx, id, assignment)
	return args.Error(0)
}

func (m *MockPoliciesDB) Update(ctx context.Context, assignment *nstructures.PolicyAssignment) error {
	args := m.Called(ctx, assignment)
	return args.Error(0)
}

func (m *MockPoliciesDB) Patch(ctx context.Context, objectRef bson.ObjectID, patch builder.Patch) error {
	args := m.Called(ctx, objectRef, patch)
	return args.Error(0)
}

func (m *MockPoliciesDB) Delete(ctx context.Context, id bson.ObjectID) error {
	args := m.Called(ctx, id)
	return args.Error(0)
}

func (m *MockPoliciesDB) DeleteMany(ctx context.Context, query builder.Query) error {
	args := m.Called(ctx, query)
	return args.Error(0)
}

func (m *MockPoliciesDB) ListPermissionBound(ctx context.Context, accountRef, organizationRef bson.ObjectID) ([]nstructures.PolicyAssignment, error) {
	args := m.Called(ctx, accountRef, organizationRef)
	return args.Get(0).([]nstructures.PolicyAssignment), args.Error(1)
}

func (m *MockPoliciesDB) ListIDs(ctx context.Context, query interface{}) ([]bson.ObjectID, error) {
	args := m.Called(ctx, query)
	return args.Get(0).([]bson.ObjectID), args.Error(1)
}

func (m *MockPoliciesDB) FindOne(ctx context.Context, query builder.Query, assignment *nstructures.PolicyAssignment) error {
	args := m.Called(ctx, query, assignment)
	return args.Error(0)
}

func (m *MockPoliciesDB) List(ctx context.Context, query builder.Query) ([]nstructures.PolicyAssignment, error) {
	args := m.Called(ctx, query)
	return args.Get(0).([]nstructures.PolicyAssignment), args.Error(1)
}

func (m *MockPoliciesDB) Name() string {
	return "mock_policies"
}

func (m *MockPoliciesDB) DeleteCascade(ctx context.Context, id bson.ObjectID) error {
	args := m.Called(ctx, id)
	return args.Error(0)
}

func (m *MockPoliciesDB) InsertMany(ctx context.Context, objects []*nstructures.PolicyAssignment) error {
	args := m.Called(ctx, objects)
	return args.Error(0)
}

type MockRolesDB struct {
	mock.Mock
}

func (m *MockRolesDB) Roles(ctx context.Context, accountRef, organizationRef bson.ObjectID) ([]nstructures.RoleAssignment, error) {
	args := m.Called(ctx, accountRef, organizationRef)
	return args.Get(0).([]nstructures.RoleAssignment), args.Error(1)
}

func (m *MockRolesDB) RolesForVenue(ctx context.Context, organizationRef bson.ObjectID) ([]nstructures.RoleAssignment, error) {
	args := m.Called(ctx, organizationRef)
	return args.Get(0).([]nstructures.RoleAssignment), args.Error(1)
}

func (m *MockRolesDB) RemoveRole(ctx context.Context, roleRef, organizationRef, accountRef bson.ObjectID) error {
	args := m.Called(ctx, roleRef, organizationRef, accountRef)
	return args.Error(0)
}

func (m *MockRolesDB) DeleteRole(ctx context.Context, roleRef bson.ObjectID) error {
	args := m.Called(ctx, roleRef)
	return args.Error(0)
}

// Template DB methods - implement as needed for testing
func (m *MockRolesDB) Create(ctx context.Context, assignment *nstructures.RoleAssignment) error {
	args := m.Called(ctx, assignment)
	return args.Error(0)
}

func (m *MockRolesDB) Get(ctx context.Context, id bson.ObjectID, assignment *nstructures.RoleAssignment) error {
	args := m.Called(ctx, id, assignment)
	return args.Error(0)
}

func (m *MockRolesDB) Update(ctx context.Context, assignment *nstructures.RoleAssignment) error {
	args := m.Called(ctx, assignment)
	return args.Error(0)
}

func (m *MockRolesDB) Patch(ctx context.Context, objectRef bson.ObjectID, patch builder.Patch) error {
	args := m.Called(ctx, objectRef, patch)
	return args.Error(0)
}

func (m *MockRolesDB) Delete(ctx context.Context, id bson.ObjectID) error {
	args := m.Called(ctx, id)
	return args.Error(0)
}

func (m *MockRolesDB) DeleteMany(ctx context.Context, query builder.Query) error {
	args := m.Called(ctx, query)
	return args.Error(0)
}

func (m *MockRolesDB) ListPermissionBound(ctx context.Context, accountRef, organizationRef bson.ObjectID) ([]nstructures.RoleAssignment, error) {
	args := m.Called(ctx, accountRef, organizationRef)
	return args.Get(0).([]nstructures.RoleAssignment), args.Error(1)
}

func (m *MockRolesDB) ListIDs(ctx context.Context, query interface{}) ([]bson.ObjectID, error) {
	args := m.Called(ctx, query)
	return args.Get(0).([]bson.ObjectID), args.Error(1)
}

func (m *MockRolesDB) FindOne(ctx context.Context, query builder.Query, assignment *nstructures.RoleAssignment) error {
	args := m.Called(ctx, query, assignment)
	return args.Error(0)
}

func (m *MockRolesDB) List(ctx context.Context, query builder.Query) ([]nstructures.RoleAssignment, error) {
	args := m.Called(ctx, query)
	return args.Get(0).([]nstructures.RoleAssignment), args.Error(1)
}

func (m *MockRolesDB) Name() string {
	return "mock_roles"
}

func (m *MockRolesDB) DeleteCascade(ctx context.Context, id bson.ObjectID) error {
	args := m.Called(ctx, id)
	return args.Error(0)
}

func (m *MockRolesDB) InsertMany(ctx context.Context, objects []*nstructures.RoleAssignment) error {
	args := m.Called(ctx, objects)
	return args.Error(0)
}

// Test helper functions
func createTestObjectID() bson.ObjectID {
	return bson.NewObjectID()
}

func createTestRoleAssignment(roleRef, accountRef, organizationRef bson.ObjectID) nstructures.RoleAssignment {
	return nstructures.RoleAssignment{
		Role: model.Role{
			AccountRef:      accountRef,
			DescriptionRef:  roleRef,
			OrganizationRef: organizationRef,
		},
	}
}

func createTestPolicyAssignment(roleRef bson.ObjectID, effect model.Effect, organizationRef, descriptionRef bson.ObjectID, objectRef *bson.ObjectID) nstructures.PolicyAssignment {
	return nstructures.PolicyAssignment{
		Policy: model.Policy{
			OrganizationRef: organizationRef,
			DescriptionRef:  descriptionRef,
			ObjectRef:       objectRef,
			Effect: model.ActionEffect{
				Action: model.ActionRead,
				Effect: effect,
			},
		},
		RoleRef: roleRef,
	}
}

func createTestEnforcer(pdb PoliciesDB, rdb RolesDB) *Enforcer {
	logger := factory.NewLogger(true)
	enforcer := &Enforcer{
		logger: logger.Named("test"),
		pdb:    pdb,
		rdb:    rdb,
	}
	return enforcer
}

func TestEnforcer_Enforce(t *testing.T) {
	ctx := context.Background()

	// Test data
	accountRef := createTestObjectID()
	organizationRef := createTestObjectID()
	permissionRef := createTestObjectID()
	objectRef := createTestObjectID()
	roleRef := createTestObjectID()

	t.Run("Allow_SingleRole_SinglePolicy", func(t *testing.T) {
		mockPDB := &MockPoliciesDB{}
		mockRDB := &MockRolesDB{}

		// Mock role assignment
		roleAssignment := createTestRoleAssignment(roleRef, accountRef, organizationRef)
		mockRDB.On("Roles", ctx, accountRef, organizationRef).Return([]nstructures.RoleAssignment{roleAssignment}, nil)

		// Mock policy assignment with ALLOW effect
		policyAssignment := createTestPolicyAssignment(roleRef, model.EffectAllow, organizationRef, permissionRef, &objectRef)
		mockPDB.On("PoliciesForPermissionAction", ctx, roleRef, permissionRef, model.ActionRead).Return([]nstructures.PolicyAssignment{policyAssignment}, nil)

		// Create enforcer
		enforcer := createTestEnforcer(mockPDB, mockRDB)

		// Execute
		allowed, err := enforcer.Enforce(ctx, permissionRef, accountRef, organizationRef, objectRef, model.ActionRead)

		// Verify
		require.NoError(t, err)
		assert.True(t, allowed)
		mockRDB.AssertExpectations(t)
		mockPDB.AssertExpectations(t)
	})

	t.Run("Deny_SingleRole_SinglePolicy", func(t *testing.T) {
		mockPDB := &MockPoliciesDB{}
		mockRDB := &MockRolesDB{}

		// Mock role assignment
		roleAssignment := createTestRoleAssignment(roleRef, accountRef, organizationRef)
		mockRDB.On("Roles", ctx, accountRef, organizationRef).Return([]nstructures.RoleAssignment{roleAssignment}, nil)

		// Mock policy assignment with DENY effect
		policyAssignment := createTestPolicyAssignment(roleRef, model.EffectDeny, organizationRef, permissionRef, &objectRef)
		mockPDB.On("PoliciesForPermissionAction", ctx, roleRef, permissionRef, model.ActionRead).Return([]nstructures.PolicyAssignment{policyAssignment}, nil)

		enforcer := createTestEnforcer(mockPDB, mockRDB)

		// Execute
		allowed, err := enforcer.Enforce(ctx, permissionRef, accountRef, organizationRef, objectRef, model.ActionRead)

		// Verify
		require.NoError(t, err)
		assert.False(t, allowed)
		mockRDB.AssertExpectations(t)
		mockPDB.AssertExpectations(t)
	})

	t.Run("DenyTakesPrecedence_MultipleRoles", func(t *testing.T) {
		mockPDB := &MockPoliciesDB{}
		mockRDB := &MockRolesDB{}

		role1Ref := createTestObjectID()
		role2Ref := createTestObjectID()

		// Mock multiple role assignments
		roleAssignment1 := createTestRoleAssignment(role1Ref, accountRef, organizationRef)
		roleAssignment2 := createTestRoleAssignment(role2Ref, accountRef, organizationRef)
		mockRDB.On("Roles", ctx, accountRef, organizationRef).Return([]nstructures.RoleAssignment{roleAssignment1, roleAssignment2}, nil)

		// First role has ALLOW policy
		allowPolicy := createTestPolicyAssignment(role1Ref, model.EffectAllow, organizationRef, permissionRef, &objectRef)
		mockPDB.On("PoliciesForPermissionAction", ctx, role1Ref, permissionRef, model.ActionRead).Return([]nstructures.PolicyAssignment{allowPolicy}, nil)

		// Second role has DENY policy - should take precedence
		denyPolicy := createTestPolicyAssignment(role2Ref, model.EffectDeny, organizationRef, permissionRef, &objectRef)
		mockPDB.On("PoliciesForPermissionAction", ctx, role2Ref, permissionRef, model.ActionRead).Return([]nstructures.PolicyAssignment{denyPolicy}, nil)

		enforcer := createTestEnforcer(mockPDB, mockRDB)

		// Execute
		allowed, err := enforcer.Enforce(ctx, permissionRef, accountRef, organizationRef, objectRef, model.ActionRead)

		// Verify - DENY should take precedence
		require.NoError(t, err)
		assert.False(t, allowed)
		mockRDB.AssertExpectations(t)
		mockPDB.AssertExpectations(t)
	})

	t.Run("NoRoles_ReturnsFalse", func(t *testing.T) {
		mockPDB := &MockPoliciesDB{}
		mockRDB := &MockRolesDB{}

		// Mock no roles found
		mockRDB.On("Roles", ctx, accountRef, organizationRef).Return([]nstructures.RoleAssignment{}, merrors.ErrNoData)

		enforcer := createTestEnforcer(mockPDB, mockRDB)

		// Execute
		allowed, err := enforcer.Enforce(ctx, permissionRef, accountRef, organizationRef, objectRef, model.ActionRead)

		// Verify
		require.NoError(t, err)
		assert.False(t, allowed)
		mockRDB.AssertExpectations(t)
	})

	t.Run("EmptyRoles_ReturnsError", func(t *testing.T) {
		mockPDB := &MockPoliciesDB{}
		mockRDB := &MockRolesDB{}

		// Mock empty roles list (not NoData error)
		mockRDB.On("Roles", ctx, accountRef, organizationRef).Return([]nstructures.RoleAssignment{}, nil)

		enforcer := createTestEnforcer(mockPDB, mockRDB)

		// Execute
		allowed, err := enforcer.Enforce(ctx, permissionRef, accountRef, organizationRef, objectRef, model.ActionRead)

		// Verify
		require.Error(t, err)
		assert.False(t, allowed)
		assert.Contains(t, err.Error(), "No roles found for account")
		mockRDB.AssertExpectations(t)
	})

	t.Run("DatabaseError_RolesDB", func(t *testing.T) {
		mockPDB := &MockPoliciesDB{}
		mockRDB := &MockRolesDB{}

		// Mock database error
		dbError := errors.New("database connection failed")
		mockRDB.On("Roles", ctx, accountRef, organizationRef).Return([]nstructures.RoleAssignment{}, dbError)

		enforcer := createTestEnforcer(mockPDB, mockRDB)

		// Execute
		allowed, err := enforcer.Enforce(ctx, permissionRef, accountRef, organizationRef, objectRef, model.ActionRead)

		// Verify
		require.Error(t, err)
		assert.False(t, allowed)
		assert.Equal(t, dbError, err)
		mockRDB.AssertExpectations(t)
	})

	t.Run("DatabaseError_PoliciesDB", func(t *testing.T) {
		mockPDB := &MockPoliciesDB{}
		mockRDB := &MockRolesDB{}

		// Mock role assignment
		roleAssignment := createTestRoleAssignment(roleRef, accountRef, organizationRef)
		mockRDB.On("Roles", ctx, accountRef, organizationRef).Return([]nstructures.RoleAssignment{roleAssignment}, nil)

		// Mock database error in policies
		dbError := errors.New("policies database error")
		mockPDB.On("PoliciesForPermissionAction", ctx, roleRef, permissionRef, model.ActionRead).Return([]nstructures.PolicyAssignment{}, dbError)

		enforcer := createTestEnforcer(mockPDB, mockRDB)

		// Execute
		allowed, err := enforcer.Enforce(ctx, permissionRef, accountRef, organizationRef, objectRef, model.ActionRead)

		// Verify
		require.Error(t, err)
		assert.False(t, allowed)
		assert.Equal(t, dbError, err)
		mockRDB.AssertExpectations(t)
		mockPDB.AssertExpectations(t)
	})

	t.Run("NoPolicies_ReturnsFalse", func(t *testing.T) {
		mockPDB := &MockPoliciesDB{}
		mockRDB := &MockRolesDB{}

		// Mock role assignment
		roleAssignment := createTestRoleAssignment(roleRef, accountRef, organizationRef)
		mockRDB.On("Roles", ctx, accountRef, organizationRef).Return([]nstructures.RoleAssignment{roleAssignment}, nil)

		// Mock no policies found
		mockPDB.On("PoliciesForPermissionAction", ctx, roleRef, permissionRef, model.ActionRead).Return([]nstructures.PolicyAssignment{}, merrors.ErrNoData)

		enforcer := createTestEnforcer(mockPDB, mockRDB)

		// Execute
		allowed, err := enforcer.Enforce(ctx, permissionRef, accountRef, organizationRef, objectRef, model.ActionRead)

		// Verify
		require.NoError(t, err)
		assert.False(t, allowed)
		mockRDB.AssertExpectations(t)
		mockPDB.AssertExpectations(t)
	})

	t.Run("CorruptedPolicy_ReturnsError", func(t *testing.T) {
		mockPDB := &MockPoliciesDB{}
		mockRDB := &MockRolesDB{}

		// Mock role assignment
		roleAssignment := createTestRoleAssignment(roleRef, accountRef, organizationRef)
		mockRDB.On("Roles", ctx, accountRef, organizationRef).Return([]nstructures.RoleAssignment{roleAssignment}, nil)

		// Mock corrupted policy with invalid effect
		corruptedPolicy := createTestPolicyAssignment(roleRef, "invalid_effect", organizationRef, permissionRef, &objectRef)
		mockPDB.On("PoliciesForPermissionAction", ctx, roleRef, permissionRef, model.ActionRead).Return([]nstructures.PolicyAssignment{corruptedPolicy}, nil)

		enforcer := createTestEnforcer(mockPDB, mockRDB)

		// Execute
		allowed, err := enforcer.Enforce(ctx, permissionRef, accountRef, organizationRef, objectRef, model.ActionRead)

		// Verify
		require.Error(t, err)
		assert.False(t, allowed)
		assert.Contains(t, err.Error(), "Corrupted action effect data")
		mockRDB.AssertExpectations(t)
		mockPDB.AssertExpectations(t)
	})
}

// Mock implementation for PermissionBoundStorable
type MockPermissionBoundStorable struct {
	id              bson.ObjectID
	permissionRef   bson.ObjectID
	organizationRef bson.ObjectID
}

func (m *MockPermissionBoundStorable) GetID() *bson.ObjectID {
	return &m.id
}

func (m *MockPermissionBoundStorable) GetPermissionRef() bson.ObjectID {
	return m.permissionRef
}

func (m *MockPermissionBoundStorable) GetOrganizationRef() bson.ObjectID {
	return m.organizationRef
}

func (m *MockPermissionBoundStorable) Collection() string {
	return "test_objects"
}

func (m *MockPermissionBoundStorable) SetID(objID bson.ObjectID) {
	m.id = objID
}

func (m *MockPermissionBoundStorable) Update() {
	// Do nothing for mock
}

func (m *MockPermissionBoundStorable) SetPermissionRef(permissionRef bson.ObjectID) {
	m.permissionRef = permissionRef
}

func (m *MockPermissionBoundStorable) SetOrganizationRef(organizationRef bson.ObjectID) {
	m.organizationRef = organizationRef
}

func (m *MockPermissionBoundStorable) IsArchived() bool {
	return false // Default to not archived for testing
}

func (m *MockPermissionBoundStorable) SetArchived(archived bool) {
	// No-op for testing
}

func TestEnforcer_EnforceBatch(t *testing.T) {
	ctx := context.Background()

	// Test data
	accountRef := createTestObjectID()
	organizationRef := createTestObjectID()
	permissionRef := createTestObjectID()
	roleRef := createTestObjectID()

	// Create test objects
	object1 := &MockPermissionBoundStorable{
		id:              createTestObjectID(),
		permissionRef:   permissionRef,
		organizationRef: organizationRef,
	}
	object2 := &MockPermissionBoundStorable{
		id:              createTestObjectID(),
		permissionRef:   permissionRef,
		organizationRef: organizationRef,
	}

	t.Run("BatchEnforce_MultipleObjects_SameVenue", func(t *testing.T) {
		mockPDB := &MockPoliciesDB{}
		mockRDB := &MockRolesDB{}

		// Mock role assignment
		roleAssignment := createTestRoleAssignment(roleRef, accountRef, organizationRef)
		mockRDB.On("Roles", ctx, accountRef, organizationRef).Return([]nstructures.RoleAssignment{roleAssignment}, nil)

		// Mock policy assignment with ALLOW effect
		policyAssignment := createTestPolicyAssignment(roleRef, model.EffectAllow, organizationRef, permissionRef, nil)
		mockPDB.On("PoliciesForRoles", ctx, []bson.ObjectID{roleRef}, model.ActionRead).Return([]nstructures.PolicyAssignment{policyAssignment}, nil)

		enforcer := createTestEnforcer(mockPDB, mockRDB)

		// Execute batch enforcement
		objects := []model.PermissionBoundStorable{object1, object2}
		results, err := enforcer.EnforceBatch(ctx, objects, accountRef, model.ActionRead)

		// Verify
		require.NoError(t, err)
		assert.Len(t, results, 2)
		assert.True(t, results[object1.id])
		assert.True(t, results[object2.id])
		mockRDB.AssertExpectations(t)
		mockPDB.AssertExpectations(t)
	})

	t.Run("BatchEnforce_NoRoles_AllObjectsDenied", func(t *testing.T) {
		mockPDB := &MockPoliciesDB{}
		mockRDB := &MockRolesDB{}

		// Mock no roles found
		mockRDB.On("Roles", ctx, accountRef, organizationRef).Return([]nstructures.RoleAssignment{}, merrors.ErrNoData)

		enforcer := createTestEnforcer(mockPDB, mockRDB)

		// Execute batch enforcement
		objects := []model.PermissionBoundStorable{object1, object2}
		results, err := enforcer.EnforceBatch(ctx, objects, accountRef, model.ActionRead)

		// Verify
		require.NoError(t, err)
		assert.Len(t, results, 2)
		assert.False(t, results[object1.id])
		assert.False(t, results[object2.id])
		mockRDB.AssertExpectations(t)
	})

	t.Run("BatchEnforce_DatabaseError", func(t *testing.T) {
		mockPDB := &MockPoliciesDB{}
		mockRDB := &MockRolesDB{}

		// Mock database error
		dbError := errors.New("database connection failed")
		mockRDB.On("Roles", ctx, accountRef, organizationRef).Return([]nstructures.RoleAssignment{}, dbError)

		enforcer := createTestEnforcer(mockPDB, mockRDB)

		// Execute batch enforcement
		objects := []model.PermissionBoundStorable{object1, object2}
		results, err := enforcer.EnforceBatch(ctx, objects, accountRef, model.ActionRead)

		// Verify
		require.Error(t, err)
		assert.Nil(t, results)
		assert.Equal(t, dbError, err)
		mockRDB.AssertExpectations(t)
	})
}

func TestEnforcer_GetRoles(t *testing.T) {
	ctx := context.Background()

	// Test data
	accountRef := createTestObjectID()
	organizationRef := createTestObjectID()
	roleRef := createTestObjectID()

	t.Run("GetRoles_Success", func(t *testing.T) {
		mockPDB := &MockPoliciesDB{}
		mockRDB := &MockRolesDB{}

		// Mock role assignment
		roleAssignment := createTestRoleAssignment(roleRef, accountRef, organizationRef)
		mockRDB.On("Roles", ctx, accountRef, organizationRef).Return([]nstructures.RoleAssignment{roleAssignment}, nil)

		enforcer := createTestEnforcer(mockPDB, mockRDB)

		// Execute
		roles, err := enforcer.GetRoles(ctx, accountRef, organizationRef)

		// Verify
		require.NoError(t, err)
		assert.Len(t, roles, 1)
		assert.Equal(t, roleRef, roles[0].DescriptionRef)
		mockRDB.AssertExpectations(t)
	})

	t.Run("GetRoles_NoRoles", func(t *testing.T) {
		mockPDB := &MockPoliciesDB{}
		mockRDB := &MockRolesDB{}

		// Mock no roles found
		mockRDB.On("Roles", ctx, accountRef, organizationRef).Return([]nstructures.RoleAssignment{}, merrors.ErrNoData)

		enforcer := createTestEnforcer(mockPDB, mockRDB)

		// Execute
		roles, err := enforcer.GetRoles(ctx, accountRef, organizationRef)

		// Verify
		require.NoError(t, err)
		assert.Len(t, roles, 0)
		mockRDB.AssertExpectations(t)
	})
}

func TestEnforcer_GetPermissions(t *testing.T) {
	ctx := context.Background()

	// Test data
	accountRef := createTestObjectID()
	organizationRef := createTestObjectID()
	roleRef := createTestObjectID()

	t.Run("GetPermissions_Success", func(t *testing.T) {
		mockPDB := &MockPoliciesDB{}
		mockRDB := &MockRolesDB{}

		// Mock role assignment
		roleAssignment := createTestRoleAssignment(roleRef, accountRef, organizationRef)
		mockRDB.On("Roles", ctx, accountRef, organizationRef).Return([]nstructures.RoleAssignment{roleAssignment}, nil)

		// Mock policy assignment
		policyAssignment := createTestPolicyAssignment(roleRef, model.EffectAllow, organizationRef, createTestObjectID(), nil)
		mockPDB.On("PoliciesForRole", ctx, roleRef).Return([]nstructures.PolicyAssignment{policyAssignment}, nil)

		enforcer := createTestEnforcer(mockPDB, mockRDB)

		// Execute
		roles, permissions, err := enforcer.GetPermissions(ctx, accountRef, organizationRef)

		// Verify
		require.NoError(t, err)
		assert.Len(t, roles, 1)
		assert.Len(t, permissions, 1)
		assert.Equal(t, accountRef, permissions[0].AccountRef)
		mockRDB.AssertExpectations(t)
		mockPDB.AssertExpectations(t)
	})
}

// Security-focused test scenarios
func TestEnforcer_SecurityScenarios(t *testing.T) {
	ctx := context.Background()

	// Test data
	accountRef := createTestObjectID()
	organizationRef := createTestObjectID()
	permissionRef := createTestObjectID()
	objectRef := createTestObjectID()
	roleRef := createTestObjectID()

	t.Run("Security_DenyAlwaysWins", func(t *testing.T) {
		mockPDB := &MockPoliciesDB{}
		mockRDB := &MockRolesDB{}

		// Mock role assignment
		roleAssignment := createTestRoleAssignment(roleRef, accountRef, organizationRef)
		mockRDB.On("Roles", ctx, accountRef, organizationRef).Return([]nstructures.RoleAssignment{roleAssignment}, nil)

		// Mock multiple policies: both ALLOW and DENY
		allowPolicy := createTestPolicyAssignment(roleRef, model.EffectAllow, organizationRef, permissionRef, &objectRef)
		denyPolicy := createTestPolicyAssignment(roleRef, model.EffectDeny, organizationRef, permissionRef, &objectRef)
		mockPDB.On("PoliciesForPermissionAction", ctx, roleRef, permissionRef, model.ActionRead).Return([]nstructures.PolicyAssignment{allowPolicy, denyPolicy}, nil)

		enforcer := createTestEnforcer(mockPDB, mockRDB)

		// Execute
		allowed, err := enforcer.Enforce(ctx, permissionRef, accountRef, organizationRef, objectRef, model.ActionRead)

		// Verify - DENY should always win
		require.NoError(t, err)
		assert.False(t, allowed)
		mockRDB.AssertExpectations(t)
		mockPDB.AssertExpectations(t)
	})

	t.Run("Security_InvalidObjectID", func(t *testing.T) {
		mockPDB := &MockPoliciesDB{}
		mockRDB := &MockRolesDB{}

		// Mock database error for invalid ObjectID
		dbError := errors.New("invalid ObjectID")
		mockRDB.On("Roles", ctx, accountRef, organizationRef).Return([]nstructures.RoleAssignment{}, dbError)

		enforcer := createTestEnforcer(mockPDB, mockRDB)

		// Execute with invalid ObjectID
		allowed, err := enforcer.Enforce(ctx, permissionRef, accountRef, organizationRef, objectRef, model.ActionRead)

		// Verify - should fail securely
		require.Error(t, err)
		assert.False(t, allowed)
		mockRDB.AssertExpectations(t)
	})
}

// Note: This test provides comprehensive coverage of the native enforcer including:
// 1. Basic enforcement logic with deny-takes-precedence
// 2. Batch operations for performance
// 3. Role and permission retrieval
// 4. Security scenarios and edge cases
// 5. Error handling and database failures
// 6. All critical security paths are tested
