package roles

import (
	"context"
	"errors"
	"fmt"
	"strings"
	"sync/atomic"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/AgentTeam/internal/contentpayload"
	contentservice "github.com/tidbcloud/AgentTeam/internal/service/content"
	"github.com/tidbcloud/AgentTeam/internal/service/resource/repos"
	contentstore "github.com/tidbcloud/AgentTeam/internal/store/content"
	rolestore "github.com/tidbcloud/AgentTeam/internal/store/resource/roles"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

type rejectingLegacyRolePackages struct {
	t      *testing.T
	legacy *testRolePackageContentStore
	reject bool
}

type roleContentWorkspaceAccess struct{ allowed map[string]bool }

type blockingRoleContentService struct {
	nativeRolePackageContentService
	armed     atomic.Bool
	published chan struct{}
	release   chan struct{}
}

func (service *blockingRoleContentService) CommitVersion(ctx context.Context, request contentservice.CommitVersionRequest) (contentservice.CommitVersionResult, error) {
	result, err := service.nativeRolePackageContentService.CommitVersion(ctx, request)
	if err == nil && service.armed.CompareAndSwap(true, false) {
		close(service.published)
		<-service.release
	}
	return result, err
}

func (access roleContentWorkspaceAccess) HasWorkspaceAccess(_ context.Context, workspaceID, subject string) (bool, error) {
	return access.allowed[workspaceID+"\x00"+subject], nil
}

func (s *rejectingLegacyRolePackages) StoreRolePackage(ctx context.Context, input StoreRolePackageInput) (StoreRolePackageOutput, error) {
	if s.reject {
		s.t.Fatal("native role binding fell back to AGS")
	}
	return s.legacy.StoreRolePackage(ctx, input)
}

func (s *rejectingLegacyRolePackages) ResolveRolePackage(ctx context.Context, input ResolveRolePackageInput) (string, error) {
	if s.reject {
		s.t.Fatal("native role binding read from AGS")
	}
	return s.legacy.ResolveRolePackage(ctx, input)
}

func TestNativeRolePackageUpdateReadUsesExactContentVersions(t *testing.T) {
	ctx := context.Background()
	db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{})
	require.NoError(t, err)
	require.NoError(t, db.AutoMigrate(
		&contentstore.Authority{},
		&contentstore.VersionedContent{}, &contentstore.ContentVersion{}, &contentstore.VersionOperation{},
		&contentstore.VersionPath{}, &contentstore.VersionPin{}, &contentstore.Outbox{}, &contentstore.StagedPayloadGC{},
		&rolestore.Role{}, &rolestore.RoleVersion{}, &rolestore.RolePackageManifestItem{}, &rolestore.RoleGrant{},
		&rolestore.RoleRealization{}, &rolestore.RoleRealizationItem{}, &rolestore.AgentRoleBinding{}, &rolestore.RoleOperationReceipt{},
	))
	tree, err := contentpayload.NewFilesystemTreeBackend(t.TempDir())
	require.NoError(t, err)
	t.Cleanup(func() { require.NoError(t, tree.Close()) })
	var ids atomic.Int64
	core, err := contentservice.NewTree(contentstore.New(db), tree, func(prefix string) (string, error) {
		return fmt.Sprintf("%s_%d", prefix, ids.Add(1)), nil
	})
	require.NoError(t, err)
	workspaceAccess := roleContentWorkspaceAccess{allowed: map[string]bool{"wsp_1\x00usr_1": true}}
	roleAccess, err := NewRoleContentAccessPolicy(workspaceAccess, rolestore.New(db))
	require.NoError(t, err)
	domain, err := contentservice.NewAuthorizedService(core, roleAccess)
	require.NoError(t, err)
	authority := contentstore.New(db)
	now := time.Now().UTC()
	require.NoError(t, db.Create(&contentstore.Authority{
		ID: "cta_role_wildcard", WorkspaceID: "wsp_1", Domain: rolePackageContentDomain,
		BindingKey: contentstore.AuthorityDomainDefaultBinding, State: contentstore.AuthorityStateNativeActive,
		Generation: 1, UpdatedBy: "operator", CreatedAt: now, UpdatedAt: now,
	}).Error)
	legacy := &rejectingLegacyRolePackages{t: t, legacy: newTestRolePackageContentStore()}
	routed := AuthorityRoutedRolePackageContentStore{
		NativeEnabled: true, Authority: authority,
		Legacy: legacy, Native: NativeRolePackageContentStore{Content: domain},
	}
	service := New(rolestore.New(db), Options{ContentStore: routed, Ownership: &testAgentOwnershipSource{owned: map[string]bool{"agt_1": true}}})
	var failProjection atomic.Bool
	require.NoError(t, db.Callback().Create().Before("gorm:create").Register("test:role_projection_failure", func(tx *gorm.DB) {
		if tx.Statement == nil || tx.Statement.Schema == nil || tx.Statement.Schema.Table != (rolestore.RoleVersion{}).TableName() {
			return
		}
		if failProjection.CompareAndSwap(true, false) {
			tx.AddError(errors.New("injected role projection failure"))
		}
	}))

	created, err := service.CreateRole(ctx, "wsp_1", "usr_1", Mutation{Name: "Reviewer", Definition: "review carefully"})
	require.NoError(t, err)
	require.Equal(t, "review carefully", created.Definition)
	exact, found, err := authority.GetAuthority(ctx, "wsp_1", rolePackageContentDomain, created.ID)
	require.NoError(t, err)
	require.False(t, found)
	require.Equal(t, contentstore.AuthorityStateLegacyActive, exact.State, "persistent wildcard policy must not capture new Roles")
	legacy.reject = true
	_, err = routed.StoreRolePackage(ctx, StoreRolePackageInput{
		WorkspaceID: "wsp_1", RoleID: created.ID, VersionID: "rlv_native_only", Actor: "usr_1", RequireNative: true,
		Assets: []RolePackageAsset{{ItemType: ManifestItemRoleDefinitionAsset, Name: "IDENTITY.md", Content: "must not reach AGS"}},
	})
	require.ErrorContains(t, err, "native role package write is not active")
	legacy.reject = false
	exact, err = authority.ActivateNativeAuthority(ctx, contentstore.ActivateNativeAuthorityParams{
		WorkspaceID: created.WorkspaceID, Domain: rolePackageContentDomain, BindingKey: created.ID,
		Checkpoint: "import:final", Actor: "operator", Now: time.Now().UTC(),
	})
	require.NoError(t, err)
	require.Equal(t, contentstore.AuthorityStateNativeActive, exact.State)
	legacy.reject = true

	inlineAttachments := []Attachment{
		{Type: AttachmentPortableKnowledge, Name: "Review rubric", Content: "prefer small diffs", Required: true},
		{Type: AttachmentSkill, Name: "Review skill", Content: "# Review skill\n\nCheck correctness.", Required: true},
		{Type: AttachmentKnowledgeBase, Name: "Shared handbook", ResourceID: "kb_1", AccessLevel: "read"},
	}
	updated, err := service.UpdateRole(ctx, "wsp_1", "usr_1", created.ID, Mutation{Name: "Reviewer", Definition: "review carefully and verify tests", Attachments: inlineAttachments})
	require.NoError(t, err)
	require.NotEqual(t, created.RoleVersionID, updated.RoleVersionID)
	require.Equal(t, "review carefully and verify tests", updated.Definition)
	var nativeVersion rolestore.RoleVersion
	require.NoError(t, db.Where("id = ?", updated.RoleVersionID).First(&nativeVersion).Error)
	require.NotEmpty(t, nativeVersion.ContentID)
	require.NotEmpty(t, nativeVersion.ContentVersionID)
	var nativeDefinition rolestore.RolePackageManifestItem
	require.NoError(t, db.Where("role_version_id = ? AND item_type = ?", updated.RoleVersionID, ManifestItemRoleDefinitionAsset).First(&nativeDefinition).Error)
	require.Equal(t, nativeVersion.ContentID, nativeDefinition.ContentID)
	require.Equal(t, nativeVersion.ContentVersionID, nativeDefinition.ContentVersionID)
	require.Equal(t, roleContentRefDefinition, nativeDefinition.ContentPath)
	require.NotContains(t, nativeDefinition.ContentRef, "/api/v3/")
	sharedBeforeRetry, err := service.UpdateRoleVisibility(ctx, "wsp_1", "usr_1", created.ID, RoleVisibilityWorkspace)
	require.NoError(t, err)
	require.Equal(t, RoleVisibilityWorkspace, sharedBeforeRetry.Visibility)

	countContentFacts := func() (versions, operations int64) {
		require.NoError(t, db.Model(&contentstore.ContentVersion{}).Where("workspace_id = ? AND content_id = ?", "wsp_1", nativeVersion.ContentID).Count(&versions).Error)
		require.NoError(t, db.Model(&contentstore.VersionOperation{}).Where("workspace_id = ? AND content_id = ?", "wsp_1", nativeVersion.ContentID).Count(&operations).Error)
		return versions, operations
	}
	versionsBefore, operationsBefore := countContentFacts()
	failProjection.Store(true)
	publicMutation := Mutation{Name: "Reviewer", Definition: "public retry uses one content version", Attachments: inlineAttachments}
	_, err = service.UpdateRole(ctx, "wsp_1", "usr_1", created.ID, publicMutation)
	require.ErrorContains(t, err, "injected role projection failure")
	versionsAfterFailure, operationsAfterFailure := countContentFacts()
	require.Equal(t, versionsBefore+1, versionsAfterFailure)
	require.Equal(t, operationsBefore+1, operationsAfterFailure)
	roleAfterPublicFailure, err := service.GetRole(ctx, "wsp_1", "usr_1", created.ID)
	require.NoError(t, err)
	require.Equal(t, RoleVisibilityWorkspace, roleAfterPublicFailure.Visibility)
	publicRecovered, err := service.UpdateRole(ctx, "wsp_1", "usr_1", created.ID, publicMutation)
	require.NoError(t, err)
	require.Equal(t, RoleVisibilityWorkspace, publicRecovered.Visibility, "public retry must preserve workspace visibility")
	versionsAfterRetry, operationsAfterRetry := countContentFacts()
	require.Equal(t, versionsAfterFailure, versionsAfterRetry, "public retry must reuse the exact Content Store receipt")
	require.Equal(t, operationsAfterFailure, operationsAfterRetry)

	failProjection.Store(true)
	hiddenOperation := MutationOperation{OperationKey: "role-native-partial-commit", RequestDigest: digestForTest("hidden retry uses one content version")}
	hiddenPatch := RoleUpdatePatch{Definition: roleStringForOperationTest("hidden retry uses one content version")}
	_, err = service.UpdateRoleOperation(ctx, "wsp_1", "usr_1", created.ID, hiddenOperation, publicRecovered.RoleVersionID, hiddenPatch)
	require.ErrorContains(t, err, "injected role projection failure")
	versionsAfterHiddenFailure, operationsAfterHiddenFailure := countContentFacts()
	require.Equal(t, versionsAfterRetry+1, versionsAfterHiddenFailure)
	require.Equal(t, operationsAfterRetry+1, operationsAfterHiddenFailure)
	hiddenRecovered, err := service.UpdateRoleOperation(ctx, "wsp_1", "usr_1", created.ID, hiddenOperation, publicRecovered.RoleVersionID, hiddenPatch)
	require.NoError(t, err)
	versionsAfterHiddenRetry, operationsAfterHiddenRetry := countContentFacts()
	require.Equal(t, versionsAfterHiddenFailure, versionsAfterHiddenRetry, "hidden operation retry must reuse the exact Content Store receipt")
	require.Equal(t, operationsAfterHiddenFailure, operationsAfterHiddenRetry)
	var hiddenVersion rolestore.RoleVersion
	require.NoError(t, db.Where("id = ?", hiddenRecovered.RoleVersionID).First(&hiddenVersion).Error)
	var hiddenManifest rolestore.RolePackageManifestItem
	require.NoError(t, db.Where("role_version_id = ? AND item_type = ?", hiddenRecovered.RoleVersionID, ManifestItemRoleDefinitionAsset).First(&hiddenManifest).Error)
	require.Equal(t, hiddenVersion.ContentID, hiddenManifest.ContentID)
	require.Equal(t, hiddenVersion.ContentVersionID, hiddenManifest.ContentVersionID)
	var hiddenInlineKnowledge rolestore.RolePackageManifestItem
	require.NoError(t, db.Where("role_version_id = ? AND item_type = ?", hiddenRecovered.RoleVersionID, AttachmentPortableKnowledge).First(&hiddenInlineKnowledge).Error)
	require.Equal(t, hiddenVersion.ContentID, hiddenInlineKnowledge.ContentID)
	require.Equal(t, hiddenVersion.ContentVersionID, hiddenInlineKnowledge.ContentVersionID)
	require.NotEmpty(t, hiddenInlineKnowledge.ContentPath)
	require.NotEmpty(t, hiddenInlineKnowledge.ContentRef)
	var hiddenExternalKnowledge rolestore.RolePackageManifestItem
	require.NoError(t, db.Where("role_version_id = ? AND item_type = ?", hiddenRecovered.RoleVersionID, AttachmentKnowledgeBase).First(&hiddenExternalKnowledge).Error)
	require.Equal(t, "kb_1", hiddenExternalKnowledge.SourceResourceID)
	require.Empty(t, hiddenExternalKnowledge.ContentRef)
	require.Empty(t, hiddenExternalKnowledge.ContentID)
	require.Empty(t, hiddenExternalKnowledge.ContentVersionID)
	require.Empty(t, hiddenExternalKnowledge.ContentPath)
	var hiddenReceipt rolestore.RoleOperationReceipt
	require.NoError(t, db.Where("workspace_id = ? AND operation_key = ?", "wsp_1", hiddenOperation.OperationKey).First(&hiddenReceipt).Error)
	require.Contains(t, hiddenReceipt.ResultJSON, hiddenRecovered.RoleVersionID)

	fenced, err := service.GetRole(ctx, "wsp_1", "usr_1", created.ID)
	require.NoError(t, err)
	require.Equal(t, hiddenRecovered.Definition, fenced.Definition)

	workspaceAccess.allowed["wsp_1\x00usr_viewer"] = true
	_, err = service.store.UpsertRoleGrant(ctx, rolestore.RoleGrant{
		ID: "rgr_viewer", WorkspaceID: "wsp_1", RoleID: created.ID, SubjectType: "user", SubjectID: "usr_viewer", Role: roleGrantView,
		CreatedBy: "usr_1", UpdatedBy: "usr_1", CreatedAt: now, UpdatedAt: now,
	})
	require.NoError(t, err)
	workspaceAccess.allowed["wsp_1\x00usr_1"] = false
	_, err = service.PlanRoleRealizationImpact(ctx, "wsp_1", "usr_viewer", created.ID, RealizationRequest{AgentID: "agt_1", DryRun: true})
	require.NoError(t, err, "impact reads must authorize the actual caller rather than the Role creator")
	workspaceAccess.allowed["wsp_1\x00usr_1"] = true

	originalVersionContentID := hiddenVersion.ContentID
	require.NoError(t, db.Model(&rolestore.RoleVersion{}).Where("id = ?", hiddenRecovered.RoleVersionID).Update("content_id", "ctn_tampered").Error)
	_, err = service.GetRole(ctx, "wsp_1", "usr_1", created.ID)
	require.ErrorContains(t, err, "role version exact content projection does not match manifest")
	_, err = service.GetRoleVersion(ctx, "wsp_1", "usr_1", created.ID, hiddenRecovered.RoleVersionID)
	require.ErrorContains(t, err, "role version exact content projection does not match manifest")
	require.NoError(t, db.Model(&rolestore.RoleVersion{}).Where("id = ?", hiddenRecovered.RoleVersionID).Update("content_id", originalVersionContentID).Error)

	require.NoError(t, db.Model(&rolestore.RolePackageManifestItem{}).
		Where("id = ?", hiddenManifest.ID).
		Update("content_version_id", "ctv_tampered").Error)
	_, err = service.GetRole(ctx, "wsp_1", "usr_1", created.ID)
	require.Error(t, err)
	require.ErrorContains(t, err, "exact content projection does not match")
	require.NoError(t, db.Model(&rolestore.RolePackageManifestItem{}).Where("id = ?", hiddenManifest.ID).Update("content_version_id", hiddenManifest.ContentVersionID).Error)

	beforeRealizations, beforeBindings := int64(0), int64(0)
	require.NoError(t, db.Model(&rolestore.RoleRealization{}).Count(&beforeRealizations).Error)
	require.NoError(t, db.Model(&rolestore.AgentRoleBinding{}).Count(&beforeBindings).Error)
	for _, corruption := range []struct {
		name    string
		item    rolestore.RolePackageManifestItem
		updates map[string]any
		want    string
	}{
		{name: "missing exact triple", item: hiddenInlineKnowledge, updates: map[string]any{"content_id": "", "content_version_id": "", "content_path": ""}, want: "inline item exact content projection is missing"},
		{name: "missing content ref", item: hiddenInlineKnowledge, updates: map[string]any{"content_ref": ""}, want: "inline item exact content projection is missing"},
		{name: "external item local projection", item: hiddenExternalKnowledge, updates: map[string]any{"content_id": hiddenVersion.ContentID}, want: "external resource item has local content projection"},
		{name: "external item local hash", item: hiddenExternalKnowledge, updates: map[string]any{"content_hash": rolePackageContentHash("not external")}, want: "external resource item has local content projection"},
		{name: "external item local payload", item: hiddenExternalKnowledge, updates: map[string]any{"content": "not external"}, want: "external resource item has local content projection"},
	} {
		t.Run(corruption.name, func(t *testing.T) {
			require.NoError(t, db.Model(&rolestore.RolePackageManifestItem{}).Where("id = ?", corruption.item.ID).Updates(corruption.updates).Error)

			_, err := service.GetRole(ctx, "wsp_1", "usr_1", created.ID)
			require.ErrorContains(t, err, corruption.want)
			_, err = service.GetRoleVersion(ctx, "wsp_1", "usr_1", created.ID, hiddenRecovered.RoleVersionID)
			require.ErrorContains(t, err, corruption.want)
			_, err = service.RealizeRoleForAgent(ctx, "wsp_1", "usr_1", created.ID, RealizationRequest{AgentID: "agt_1", DryRun: true})
			require.ErrorContains(t, err, corruption.want)
			operation := MutationOperation{OperationKey: "native-inline-corruption-" + strings.ReplaceAll(corruption.name, " ", "-"), RequestDigest: digestForTest(corruption.name)}
			_, err = service.ApplyRoleOperation(ctx, "wsp_1", "usr_1", created.ID, operation, RealizationRequest{AgentID: "agt_1", RoleVersionID: hiddenRecovered.RoleVersionID, Apply: true})
			require.ErrorContains(t, err, corruption.want)
			var realizations, bindings, receipts int64
			require.NoError(t, db.Model(&rolestore.RoleRealization{}).Count(&realizations).Error)
			require.NoError(t, db.Model(&rolestore.AgentRoleBinding{}).Count(&bindings).Error)
			require.NoError(t, db.Model(&rolestore.RoleOperationReceipt{}).Where("operation_key = ?", operation.OperationKey).Count(&receipts).Error)
			require.Equal(t, beforeRealizations, realizations)
			require.Equal(t, beforeBindings, bindings)
			require.Zero(t, receipts)

			require.NoError(t, db.Model(&rolestore.RolePackageManifestItem{}).Where("id = ?", corruption.item.ID).Updates(map[string]any{
				"content_id": corruption.item.ContentID, "content_version_id": corruption.item.ContentVersionID,
				"content_path": corruption.item.ContentPath, "content_ref": corruption.item.ContentRef,
				"content_hash": corruption.item.ContentHash, "content": corruption.item.Content,
			}).Error)
		})
	}
	require.NoError(t, db.Model(&rolestore.RolePackageManifestItem{}).Where("id = ?", hiddenManifest.ID).Update("content_hash", "bad-hash").Error)
	_, err = service.RealizeRoleForAgent(ctx, "wsp_1", "usr_1", created.ID, RealizationRequest{AgentID: "agt_1", DryRun: true})
	require.ErrorContains(t, err, "content hash mismatch")
	tamperedApply := MutationOperation{OperationKey: "native-tampered-apply", RequestDigest: digestForTest("native tampered")}
	_, err = service.ApplyRoleOperation(ctx, "wsp_1", "usr_1", created.ID, tamperedApply, RealizationRequest{AgentID: "agt_1", RoleVersionID: hiddenRecovered.RoleVersionID, Apply: true})
	require.ErrorContains(t, err, "content hash mismatch")
	var tamperedReceipts int64
	require.NoError(t, db.Model(&rolestore.RoleOperationReceipt{}).Where("operation_key = ?", tamperedApply.OperationKey).Count(&tamperedReceipts).Error)
	require.Zero(t, tamperedReceipts)
	require.NoError(t, db.Model(&rolestore.RolePackageManifestItem{}).Where("id = ?", hiddenManifest.ID).Update("content_hash", hiddenManifest.ContentHash).Error)

	routed.Native = unavailableRolePackageContentStore{}
	service.contentStore = routed
	_, err = service.RealizeRoleForAgent(ctx, "wsp_1", "usr_1", created.ID, RealizationRequest{AgentID: "agt_1", DryRun: true})
	require.Error(t, err)
	applyOperation := MutationOperation{OperationKey: "native-unavailable-apply", RequestDigest: digestForTest("native unavailable")}
	_, err = service.ApplyRoleOperation(ctx, "wsp_1", "usr_1", created.ID, applyOperation, RealizationRequest{AgentID: "agt_1", RoleVersionID: hiddenRecovered.RoleVersionID, Apply: true})
	require.Error(t, err)
	var afterRealizations, afterBindings, applyReceipts int64
	require.NoError(t, db.Model(&rolestore.RoleRealization{}).Count(&afterRealizations).Error)
	require.NoError(t, db.Model(&rolestore.AgentRoleBinding{}).Count(&afterBindings).Error)
	require.NoError(t, db.Model(&rolestore.RoleOperationReceipt{}).Where("operation_key = ?", applyOperation.OperationKey).Count(&applyReceipts).Error)
	require.Equal(t, beforeRealizations, afterRealizations)
	require.Equal(t, beforeBindings, afterBindings)
	require.Zero(t, applyReceipts)

	countRoleFacts := func() (versions, contentOperations, roleVersions, roleOperations int64) {
		require.NoError(t, db.Model(&contentstore.ContentVersion{}).Where("workspace_id = ? AND content_id = ?", "wsp_1", hiddenVersion.ContentID).Count(&versions).Error)
		require.NoError(t, db.Model(&contentstore.VersionOperation{}).Where("workspace_id = ? AND content_id = ?", "wsp_1", hiddenVersion.ContentID).Count(&contentOperations).Error)
		require.NoError(t, db.Model(&rolestore.RoleVersion{}).Where("workspace_id = ? AND role_id = ?", "wsp_1", created.ID).Count(&roleVersions).Error)
		require.NoError(t, db.Model(&rolestore.RoleOperationReceipt{}).Where("workspace_id = ?", "wsp_1").Count(&roleOperations).Error)
		return
	}
	assertActiveRoleMatchesContent := func() rolestore.RoleVersion {
		active, err := service.store.GetActiveRoleVersion(ctx, "wsp_1", created.ID)
		require.NoError(t, err)
		content, err := authority.GetVersionedContent(ctx, "wsp_1", active.ContentID)
		require.NoError(t, err)
		require.Equal(t, active.ContentVersionID, content.HeadVersionID)
		items, err := service.store.ListManifestItemsByRoleVersion(ctx, "wsp_1", created.ID, active.ID)
		require.NoError(t, err)
		for _, item := range items {
			if roleManifestItemProjection(item) == roleManifestItemProjectionExact {
				require.Equal(t, active.ContentID, item.ContentID)
				require.Equal(t, active.ContentVersionID, item.ContentVersionID)
				require.NoError(t, validateRoleManifestExactContentRef(item))
			}
		}
		return active
	}

	hiddenBarrier := &blockingRoleContentService{nativeRolePackageContentService: domain, published: make(chan struct{}), release: make(chan struct{})}
	hiddenBarrier.armed.Store(true)
	routed.Native = NativeRolePackageContentStore{Content: hiddenBarrier}
	service.contentStore = routed
	beforeVersions, beforeContentOperations, beforeRoleVersions, beforeRoleOperations := countRoleFacts()
	type roleUpdateResult struct {
		role Role
		err  error
	}
	aResult := make(chan roleUpdateResult, 1)
	aOperation := MutationOperation{OperationKey: "role-native-concurrent-a", RequestDigest: digestForTest("concurrent A")}
	go func() {
		role, err := service.UpdateRoleOperation(ctx, "wsp_1", "usr_1", created.ID, aOperation, hiddenRecovered.RoleVersionID, RoleUpdatePatch{Definition: roleStringForOperationTest("concurrent A")})
		aResult <- roleUpdateResult{role: role, err: err}
	}()
	<-hiddenBarrier.published
	aPublishedVersions, aPublishedContentOperations, aPublishedRoleVersions, aPublishedRoleOperations := countRoleFacts()
	require.Equal(t, beforeVersions+1, aPublishedVersions)
	require.Equal(t, beforeContentOperations+1, aPublishedContentOperations)
	require.Equal(t, beforeRoleVersions, aPublishedRoleVersions)
	require.Equal(t, beforeRoleOperations, aPublishedRoleOperations)

	bOperation := MutationOperation{OperationKey: "role-native-concurrent-b", RequestDigest: digestForTest("concurrent B")}
	_, err = service.UpdateRoleOperation(ctx, "wsp_1", "usr_1", created.ID, bOperation, hiddenRecovered.RoleVersionID, RoleUpdatePatch{Definition: roleStringForOperationTest("concurrent B")})
	require.ErrorIs(t, err, ErrRoleVersionConflict)
	afterBVersions, afterBContentOperations, afterBRoleVersions, afterBRoleOperations := countRoleFacts()
	require.Equal(t, aPublishedVersions, afterBVersions, "stale hidden update must not publish another ContentVersion")
	require.Equal(t, aPublishedContentOperations, afterBContentOperations, "stale hidden update must not persist a Content operation")
	require.Equal(t, aPublishedRoleVersions, afterBRoleVersions, "stale hidden update must not persist a RoleVersion")
	require.Equal(t, aPublishedRoleOperations, afterBRoleOperations, "stale hidden update must not persist a Role operation")
	close(hiddenBarrier.release)
	a := <-aResult
	require.NoError(t, a.err)
	require.NotEmpty(t, a.role.RoleVersionID)
	_, _, finalHiddenRoleVersions, finalHiddenRoleOperations := countRoleFacts()
	require.Equal(t, beforeRoleVersions+1, finalHiddenRoleVersions)
	require.Equal(t, beforeRoleOperations+1, finalHiddenRoleOperations)
	var bReceipts int64
	require.NoError(t, db.Model(&rolestore.RoleOperationReceipt{}).Where("workspace_id = ? AND operation_key = ?", "wsp_1", bOperation.OperationKey).Count(&bReceipts).Error)
	require.Zero(t, bReceipts)
	activeAfterHiddenRace := assertActiveRoleMatchesContent()
	require.Equal(t, a.role.RoleVersionID, activeAfterHiddenRace.ID)

	publicBarrier := &blockingRoleContentService{nativeRolePackageContentService: domain, published: make(chan struct{}), release: make(chan struct{})}
	publicBarrier.armed.Store(true)
	routed.Native = NativeRolePackageContentStore{Content: publicBarrier}
	service.contentStore = routed
	beforeVersions, beforeContentOperations, beforeRoleVersions, beforeRoleOperations = countRoleFacts()
	publicResult := make(chan roleUpdateResult, 1)
	publicConcurrentMutation := Mutation{Name: "Reviewer", Definition: "public concurrent update", Attachments: inlineAttachments}
	go func() {
		role, err := service.UpdateRole(ctx, "wsp_1", "usr_1", created.ID, publicConcurrentMutation)
		publicResult <- roleUpdateResult{role: role, err: err}
	}()
	<-publicBarrier.published
	publicWinner, err := service.UpdateRole(ctx, "wsp_1", "usr_1", created.ID, publicConcurrentMutation)
	require.NoError(t, err)
	close(publicBarrier.release)
	publicLoser := <-publicResult
	require.ErrorIs(t, publicLoser.err, ErrRoleVersionConflict)
	afterVersions, afterContentOperations, afterRoleVersions, afterRoleOperations := countRoleFacts()
	require.Equal(t, beforeVersions+1, afterVersions, "same public request must publish one ContentVersion")
	require.Equal(t, beforeContentOperations+1, afterContentOperations, "same public request must persist one Content operation")
	require.Equal(t, beforeRoleVersions+1, afterRoleVersions, "public product CAS must persist one RoleVersion")
	require.Equal(t, beforeRoleOperations, afterRoleOperations)
	activeAfterPublicRace := assertActiveRoleMatchesContent()
	require.Equal(t, publicWinner.RoleVersionID, activeAfterPublicRace.ID)

	history, err := service.ListRoleVersions(ctx, "wsp_1", "usr_1", created.ID, 1, 2)
	require.NoError(t, err)
	require.Len(t, history.Items, 2)
	require.True(t, history.HasMore)
	require.Equal(t, publicWinner.RoleVersionID, history.Items[0].ID)
	require.True(t, history.Items[0].Active)
	beforeVersions, beforeContentOperations, beforeRoleVersions, beforeRoleOperations = countRoleFacts()
	_, err = service.RollbackRoleVersion(ctx, "wsp_1", "usr_viewer", created.ID, publicWinner.RoleVersionID, updated.RoleVersionID)
	require.ErrorIs(t, err, repos.ErrForbidden)
	afterForbiddenVersions, afterForbiddenOperations, afterForbiddenRoleVersions, afterForbiddenRoleOperations := countRoleFacts()
	require.Equal(t, beforeVersions, afterForbiddenVersions)
	require.Equal(t, beforeContentOperations, afterForbiddenOperations)
	require.Equal(t, beforeRoleVersions, afterForbiddenRoleVersions)
	require.Equal(t, beforeRoleOperations, afterForbiddenRoleOperations)
	routed.Native = unavailableRolePackageContentStore{}
	service.contentStore = routed
	_, err = service.RollbackRoleVersion(ctx, "wsp_1", "usr_1", created.ID, publicWinner.RoleVersionID, updated.RoleVersionID)
	require.Error(t, err)
	afterUnavailableVersions, afterUnavailableOperations, afterUnavailableRoleVersions, afterUnavailableRoleOperations := countRoleFacts()
	require.Equal(t, beforeVersions, afterUnavailableVersions)
	require.Equal(t, beforeContentOperations, afterUnavailableOperations)
	require.Equal(t, beforeRoleVersions, afterUnavailableRoleVersions)
	require.Equal(t, beforeRoleOperations, afterUnavailableRoleOperations)
	routed.Native = NativeRolePackageContentStore{Content: publicBarrier}
	service.contentStore = routed

	beforeVersions, beforeContentOperations, beforeRoleVersions, beforeRoleOperations = countRoleFacts()
	failProjection.Store(true)
	_, err = service.RollbackRoleVersion(ctx, "wsp_1", "usr_1", created.ID, publicWinner.RoleVersionID, updated.RoleVersionID)
	require.ErrorContains(t, err, "injected role projection failure")
	afterRollbackFailureVersions, afterRollbackFailureOperations, afterRollbackFailureRoleVersions, afterRollbackFailureRoleOperations := countRoleFacts()
	require.Equal(t, beforeVersions+1, afterRollbackFailureVersions)
	require.Equal(t, beforeContentOperations+1, afterRollbackFailureOperations)
	require.Equal(t, beforeRoleVersions, afterRollbackFailureRoleVersions)
	require.Equal(t, beforeRoleOperations, afterRollbackFailureRoleOperations)
	activeAfterRollbackFailure, err := service.store.GetActiveRoleVersion(ctx, "wsp_1", created.ID)
	require.NoError(t, err)
	require.Equal(t, publicWinner.RoleVersionID, activeAfterRollbackFailure.ID)
	roleAfterRollbackFailure, err := service.GetRole(ctx, "wsp_1", "usr_1", created.ID)
	require.NoError(t, err)
	require.Equal(t, RoleVisibilityWorkspace, roleAfterRollbackFailure.Visibility)

	rolledBack, err := service.RollbackRoleVersion(ctx, "wsp_1", "usr_1", created.ID, publicWinner.RoleVersionID, updated.RoleVersionID)
	require.NoError(t, err)
	afterRollbackRetryVersions, afterRollbackRetryOperations, afterRollbackRetryRoleVersions, afterRollbackRetryRoleOperations := countRoleFacts()
	require.Equal(t, afterRollbackFailureVersions, afterRollbackRetryVersions, "rollback retry must reuse the exact Content Store receipt")
	require.Equal(t, afterRollbackFailureOperations, afterRollbackRetryOperations)
	require.Equal(t, beforeRoleVersions+1, afterRollbackRetryRoleVersions)
	require.Equal(t, beforeRoleOperations, afterRollbackRetryRoleOperations)
	require.Equal(t, updated.Definition, rolledBack.Definition)
	require.Equal(t, RoleVisibilityWorkspace, rolledBack.Visibility, "rollback retry must preserve workspace visibility")
	require.NotEqual(t, updated.RoleVersionID, rolledBack.RoleVersionID, "rollback publishes a new immutable RoleVersion")
	activeAfterRollbackRetry := assertActiveRoleMatchesContent()
	require.Equal(t, rolledBack.RoleVersionID, activeAfterRollbackRetry.ID)

	rollbackBarrier := &blockingRoleContentService{nativeRolePackageContentService: domain, published: make(chan struct{}), release: make(chan struct{})}
	rollbackBarrier.armed.Store(true)
	routed.Native = NativeRolePackageContentStore{Content: rollbackBarrier}
	service.contentStore = routed
	beforeVersions, beforeContentOperations, beforeRoleVersions, beforeRoleOperations = countRoleFacts()
	rollbackA := make(chan roleUpdateResult, 1)
	go func() {
		role, err := service.RollbackRoleVersion(ctx, "wsp_1", "usr_1", created.ID, rolledBack.RoleVersionID, hiddenRecovered.RoleVersionID)
		rollbackA <- roleUpdateResult{role: role, err: err}
	}()
	<-rollbackBarrier.published
	afterRollbackAPublishVersions, afterRollbackAPublishOperations, afterRollbackAPublishRoleVersions, afterRollbackAPublishRoleOperations := countRoleFacts()
	require.Equal(t, beforeVersions+1, afterRollbackAPublishVersions)
	require.Equal(t, beforeContentOperations+1, afterRollbackAPublishOperations)
	require.Equal(t, beforeRoleVersions, afterRollbackAPublishRoleVersions)
	require.Equal(t, beforeRoleOperations, afterRollbackAPublishRoleOperations)

	_, err = service.RollbackRoleVersion(ctx, "wsp_1", "usr_1", created.ID, rolledBack.RoleVersionID, publicRecovered.RoleVersionID)
	require.ErrorIs(t, err, ErrRoleVersionConflict)
	afterStaleRollbackVersions, afterStaleRollbackOperations, afterStaleRollbackRoleVersions, afterStaleRollbackRoleOperations := countRoleFacts()
	require.Equal(t, afterRollbackAPublishVersions, afterStaleRollbackVersions)
	require.Equal(t, afterRollbackAPublishOperations, afterStaleRollbackOperations)
	require.Equal(t, afterRollbackAPublishRoleVersions, afterStaleRollbackRoleVersions)
	require.Equal(t, afterRollbackAPublishRoleOperations, afterStaleRollbackRoleOperations)
	close(rollbackBarrier.release)
	rollbackWinner := <-rollbackA
	require.NoError(t, rollbackWinner.err)
	activeAfterRollbackRace := assertActiveRoleMatchesContent()
	require.Equal(t, rollbackWinner.role.RoleVersionID, activeAfterRollbackRace.ID)

}
