package permissions

import (
	"bytes"
	"context"
	"fmt"
	"strings"
	"sync"
	"testing"

	"github.com/nexuscrm/kernel/pkg/schemacatalog"
	"github.com/nexuscrm/shared/pkg/models"
	cp "github.com/pingcap-inc/nexuscrm-contract/pkg/controlplane"
)

func TestAssignmentPolicyLifecycleRequiresEligibilityProjectionProvider(t *testing.T) {
	_, lifecycle, err := NewPermissionSetAssignmentPolicyManagedLifecycleRegistrationWithEligibility(nil)
	if err != nil {
		t.Fatal(err)
	}
	request := cp.NewComponentManagedItemLifecycleRequest(assignmentPolicyManagedRequest(t))
	_, err = lifecycle.Lifecycle().Plan(
		context.Background(), cp.ComponentManagedScopeItem, request, assignmentPolicyLifecycleStore(),
	)
	if err == nil || !containsAll(err.Error(), "assignment policy", "eligibility", "provider", "required") {
		t.Fatalf("missing eligibility provider error = %v", err)
	}
	for _, surface := range lifecycle.ReadSet() {
		if surface.Table == "Profile" || surface.Table == "User" {
			t.Fatalf("dark L0 registration leaked product read surface %#v", surface)
		}
	}
}

func TestCatalogAssignmentPolicyEligibilityProjectsNeutralAliasedSources(t *testing.T) {
	provider, err := NewCatalogAssignmentPolicyEligibilityProjectionProvider([]*models.ObjectMetadata{
		{
			APIName: "Workspace",
			AccessPolicy: &models.ObjectAccessPolicy{Lifecycle: &models.RecordLifecycleAccessPolicy{
				AssignmentPolicyEligibility: &models.AssignmentPolicyEligibilityLifecyclePolicy{
					Role: models.AssignmentPolicyEligibilitySelectorAuthority,
					EnabledWhen: []models.AssignmentPolicyEligibilityBoolCondition{
						{Field: "Enabled", Equals: true, ResolvedColumn: "is_enabled"},
					},
					Selector: models.AssignmentPolicyEligibilitySelector{
						Field: "Label", ResolvedFieldColumn: "display_name",
					},
					ResolvedSourceTable:    "workspace_rows",
					ResolvedSourceIDColumn: "workspace_id",
				},
			}},
		},
		{
			APIName: "Member",
			AccessPolicy: &models.ObjectAccessPolicy{Lifecycle: &models.RecordLifecycleAccessPolicy{
				AssignmentPolicyEligibility: &models.AssignmentPolicyEligibilityLifecyclePolicy{
					Role:           models.AssignmentPolicyEligibilitySubjectPopulation,
					SubjectIDField: "MemberKey",
					EnabledWhen: []models.AssignmentPolicyEligibilityBoolCondition{
						{Field: "Enabled", Equals: true, ResolvedColumn: "can_receive"},
					},
					Selector: models.AssignmentPolicyEligibilitySelector{Reference: &models.AssignmentPolicyEligibilityReferenceSelector{
						SourceField: "Workspace", TargetObject: "Workspace", TargetField: "Label",
						ResolvedSourceFieldColumn: "workspace_fk", ResolvedTargetTable: "workspace_rows",
						ResolvedTargetIDColumn: "workspace_id", ResolvedTargetFieldColumn: "display_name",
					}},
					ResolvedSourceTable:     "member_rows",
					ResolvedSourceIDColumn:  "row_id",
					ResolvedSubjectIDColumn: "member_key",
				},
			}},
		},
	})
	if err != nil {
		t.Fatal(err)
	}
	store := newPermissionSetDefinitionLifecycleMemoryStore()
	store.rows["workspace_rows"] = []cp.ComponentRow{
		{"workspace_id": "workspace-1", "display_name": "Blue", "is_enabled": true},
	}
	store.rows["member_rows"] = []cp.ComponentRow{
		{"row_id": "row-2", "member_key": "subject-b", "workspace_fk": "workspace-1", "can_receive": true},
		{"row_id": "row-1", "member_key": "subject-a", "workspace_fk": "workspace-1", "can_receive": true},
		{"row_id": "row-3", "member_key": "subject-c", "workspace_fk": "workspace-1", "can_receive": false},
	}
	projection, err := provider.ProjectAssignmentPolicyEligibility(t.Context(), store, []string{"Blue"})
	if err != nil {
		t.Fatal(err)
	}
	if projection.Resolution != AssignmentPolicyEligibilityResolved ||
		strings.Join(projection.SubjectIDs, ",") != "subject-a,subject-b" {
		t.Fatalf("neutral aliased eligibility projection = %#v", projection)
	}
	surfaces := provider.AssignmentPolicyEligibilityReadSurfaces()
	if len(surfaces) != 2 || surfaces[0].Table != "member_rows" || surfaces[1].Table != "workspace_rows" {
		t.Fatalf("neutral aliased read surfaces = %#v", surfaces)
	}
}

func TestCatalogAssignmentPolicyEligibilityIsAbsentForCleanApp(t *testing.T) {
	provider, err := NewCatalogAssignmentPolicyEligibilityProjectionProvider([]*models.ObjectMetadata{{APIName: "Document"}})
	if err != nil {
		t.Fatal(err)
	}
	if provider != nil {
		t.Fatalf("clean app eligibility provider = %#v, want nil", provider)
	}
}

func TestAssignmentPolicyLifecycleRejectsTypedNilEligibilityProjectionProvider(t *testing.T) {
	var provider *assignmentPolicyTestEligibilityProjectionProvider
	_, lifecycle, err := NewPermissionSetAssignmentPolicyManagedLifecycleRegistrationWithEligibility(provider)
	if err != nil {
		t.Fatal(err)
	}
	request := cp.NewComponentManagedItemLifecycleRequest(assignmentPolicyManagedRequest(t))
	_, err = lifecycle.Lifecycle().Plan(
		context.Background(), cp.ComponentManagedScopeItem, request, assignmentPolicyLifecycleStore(),
	)
	if err == nil || !containsAll(err.Error(), "eligibility", "provider", "required") {
		t.Fatalf("typed-nil eligibility provider error = %v", err)
	}
}

func TestAssignmentPolicyLifecycleEligibilityProjectionIsReadOnlyAfterTargetLock(t *testing.T) {
	store := assignmentPolicyLifecycleStore()
	provider := &assignmentPolicyTestEligibilityProjectionProvider{
		store:      store,
		subjectIDs: []string{"user-sales"},
	}
	_, lifecycle, err := NewPermissionSetAssignmentPolicyManagedLifecycleRegistrationWithEligibility(provider)
	if err != nil {
		t.Fatal(err)
	}
	request := cp.NewComponentManagedItemLifecycleRequest(assignmentPolicyManagedRequest(t))
	plan, err := lifecycle.Lifecycle().Plan(
		context.Background(), cp.ComponentManagedScopeItem, request, store,
	)
	if err != nil {
		t.Fatal(err)
	}
	provider.requireTargetLock = true
	provider.calls = 0
	store.locks = nil
	guard := &assignmentPolicyOperationNoSourceLockStore{
		permissionSetDefinitionLifecycleMemoryStore: store,
	}
	if _, err := lifecycle.Lifecycle().Mutate(
		context.Background(), cp.ComponentManagedScopeItem, request, plan, guard,
	); err != nil {
		t.Fatal(err)
	}
	if provider.calls == 0 {
		t.Fatal("eligibility projection provider was not consulted after target locking")
	}
}

func TestAssignmentPolicyOperationEligibilityProjectionRunsAfterTargetStateLocks(t *testing.T) {
	store := assignmentPolicyLifecycleStore()
	provider := &assignmentPolicyTestEligibilityProjectionProvider{
		store:      store,
		subjectIDs: []string{"user-sales"},
	}
	_, lifecycle, err := NewPermissionSetAssignmentPolicyManagedLifecycleRegistrationWithEligibility(provider)
	if err != nil {
		t.Fatal(err)
	}
	item := cp.NewComponentManagedItemLifecycleRequest(assignmentPolicyManagedRequest(t))
	plan, err := lifecycle.Lifecycle().Plan(
		context.Background(), cp.ComponentManagedScopeItem, item, store,
	)
	if err != nil {
		t.Fatal(err)
	}
	if _, err := lifecycle.Lifecycle().Mutate(
		context.Background(), cp.ComponentManagedScopeItem, item, plan, store,
	); err != nil {
		t.Fatal(err)
	}

	operationPlan, err := PlanAssignmentPolicyOperationWithEligibility(
		context.Background(),
		store,
		AssignmentPolicyOperationRequest{
			PermissionSet: "Sales_User",
			Operation:     AssignmentPolicyOperationSuspend,
			Actor:         "operator",
			Reason:        "incident",
		},
		provider,
	)
	if err != nil {
		t.Fatal(err)
	}
	provider.requireTargetLock = true
	provider.requireTargetStateLocks = true
	provider.calls = 0
	store.locks = nil
	guard := &assignmentPolicyOperationNoSourceLockStore{
		permissionSetDefinitionLifecycleMemoryStore: store,
	}
	operation := PermissionSetAssignmentPolicyTransactionOperationProviderWithEligibility(provider)
	if _, err := operation.Mutate(context.Background(), operationPlan, guard); err != nil {
		t.Fatal(err)
	}
	if provider.calls != 1 {
		t.Fatalf("locked operation eligibility projection calls = %d, want 1", provider.calls)
	}
}

func TestAssignmentPolicyLifecycleUnicodeSubjectOrderConverges(t *testing.T) {
	store := assignmentPolicyLifecycleStore()
	provider := &assignmentPolicyTestEligibilityProjectionProvider{
		store:      store,
		subjectIDs: []string{"z", "ä"},
	}
	_, registration, err :=
		NewPermissionSetAssignmentPolicyManagedLifecycleRegistrationWithEligibility(provider)
	if err != nil {
		t.Fatal(err)
	}
	lifecycle := registration.Lifecycle()
	request := cp.NewComponentManagedItemLifecycleRequest(assignmentPolicyManagedRequest(t))
	plan, err := lifecycle.Plan(
		context.Background(), cp.ComponentManagedScopeItem, request, store,
	)
	if err != nil {
		t.Fatal(err)
	}
	if _, err := lifecycle.Mutate(
		context.Background(), cp.ComponentManagedScopeItem, request, plan, store,
	); err != nil {
		t.Fatal(err)
	}
	projection, err := lifecycle.Project(
		context.Background(), cp.ComponentManagedScopeItem, request, store,
	)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(projection.Expected, projection.Live) {
		t.Fatalf(
			"Unicode subject ordering did not converge:\nexpected=%s\nlive=%s",
			projection.Expected,
			projection.Live,
		)
	}
}

func TestAssignmentPolicyLifecycleRetainsCollationEquivalentSubject(t *testing.T) {
	store := assignmentPolicyLifecycleStore()
	provider := &assignmentPolicyTestEligibilityProjectionProvider{
		store:      store,
		subjectIDs: []string{"café"},
	}
	_, registration, err :=
		NewPermissionSetAssignmentPolicyManagedLifecycleRegistrationWithEligibility(provider)
	if err != nil {
		t.Fatal(err)
	}
	lifecycle := registration.Lifecycle()
	request := cp.NewComponentManagedItemLifecycleRequest(assignmentPolicyManagedRequest(t))
	initialPlan, err := lifecycle.Plan(
		context.Background(), cp.ComponentManagedScopeItem, request, store,
	)
	if err != nil {
		t.Fatal(err)
	}
	if _, err := lifecycle.Mutate(
		context.Background(), cp.ComponentManagedScopeItem, request, initialPlan, store,
	); err != nil {
		t.Fatal(err)
	}

	provider.subjectIDs = []string{"cafe"}
	plan, err := lifecycle.Plan(
		context.Background(), cp.ComponentManagedScopeItem, request, store,
	)
	if err != nil {
		t.Fatal(err)
	}
	result, err := lifecycle.Mutate(
		context.Background(), cp.ComponentManagedScopeItem, request, plan, store,
	)
	if err != nil {
		t.Fatal(err)
	}
	if result.Disposition != cp.ComponentManagedMutationNoChange {
		t.Fatalf("collation-equivalent subject disposition = %q", result.Disposition)
	}
	projection, err := lifecycle.Project(
		context.Background(), cp.ComponentManagedScopeItem, request, store,
	)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(projection.Expected, projection.Live) {
		t.Fatalf(
			"collation-equivalent subject did not converge:\nexpected=%s\nlive=%s",
			projection.Expected,
			projection.Live,
		)
	}
}

func TestAssignmentPolicyOperationAcceptsCanonicalUnicodeSubjectOrder(t *testing.T) {
	store := assignmentPolicyLifecycleStore()
	provider := &assignmentPolicyTestEligibilityProjectionProvider{
		store:      store,
		subjectIDs: []string{"z", "ä"},
	}
	_, registration, err :=
		NewPermissionSetAssignmentPolicyManagedLifecycleRegistrationWithEligibility(provider)
	if err != nil {
		t.Fatal(err)
	}
	lifecycle := registration.Lifecycle()
	request := cp.NewComponentManagedItemLifecycleRequest(assignmentPolicyManagedRequest(t))
	lifecyclePlan, err := lifecycle.Plan(
		context.Background(), cp.ComponentManagedScopeItem, request, store,
	)
	if err != nil {
		t.Fatal(err)
	}
	if _, err := lifecycle.Mutate(
		context.Background(), cp.ComponentManagedScopeItem, request, lifecyclePlan, store,
	); err != nil {
		t.Fatal(err)
	}

	operationPlan, err := PlanAssignmentPolicyOperationWithEligibility(
		context.Background(),
		store,
		AssignmentPolicyOperationRequest{
			PermissionSet: "Sales_User",
			Operation:     AssignmentPolicyOperationReconcile,
		},
		provider,
	)
	if err != nil {
		t.Fatal(err)
	}
	operation := PermissionSetAssignmentPolicyTransactionOperationProviderWithEligibility(provider)
	if _, err := operation.Mutate(context.Background(), operationPlan, store); err != nil {
		t.Fatal(err)
	}
	projection, err := operation.Project(context.Background(), operationPlan, store)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(projection.Expected, projection.Live) {
		t.Fatalf(
			"Unicode operation projection did not converge:\nexpected=%s\nlive=%s",
			projection.Expected,
			projection.Live,
		)
	}
}

func TestAssignmentPolicyOperationRetainsCollationEquivalentSubject(t *testing.T) {
	store := assignmentPolicyLifecycleStore()
	provider := &assignmentPolicyTestEligibilityProjectionProvider{
		store:      store,
		subjectIDs: []string{"café"},
	}
	_, registration, err :=
		NewPermissionSetAssignmentPolicyManagedLifecycleRegistrationWithEligibility(provider)
	if err != nil {
		t.Fatal(err)
	}
	lifecycle := registration.Lifecycle()
	request := cp.NewComponentManagedItemLifecycleRequest(assignmentPolicyManagedRequest(t))
	lifecyclePlan, err := lifecycle.Plan(
		context.Background(), cp.ComponentManagedScopeItem, request, store,
	)
	if err != nil {
		t.Fatal(err)
	}
	if _, err := lifecycle.Mutate(
		context.Background(), cp.ComponentManagedScopeItem, request, lifecyclePlan, store,
	); err != nil {
		t.Fatal(err)
	}

	provider.subjectIDs = []string{"cafe"}
	operationPlan, err := PlanAssignmentPolicyOperationWithEligibility(
		context.Background(),
		store,
		AssignmentPolicyOperationRequest{
			PermissionSet: "Sales_User",
			Operation:     AssignmentPolicyOperationReconcile,
		},
		provider,
	)
	if err != nil {
		t.Fatal(err)
	}
	operation := PermissionSetAssignmentPolicyTransactionOperationProviderWithEligibility(provider)
	result, err := operation.Mutate(context.Background(), operationPlan, store)
	if err != nil {
		t.Fatal(err)
	}
	if result.Disposition != cp.ComponentManagedMutationNoChange {
		t.Fatalf("collation-equivalent operation disposition = %q", result.Disposition)
	}
	projection, err := operation.Project(context.Background(), operationPlan, store)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(projection.Expected, projection.Live) {
		t.Fatalf(
			"collation-equivalent operation did not converge:\nexpected=%s\nlive=%s",
			projection.Expected,
			projection.Live,
		)
	}
}

func TestAssignmentPolicyLifecycleRejectsConcurrentEligibilityReadsOverBudget(t *testing.T) {
	const (
		workers     = 32
		rowsPerRead = 1600
	)
	store := &assignmentPolicyConcurrentEligibilityReadStore{
		permissionSetDefinitionLifecycleMemoryStore: assignmentPolicyLifecycleStore(),
		rowsPerRead: rowsPerRead,
	}
	provider := assignmentPolicyConcurrentBudgetProjectionProvider{
		workers: workers,
	}
	_, registration, err :=
		NewPermissionSetAssignmentPolicyManagedLifecycleRegistrationWithEligibility(provider)
	if err != nil {
		t.Fatal(err)
	}
	request := cp.NewComponentManagedItemLifecycleRequest(assignmentPolicyManagedRequest(t))
	_, err = registration.Lifecycle().Plan(
		context.Background(), cp.ComponentManagedScopeItem, request, store,
	)
	if err == nil || !containsAll(
		err.Error(),
		"assignment policy",
		"eligibility",
		"items",
		"exceed maximum",
	) {
		t.Fatalf("concurrent over-budget eligibility error = %v", err)
	}
}

func TestAssignmentPolicyLifecycleSharesEligibilityBudgetAcrossProjectionPasses(t *testing.T) {
	store := &assignmentPolicyCumulativeEligibilityReadStore{
		permissionSetDefinitionLifecycleMemoryStore: assignmentPolicyLifecycleStore(),
	}
	provider := &assignmentPolicyCumulativeBudgetProjectionProvider{}
	_, registration, err :=
		NewPermissionSetAssignmentPolicyManagedLifecycleRegistrationWithEligibility(provider)
	if err != nil {
		t.Fatal(err)
	}
	lifecycle := registration.Lifecycle()
	request := cp.NewComponentManagedItemLifecycleRequest(assignmentPolicyManagedRequest(t))
	plan, err := lifecycle.Plan(
		context.Background(), cp.ComponentManagedScopeItem, request, store,
	)
	if err != nil {
		t.Fatal(err)
	}
	if _, err := lifecycle.Mutate(
		context.Background(), cp.ComponentManagedScopeItem, request, plan, store,
	); err != nil {
		t.Fatal(err)
	}

	provider.rowsPerProjection = 30000
	_, err = lifecycle.Project(
		context.Background(), cp.ComponentManagedScopeItem, request, store,
	)
	if err == nil || !containsAll(err.Error(), "eligibility", "maximum", "20000") {
		t.Fatalf("cumulative eligibility budget error = %v", err)
	}
	if store.visibleRows > assignmentPolicyManagedBudget().MaxCurrentItems {
		t.Fatalf(
			"eligibility provider observed %d rows, maximum is %d",
			store.visibleRows,
			assignmentPolicyManagedBudget().MaxCurrentItems,
		)
	}
}

func TestAssignmentPolicyEligibilityValidatesSubjectCharacterWidthAgainstAssigneeColumn(t *testing.T) {
	store := assignmentPolicyLifecycleStore()
	provider := &assignmentPolicyTestEligibilityProjectionProvider{store: store}
	_, registration, err :=
		NewPermissionSetAssignmentPolicyManagedLifecycleRegistrationWithEligibility(provider)
	if err != nil {
		t.Fatal(err)
	}
	request := cp.NewComponentManagedItemLifecycleRequest(assignmentPolicyManagedRequest(t))
	for _, test := range []struct {
		name         string
		subjectID    string
		wantErrParts []string
	}{
		{name: "255 ASCII characters", subjectID: strings.Repeat("u", 255)},
		{
			name:         "256 ASCII characters",
			subjectID:    strings.Repeat("u", 256),
			wantErrParts: []string{"eligibility", "subject ID", "exceeds 255 characters", "AssigneeId"},
		},
		{name: "255 four-byte characters", subjectID: strings.Repeat("😀", 255)},
		{
			name:         "256 four-byte characters",
			subjectID:    strings.Repeat("😀", 256),
			wantErrParts: []string{"eligibility", "subject ID", "exceeds 255 characters", "AssigneeId"},
		},
		{
			name:         "invalid UTF-8",
			subjectID:    string([]byte{0xff}),
			wantErrParts: []string{"eligibility", "subject ID", "valid UTF-8"},
		},
	} {
		t.Run(test.name, func(t *testing.T) {
			provider.subjectIDs = []string{test.subjectID}
			_, err := registration.Lifecycle().Plan(
				context.Background(), cp.ComponentManagedScopeItem, request, store,
			)
			if len(test.wantErrParts) == 0 {
				if err != nil {
					t.Fatalf("valid AssigneeId was rejected: %v", err)
				}
				return
			}
			if err == nil || !containsAll(err.Error(), test.wantErrParts...) {
				t.Fatalf("AssigneeId validation error = %v", err)
			}
		})
	}
}

const assignmentPolicyConcurrentEligibilityTable = "ConcurrentEligibility"

type assignmentPolicyConcurrentBudgetProjectionProvider struct {
	workers int
}

func (assignmentPolicyConcurrentBudgetProjectionProvider) AssignmentPolicyEligibilityReadSurfaces() []cp.ComponentReadSurface {
	return []cp.ComponentReadSurface{{
		Table: assignmentPolicyConcurrentEligibilityTable,
		Fact:  "concurrent eligibility budget test",
	}}
}

func (p assignmentPolicyConcurrentBudgetProjectionProvider) ProjectAssignmentPolicyEligibility(
	ctx context.Context,
	store cp.ComponentManagedReadStore,
	_ []string,
) (AssignmentPolicyEligibilityProjection, error) {
	start := make(chan struct{})
	var reads sync.WaitGroup
	reads.Add(p.workers)
	for range p.workers {
		go func() {
			defer reads.Done()
			<-start
			_, _ = store.ReadRows(ctx, cp.ComponentManagedRowQuery{
				Table:       assignmentPolicyConcurrentEligibilityTable,
				Columns:     []string{"Id"},
				MaximumRows: 1600,
			})
		}()
	}
	close(start)
	reads.Wait()
	return AssignmentPolicyEligibilityProjection{
		Resolution: AssignmentPolicyEligibilityResolved,
		SubjectIDs: []string{"user-sales"},
	}, nil
}

type assignmentPolicyConcurrentEligibilityReadStore struct {
	*permissionSetDefinitionLifecycleMemoryStore
	rowsPerRead int
}

const assignmentPolicyCumulativeEligibilityTable = "CumulativeEligibility"

type assignmentPolicyCumulativeBudgetProjectionProvider struct {
	rowsPerProjection int
}

func (*assignmentPolicyCumulativeBudgetProjectionProvider) AssignmentPolicyEligibilityReadSurfaces() []cp.ComponentReadSurface {
	return []cp.ComponentReadSurface{{
		Table: assignmentPolicyCumulativeEligibilityTable,
		Fact:  "cumulative eligibility budget test",
	}}
}

func (p *assignmentPolicyCumulativeBudgetProjectionProvider) ProjectAssignmentPolicyEligibility(
	ctx context.Context,
	store cp.ComponentManagedReadStore,
	_ []string,
) (AssignmentPolicyEligibilityProjection, error) {
	if p.rowsPerProjection > 0 {
		if _, err := store.ReadRows(ctx, cp.ComponentManagedRowQuery{
			Table:       assignmentPolicyCumulativeEligibilityTable,
			Columns:     []string{"Id"},
			MaximumRows: p.rowsPerProjection,
		}); err != nil {
			return AssignmentPolicyEligibilityProjection{}, err
		}
	}
	return AssignmentPolicyEligibilityProjection{
		Resolution: AssignmentPolicyEligibilityResolved,
		SubjectIDs: []string{"user-sales"},
	}, nil
}

type assignmentPolicyCumulativeEligibilityReadStore struct {
	*permissionSetDefinitionLifecycleMemoryStore
	visibleRows int
}

func (s *assignmentPolicyCumulativeEligibilityReadStore) ReadRows(
	ctx context.Context,
	query cp.ComponentManagedRowQuery,
) ([]cp.ComponentRow, error) {
	if query.Table == assignmentPolicyCumulativeEligibilityTable {
		const available = 30000
		if available > query.MaximumRows {
			return nil, fmt.Errorf(
				"test eligibility read exceeds maximum %d", query.MaximumRows,
			)
		}
		s.visibleRows += available
		return make([]cp.ComponentRow, available), nil
	}
	return s.permissionSetDefinitionLifecycleMemoryStore.ReadRows(ctx, query)
}

func (s *assignmentPolicyConcurrentEligibilityReadStore) ReadRows(
	ctx context.Context,
	query cp.ComponentManagedRowQuery,
) ([]cp.ComponentRow, error) {
	if query.Table == assignmentPolicyConcurrentEligibilityTable {
		return make([]cp.ComponentRow, s.rowsPerRead), nil
	}
	return s.permissionSetDefinitionLifecycleMemoryStore.ReadRows(ctx, query)
}

type assignmentPolicyTestEligibilityProjectionProvider struct {
	store                   *permissionSetDefinitionLifecycleMemoryStore
	subjectIDs              []string
	calls                   int
	requireTargetLock       bool
	requireTargetStateLocks bool
}

func (*assignmentPolicyTestEligibilityProjectionProvider) AssignmentPolicyEligibilityReadSurfaces() []cp.ComponentReadSurface {
	return nil
}

func (p *assignmentPolicyTestEligibilityProjectionProvider) ProjectAssignmentPolicyEligibility(
	_ context.Context,
	store cp.ComponentManagedReadStore,
	selectorKeys []string,
) (AssignmentPolicyEligibilityProjection, error) {
	p.calls++
	if _, exposesMutation := store.(cp.ComponentManagedMutationStore); exposesMutation {
		return AssignmentPolicyEligibilityProjection{}, fmt.Errorf(
			"eligibility provider received a mutation-capable store",
		)
	}
	if p.requireTargetLock && !assignmentPolicyTestHasLock(p.store.locks, "PermissionSet") {
		return AssignmentPolicyEligibilityProjection{}, fmt.Errorf(
			"eligibility provider ran before the target root was locked",
		)
	}
	if p.requireTargetStateLocks {
		for _, table := range []string{
			schemacatalog.AssignmentPolicyClaimTable,
			schemacatalog.AssignmentPolicySelectorTable,
			schemacatalog.AssignmentPolicyTargetStateTable,
			"PermissionSetAssignment",
		} {
			if !assignmentPolicyTestHasLock(p.store.locks, table) {
				return AssignmentPolicyEligibilityProjection{}, fmt.Errorf(
					"eligibility provider ran before %s was locked", table,
				)
			}
		}
	}
	return AssignmentPolicyEligibilityProjection{
		Resolution: AssignmentPolicyEligibilityResolved,
		SubjectIDs: append([]string(nil), p.subjectIDs...),
	}, nil
}

func assignmentPolicyTestHasLock(locks []cp.ComponentManagedRowQuery, table string) bool {
	for _, query := range locks {
		if query.Table == table {
			return true
		}
	}
	return false
}

func containsAll(value string, fragments ...string) bool {
	for _, fragment := range fragments {
		if !strings.Contains(value, fragment) {
			return false
		}
	}
	return true
}

func assignmentPolicyTestEligibilityProvider() AssignmentPolicyEligibilityProjectionProvider {
	provider, err := NewCatalogAssignmentPolicyEligibilityProjectionProvider([]*models.ObjectMetadata{
		{
			APIName: "Profile",
			AccessPolicy: &models.ObjectAccessPolicy{Lifecycle: &models.RecordLifecycleAccessPolicy{
				AssignmentPolicyEligibility: &models.AssignmentPolicyEligibilityLifecyclePolicy{
					Role: models.AssignmentPolicyEligibilitySelectorAuthority,
					EnabledWhen: []models.AssignmentPolicyEligibilityBoolCondition{
						{Field: "IsActive", Equals: true, ResolvedColumn: "IsActive"},
						{Field: "IsDeleted", Equals: false, ResolvedColumn: "IsDeleted"},
					},
					Selector: models.AssignmentPolicyEligibilitySelector{
						Field: "Name", ResolvedFieldColumn: "Name",
					},
					ResolvedSourceTable:    "Profile",
					ResolvedSourceIDColumn: "Id",
				},
			}},
		},
		{
			APIName: "User",
			AccessPolicy: &models.ObjectAccessPolicy{Lifecycle: &models.RecordLifecycleAccessPolicy{
				AssignmentPolicyEligibility: &models.AssignmentPolicyEligibilityLifecyclePolicy{
					Role:           models.AssignmentPolicyEligibilitySubjectPopulation,
					SubjectIDField: "Id",
					EnabledWhen: []models.AssignmentPolicyEligibilityBoolCondition{
						{Field: "IsActive", Equals: true, ResolvedColumn: "IsActive"},
						{Field: "IsDeleted", Equals: false, ResolvedColumn: "IsDeleted"},
					},
					Selector: models.AssignmentPolicyEligibilitySelector{Reference: &models.AssignmentPolicyEligibilityReferenceSelector{
						SourceField: "ProfileId", TargetObject: "Profile", TargetField: "Name",
						ResolvedSourceFieldColumn: "ProfileId", ResolvedTargetTable: "Profile",
						ResolvedTargetIDColumn: "Id", ResolvedTargetFieldColumn: "Name",
					}},
					ResolvedSourceTable:     "User",
					ResolvedSourceIDColumn:  "Id",
					ResolvedSubjectIDColumn: "Id",
				},
			}},
		},
	})
	if err != nil {
		panic(err)
	}
	return provider
}

func assignmentPolicyTestLifecycleProvider() cp.ComponentManagedLifecycleProvider {
	return permissionSetAssignmentPolicyLifecycleProvider(assignmentPolicyTestEligibilityProvider())
}

func newAssignmentPolicyTestManagedLifecycleRegistration() (
	cp.ComponentKindRegistration,
	cp.ComponentManagedLifecycleRegistration,
	error,
) {
	return NewPermissionSetAssignmentPolicyManagedLifecycleRegistrationWithEligibility(
		assignmentPolicyTestEligibilityProvider(),
	)
}

func planAssignmentPolicyTestOperation(
	ctx context.Context,
	store cp.ComponentManagedReadStore,
	request AssignmentPolicyOperationRequest,
) (cp.ComponentManagedPlan, error) {
	return PlanAssignmentPolicyOperationWithEligibility(
		ctx, store, request, assignmentPolicyTestEligibilityProvider(),
	)
}

func assignmentPolicyTestTransactionOperationProvider() cp.ComponentManagedTransactionOperationProvider {
	return PermissionSetAssignmentPolicyTransactionOperationProviderWithEligibility(
		assignmentPolicyTestEligibilityProvider(),
	)
}
