package memory

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/contentpayload"
	"github.com/tidbcloud/AgentTeam/internal/core/identifiers"
	contentservice "github.com/tidbcloud/AgentTeam/internal/service/content"
	"github.com/tidbcloud/AgentTeam/internal/service/content/migration"
	"github.com/tidbcloud/AgentTeam/internal/service/resource/repos"
	"github.com/tidbcloud/AgentTeam/internal/store/content"
	migrationstore "github.com/tidbcloud/AgentTeam/internal/store/content/migration"
	memorystore "github.com/tidbcloud/AgentTeam/internal/store/resource/memory"
	reposstore "github.com/tidbcloud/AgentTeam/internal/store/resource/repos"
	"gorm.io/gorm"
)

var memoryMigrationQuota = contentservice.QuotaProfile{
	MaxRetainedVersions: memoryContentMaxVersions, MaxStoredPayloadBytes: memoryContentMaxStoredBytes, MaxPins: memoryContentMaxPins,
}

// MemoryContentMigrationWorker is the existing durable exact-source worker
// narrowed to the two publication contracts Memory needs.
type MemoryContentMigrationWorker interface {
	RunExact(context.Context, migration.Request, migration.Exporter, migration.Projector) (migration.Result, error)
	RunDetachedExact(context.Context, migration.DetachedRequest, migration.Exporter, migration.Projector) (migration.Result, error)
}

// MemoryMigrationMappingReader resolves one exact durable source mapping. It
// is used only to resume an older first-parent job after the live head moved.
type MemoryMigrationMappingReader interface {
	GetMapping(context.Context, string, string) (migrationstore.Mapping, error)
}

// MemoryMigrationContent is the authorized Content Store surface used by the
// Memory-owned import coordinator. It has no repository or Git semantics.
type MemoryMigrationContent interface {
	FindContentByBinding(context.Context, string, string, string) (contentservice.Content, bool, error)
	CreateContent(context.Context, contentservice.CreateContentRequest) (contentservice.Content, error)
	GetContent(context.Context, string, string) (contentservice.Content, error)
	GetVersion(context.Context, string, string, string) (contentservice.Version, error)
	CreatePin(context.Context, contentservice.CreatePinRequest) (contentservice.Pin, error)
	ListPins(context.Context, string, string, int) ([]contentservice.Pin, error)
}

type MemoryContentMigrationRequest struct {
	Branch            string
	ProductReferences []MemoryMigrationReference
}

type MemoryContentMigrationResult struct {
	ContentID        string
	HeadVersionID    string
	Generation       uint64
	ImportedVersions int
	ImportedPins     int
	Replayed         bool
}

type memoryMigrationRun struct {
	workspaceID       string
	memoryID          string
	actor             string
	repository        repos.RepositoryIdentity
	repositoryBinding reposstore.ResourceRepository
	boundBranch       string
	plan              MemoryMigrationPreflight
	content           contentservice.Content
}

// RunMemoryContentMigration imports one bounded, preflighted AGS history into
// a dormant native Memory lineage. It never changes authority; Desktop remains
// on legacy ownership until the later grouped cutover.
func (s *MemoryService) RunMemoryContentMigration(ctx context.Context, workspaceID, subject, memoryID string, request MemoryContentMigrationRequest) (MemoryContentMigrationResult, error) {
	if s == nil || s.store == nil || s.repositoryStore == nil || s.migrationSource == nil || s.migrationWorker == nil || s.migrationMappings == nil || s.migrationContent == nil || s.contentAuthority == nil {
		return MemoryContentMigrationResult{}, invalidArgument("memory content migration is not configured")
	}
	workspaceID = strings.TrimSpace(workspaceID)
	subject = strings.TrimSpace(subject)
	memoryID = strings.TrimSpace(memoryID)
	memory, err := s.GetMemory(ctx, workspaceID, subject, memoryID)
	if err != nil {
		return MemoryContentMigrationResult{}, err
	}
	if !memory.CanManage {
		return MemoryContentMigrationResult{}, forbidden("memory content migration requires manage access")
	}
	if err := s.requireLegacyMemoryMigrationAuthority(ctx, workspaceID, memory.ID); err != nil {
		return MemoryContentMigrationResult{}, err
	}
	repository, err := s.repositoryStore.Get(ctx, workspaceID, reposstore.ResourceTypeMemory, memory.ID, reposstore.RepoRolePrimary)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return MemoryContentMigrationResult{}, notFound("memory migration repository not found")
		}
		return MemoryContentMigrationResult{}, err
	}
	if strings.TrimSpace(repository.AGSRepoID) == "" {
		return MemoryContentMigrationResult{}, invalidArgument("memory migration repository identity is missing")
	}
	boundBranch, err := exactMemoryMigrationBranch(memory, repository, request.Branch)
	if err != nil {
		return MemoryContentMigrationResult{}, err
	}
	identity := repos.IdentityFromStore(repository)
	plan, err := PreflightMemoryMigration(ctx, s.migrationSource, MemoryMigrationPreflightRequest{
		Repository: identity, Branch: boundBranch, ProductReferences: request.ProductReferences,
	})
	if err != nil {
		return MemoryContentMigrationResult{}, err
	}
	if plan.RepositoryID != repository.AGSRepoID || plan.VersionCount == 0 {
		return MemoryContentMigrationResult{}, conflict("memory migration preflight identity is inconsistent")
	}
	run := memoryMigrationRun{
		workspaceID: workspaceID, memoryID: memory.ID, actor: subject, repository: identity,
		repositoryBinding: repository, boundBranch: boundBranch, plan: plan,
	}
	if err := s.revalidateMemoryMigrationRun(ctx, run); err != nil {
		return MemoryContentMigrationResult{}, err
	}
	content, err := s.ensureMemoryMigrationContent(ctx, workspaceID, memory, subject)
	if err != nil {
		return MemoryContentMigrationResult{}, err
	}

	run.content = content
	versions, head, firstParentReplayed, err := s.importMemoryFirstParent(ctx, run)
	if err != nil {
		return MemoryContentMigrationResult{}, err
	}
	detachedReplayed, err := s.importMemoryDetached(ctx, run, versions, head)
	if err != nil {
		return MemoryContentMigrationResult{}, err
	}
	replayed := firstParentReplayed && detachedReplayed
	if err := s.revalidateMemoryMigrationRun(ctx, run); err != nil {
		return MemoryContentMigrationResult{}, err
	}
	pins, err := s.ensureMemoryMigrationPins(ctx, workspaceID, memory.ID, subject, content, plan, versions)
	if err != nil {
		return MemoryContentMigrationResult{}, err
	}
	if err := s.revalidateMemoryMigrationRun(ctx, run); err != nil {
		return MemoryContentMigrationResult{}, err
	}
	_, err = s.store.FinalizeMemoryContentImport(ctx, workspaceID, memory.ID, content.ID, head.VersionID, content.Generation, uint64(len(plan.Versions)), subject, s.now())
	if err != nil {
		return MemoryContentMigrationResult{}, mapMemoryContentStoreError(err)
	}
	return MemoryContentMigrationResult{
		ContentID: content.ID, HeadVersionID: head.VersionID, Generation: content.Generation,
		ImportedVersions: len(plan.Versions), ImportedPins: pins, Replayed: replayed,
	}, nil
}

func (s *MemoryService) importMemoryFirstParent(ctx context.Context, run memoryMigrationRun) (map[string]migration.Result, migration.Result, bool, error) {
	versions := make(map[string]migration.Result, len(run.plan.Versions))
	replayed := true
	for _, planned := range run.plan.Versions {
		if !planned.FirstParent {
			break
		}
		parentVersionID, err := memoryMigrationParentVersionID(planned, versions)
		if err != nil {
			return nil, migration.Result{}, false, err
		}
		result, found, err := s.loadProjectedMemoryMigration(ctx, run.workspaceID, run.memoryID, run.actor, run.plan.RepositoryID, run.content, planned, parentVersionID)
		if err != nil {
			return nil, migration.Result{}, false, err
		}
		current, err := s.getMemoryMigrationContent(ctx, run.workspaceID, run.memoryID, run.content.ID, run.content.Generation, run.actor)
		if err != nil {
			return nil, migration.Result{}, false, err
		}
		if !found || current.HeadVersionID == result.VersionID {
			if current.HeadVersionID != parentVersionID && (result.VersionID == "" || current.HeadVersionID != result.VersionID) {
				return nil, migration.Result{}, false, conflict("memory migration live head does not match first-parent plan")
			}
			result, err = s.migrationWorker.RunExact(ctx, migration.Request{
				WorkspaceID: run.workspaceID, BindingKey: run.memoryID, SourceCursor: "first:" + planned.CommitSHA,
				RepositoryID: run.plan.RepositoryID, CommitSHA: planned.CommitSHA, ExpectedHeadVersionID: parentVersionID,
				Actor: run.actor, Limits: memoryContentTreeLimits,
			}, s.memoryMigrationExporter(run.repository, planned), s.memoryMigrationProjector(run.workspaceID, run.memoryID, run.plan.RepositoryID, run.content.ID, run.actor, planned, parentVersionID, run.content.Generation))
			if err != nil {
				return nil, migration.Result{}, false, err
			}
			if err := validateMemoryMigrationResult(result, planned, run.content.ID); err != nil {
				return nil, migration.Result{}, false, err
			}
			replayed = replayed && result.Replayed
		}
		versions[planned.CommitSHA] = result
	}
	head := versions[run.plan.HeadCommitSHA]
	if head.VersionID == "" {
		return nil, migration.Result{}, false, conflict("memory migration branch head mapping is missing")
	}
	current, err := s.getMemoryMigrationContent(ctx, run.workspaceID, run.memoryID, run.content.ID, run.content.Generation, run.actor)
	if err != nil {
		return nil, migration.Result{}, false, err
	}
	if current.HeadVersionID != head.VersionID {
		return nil, migration.Result{}, false, conflict("memory migration branch head was not published exactly")
	}
	return versions, head, replayed, nil
}

func (s *MemoryService) importMemoryDetached(ctx context.Context, run memoryMigrationRun, versions map[string]migration.Result, head migration.Result) (bool, error) {
	replayed := true
	for _, planned := range run.plan.Versions {
		if planned.FirstParent {
			continue
		}
		parentVersionID, err := memoryMigrationParentVersionID(planned, versions)
		if err != nil {
			return false, err
		}
		if _, _, err := s.loadProjectedMemoryMigration(ctx, run.workspaceID, run.memoryID, run.actor, run.plan.RepositoryID, run.content, planned, parentVersionID); err != nil {
			return false, err
		}
		result, err := s.migrationWorker.RunDetachedExact(ctx, migration.DetachedRequest{
			Request: migration.Request{
				WorkspaceID: run.workspaceID, BindingKey: run.memoryID, SourceCursor: "detached:" + planned.CommitSHA,
				RepositoryID: run.plan.RepositoryID, CommitSHA: planned.CommitSHA, ExpectedHeadVersionID: head.VersionID,
				Actor: run.actor, Limits: memoryContentTreeLimits,
			},
			ParentVersionID: parentVersionID, ExpectedGeneration: run.content.Generation, Quota: memoryMigrationQuota,
		}, s.memoryMigrationExporter(run.repository, planned), s.memoryMigrationProjector(run.workspaceID, run.memoryID, run.plan.RepositoryID, run.content.ID, run.actor, planned, parentVersionID, run.content.Generation))
		if err != nil {
			return false, err
		}
		if err := validateMemoryMigrationResult(result, planned, run.content.ID); err != nil {
			return false, err
		}
		replayed = replayed && result.Replayed
		versions[planned.CommitSHA] = result
	}
	return replayed, nil
}

func (s *MemoryService) requireLegacyMemoryMigrationAuthority(ctx context.Context, workspaceID, memoryID string) error {
	authority, found, err := s.contentAuthority.GetAuthority(ctx, workspaceID, memoryContentDomain, memoryID)
	if err != nil {
		return fmt.Errorf("resolve memory migration authority: %w", err)
	}
	if found && strings.TrimSpace(authority.State) != content.AuthorityStateLegacyActive {
		return conflict("memory migration requires legacy read ownership")
	}
	return nil
}

func (s *MemoryService) revalidateMemoryMigrationHead(ctx context.Context, repository repos.RepositoryIdentity, plan MemoryMigrationPreflight) error {
	head, err := s.migrationSource.ResolveMemoryMigrationHead(ctx, repository, plan.Branch)
	if err != nil {
		return err
	}
	head, err = normalizeMemoryMigrationSHA(head)
	if err != nil || head != plan.HeadCommitSHA {
		return conflict("memory migration source branch changed after preflight")
	}
	return nil
}

func exactMemoryMigrationBranch(memory memorystore.Memory, repository reposstore.ResourceRepository, requested string) (string, error) {
	bound := strings.TrimSpace(memory.Branch)
	if bound == "" {
		return "", conflict("memory migration bound branch is missing")
	}
	if repositoryBranch := strings.TrimSpace(repository.DefaultRef); repositoryBranch != "" && repositoryBranch != bound {
		return "", conflict("memory migration repository branch does not match Memory binding")
	}
	if requested = strings.TrimSpace(requested); requested != "" && requested != bound {
		return "", conflict("memory migration request branch does not match Memory binding")
	}
	return bound, nil
}

func (s *MemoryService) revalidateMemoryMigrationRun(ctx context.Context, run memoryMigrationRun) error {
	memory, err := s.GetMemory(ctx, run.workspaceID, run.actor, run.memoryID)
	if err != nil {
		return err
	}
	if !memory.CanManage {
		return forbidden("memory content migration requires manage access")
	}
	if strings.TrimSpace(memory.Branch) != run.boundBranch {
		return conflict("memory migration bound branch changed after preflight")
	}
	repository, err := s.repositoryStore.Get(ctx, run.workspaceID, reposstore.ResourceTypeMemory, run.memoryID, reposstore.RepoRolePrimary)
	if err != nil {
		return conflict("memory migration primary repository changed after preflight")
	}
	if !sameMemoryMigrationRepository(repository, run.repositoryBinding) {
		return conflict("memory migration primary repository changed after preflight")
	}
	if err := s.requireLegacyMemoryMigrationAuthority(ctx, run.workspaceID, run.memoryID); err != nil {
		return err
	}
	return s.revalidateMemoryMigrationHead(ctx, repos.IdentityFromStore(repository), run.plan)
}

func sameMemoryMigrationRepository(left, right reposstore.ResourceRepository) bool {
	return left.ID == right.ID && left.WorkspaceID == right.WorkspaceID && left.ResourceType == right.ResourceType && left.ResourceID == right.ResourceID && left.RepoRole == right.RepoRole &&
		left.OwnerKind == right.OwnerKind && left.RepoOwner == right.RepoOwner && left.RepoName == right.RepoName && left.RepoFullName == right.RepoFullName && left.AGSRepoID == right.AGSRepoID && left.DefaultRef == right.DefaultRef
}

func (s *MemoryService) ensureMemoryMigrationContent(ctx context.Context, workspaceID string, memory memorystore.Memory, actor string) (contentservice.Content, error) {
	request := NativeMemoryContentRequest{WorkspaceID: workspaceID, MemoryID: memory.ID, Actor: actor}
	readCtx, cancel := boundedMemoryContentContext(memoryContentContext(ctx, request, contentservice.AccessReadMetadata))
	defer cancel()
	content, found, err := s.migrationContent.FindContentByBinding(readCtx, workspaceID, memoryContentDomain, memory.ID)
	if err != nil {
		return contentservice.Content{}, mapNativeMemoryContentError(err)
	}
	if !found {
		createCtx, createCancel := boundedMemoryContentContext(memoryContentContext(ctx, request, contentservice.AccessCreateLineage))
		content, err = s.migrationContent.CreateContent(createCtx, contentservice.CreateContentRequest{
			WorkspaceID: workspaceID, Domain: memoryContentDomain, BindingKey: memory.ID,
			Model: contentservice.TreeModel, Actor: actor, Quota: memoryMigrationQuota,
		})
		createCancel()
		if err != nil && contentservice.IsBindingConflict(err) {
			content, found, err = s.migrationContent.FindContentByBinding(readCtx, workspaceID, memoryContentDomain, memory.ID)
			if err == nil && !found {
				err = migrationstore.ErrMigrationConflict
			}
		}
		if err != nil {
			return contentservice.Content{}, mapNativeMemoryContentError(err)
		}
	}
	if err := validateMemoryContentQuotaProfile(content); err != nil {
		return contentservice.Content{}, err
	}
	if content.Generation != 1 || content.Domain != memoryContentDomain || content.BindingKey != memory.ID || content.Model != contentservice.TreeModel {
		return contentservice.Content{}, conflict("memory migration lineage is inconsistent")
	}
	if memory.ContentID != "" && memory.ContentID != content.ID {
		return contentservice.Content{}, conflict("memory migration product lineage is inconsistent")
	}
	return content, nil
}

func (s *MemoryService) getMemoryMigrationContent(ctx context.Context, workspaceID, memoryID, contentID string, generation uint64, actor string) (contentservice.Content, error) {
	readCtx, cancel := boundedMemoryContentContext(memoryContentContext(ctx, NativeMemoryContentRequest{
		WorkspaceID: workspaceID, MemoryID: memoryID, ContentID: contentID, Generation: generation, Actor: actor,
	}, contentservice.AccessReadMetadata))
	defer cancel()
	content, err := s.migrationContent.GetContent(readCtx, workspaceID, contentID)
	if err != nil {
		return contentservice.Content{}, mapNativeMemoryContentError(err)
	}
	if content.Generation != generation || content.ID != contentID {
		return contentservice.Content{}, conflict("memory migration lineage generation changed")
	}
	return content, nil
}

func (s *MemoryService) memoryMigrationExporter(repository repos.RepositoryIdentity, planned MemoryMigrationPlanVersion) migration.Exporter {
	return func(ctx context.Context, limits contentpayload.Limits) (migration.Export, error) {
		files, err := s.migrationSource.ReadMemoryMigrationSnapshot(ctx, repository, planned.CommitSHA, limits)
		if err != nil {
			return migration.Export{}, err
		}
		digest, sizeBytes, err := validateMemoryMigrationSnapshot(files)
		if err != nil {
			return migration.Export{}, err
		}
		if digest != planned.RootDigest || len(files) != planned.FileCount || sizeBytes != planned.SizeBytes {
			return migration.Export{}, conflict("memory migration snapshot changed after preflight")
		}
		exported := make([]migration.File, len(files))
		for index := range files {
			exported[index] = migration.File{Path: files[index].Path, Data: files[index].Data, Executable: files[index].Executable}
		}
		return migration.Export{Files: exported}, nil
	}
}

func (s *MemoryService) memoryMigrationProjector(workspaceID, memoryID, repositoryID, contentID, actor string, planned MemoryMigrationPlanVersion, parentVersionID string, generation uint64) migration.Projector {
	return func(ctx context.Context, result migration.Result) error {
		if err := validateMemoryMigrationResult(result, planned, contentID); err != nil {
			return err
		}
		checkpointID, err := identifiers.NewEntityID("mcp")
		if err != nil {
			return err
		}
		_, err = s.store.CreateMemoryContentCheckpoint(ctx, memorystore.MemoryContentCheckpoint{
			ID: checkpointID, WorkspaceID: workspaceID, MemoryID: memoryID, ContentID: result.ContentID,
			ContentVersionID: result.VersionID, ParentContentVersionID: parentVersionID,
			OperationID: memoryMigrationOperationID(repositoryID, planned.CommitSHA), OperationKind: "import", Generation: generation,
			HistorySequence: planned.HistorySequence,
			RootDigest:      result.RootDigest, FileCount: result.FileCount, SizeBytes: result.SizeBytes,
			SourceAuthorName: planned.Source.AuthorName, SourceAuthorEmail: planned.Source.AuthorEmail,
			SourceAuthoredAt: &planned.AuthoredAt, SourceMessage: planned.Source.Message,
			CreatedBy: actor, CreatedAt: planned.AuthoredAt,
		})
		return err
	}
}

func (s *MemoryService) loadProjectedMemoryMigration(ctx context.Context, workspaceID, memoryID, actor, repositoryID string, content contentservice.Content, planned MemoryMigrationPlanVersion, parentVersionID string) (migration.Result, bool, error) {
	mapping, err := s.migrationMappings.GetMapping(ctx, repositoryID, planned.CommitSHA)
	if errors.Is(err, gorm.ErrRecordNotFound) {
		return migration.Result{}, false, nil
	}
	if err != nil {
		return migration.Result{}, false, err
	}
	if mapping.WorkspaceID != workspaceID || mapping.RepositoryID != repositoryID || mapping.CommitSHA != planned.CommitSHA ||
		mapping.ContentID != content.ID || mapping.Model != contentservice.TreeModel || mapping.RootDigest != planned.RootDigest ||
		mapping.FileCount != planned.FileCount || mapping.SizeBytes != planned.SizeBytes || mapping.VerifiedAt == nil {
		return migration.Result{}, false, conflict("memory migration durable mapping is inconsistent")
	}
	readCtx, cancel := boundedMemoryContentContext(memoryContentContext(ctx, NativeMemoryContentRequest{
		WorkspaceID: workspaceID, MemoryID: memoryID, ContentID: content.ID, Generation: content.Generation, Actor: actor,
	}, contentservice.AccessReadMetadata))
	defer cancel()
	version, err := s.migrationContent.GetVersion(readCtx, workspaceID, content.ID, mapping.ContentVersionID)
	if err != nil {
		return migration.Result{}, false, mapNativeMemoryContentError(err)
	}
	if version.ContentID != content.ID || version.ParentVersionID != parentVersionID || version.Generation != content.Generation ||
		version.Model != contentservice.TreeModel || version.RootDigest != planned.RootDigest || version.FileCount != planned.FileCount || version.SizeBytes != planned.SizeBytes {
		return migration.Result{}, false, conflict("memory migration mapped version is inconsistent")
	}
	result := migration.Result{
		ContentID: content.ID, VersionID: version.ID, RootDigest: version.RootDigest,
		FileCount: version.FileCount, SizeBytes: version.SizeBytes, Replayed: true,
	}
	checkpoint, found, err := s.store.FindMemoryCheckpointByContentVersion(ctx, workspaceID, memoryID, content.ID, version.ID)
	if err != nil {
		return migration.Result{}, false, err
	}
	if !found {
		return result, false, nil
	}
	if checkpoint.ParentContentVersionID != parentVersionID || checkpoint.OperationID != memoryMigrationOperationID(repositoryID, planned.CommitSHA) ||
		checkpoint.OperationKind != "import" || checkpoint.Generation != content.Generation || checkpoint.HistorySequence != planned.HistorySequence || checkpoint.RootDigest != planned.RootDigest ||
		checkpoint.FileCount != planned.FileCount || checkpoint.SizeBytes != planned.SizeBytes || checkpoint.SourceAuthorName != planned.Source.AuthorName ||
		checkpoint.SourceAuthorEmail != planned.Source.AuthorEmail || checkpoint.SourceAuthoredAt == nil || !checkpoint.SourceAuthoredAt.Equal(planned.AuthoredAt) || checkpoint.SourceMessage != planned.Source.Message || !checkpoint.CreatedAt.Equal(planned.AuthoredAt) {
		return migration.Result{}, false, conflict("memory migration checkpoint projection is inconsistent")
	}
	return result, true, nil
}

func memoryMigrationParentVersionID(planned MemoryMigrationPlanVersion, versions map[string]migration.Result) (string, error) {
	if planned.ParentCommitSHA == "" {
		return "", nil
	}
	parent := versions[planned.ParentCommitSHA]
	if parent.VersionID == "" {
		return "", conflict("memory migration retained parent mapping is missing")
	}
	return parent.VersionID, nil
}

func validateMemoryMigrationResult(result migration.Result, planned MemoryMigrationPlanVersion, contentID string) error {
	if strings.TrimSpace(result.ContentID) == "" || strings.TrimSpace(result.VersionID) == "" ||
		(strings.TrimSpace(contentID) != "" && result.ContentID != contentID) || result.RootDigest != planned.RootDigest ||
		result.FileCount != planned.FileCount || result.SizeBytes != planned.SizeBytes {
		return conflict("memory migration publication does not match preflight")
	}
	return nil
}

func memoryMigrationOperationID(repositoryID, commitSHA string) string {
	hash := sha256.New()
	writeMemoryOperationPart(hash, []byte(strings.TrimSpace(repositoryID)))
	writeMemoryOperationPart(hash, []byte(strings.TrimSpace(commitSHA)))
	return "memory-import:" + hex.EncodeToString(hash.Sum(nil))
}

func (s *MemoryService) ensureMemoryMigrationPins(ctx context.Context, workspaceID, memoryID, actor string, content contentservice.Content, plan MemoryMigrationPreflight, versions map[string]migration.Result) (int, error) {
	pinCtx, cancel := boundedMemoryContentContext(memoryContentContext(ctx, NativeMemoryContentRequest{
		WorkspaceID: workspaceID, MemoryID: memoryID, ContentID: content.ID, Generation: content.Generation, Actor: actor,
	}, contentservice.AccessManagePin))
	defer cancel()
	pins, err := s.migrationContent.ListPins(pinCtx, workspaceID, content.ID, int(memoryContentMaxPins))
	if err != nil {
		return 0, mapNativeMemoryContentError(err)
	}
	byLabel := make(map[string]contentservice.Pin, len(pins))
	for _, pin := range pins {
		if existing, duplicate := byLabel[pin.Label]; duplicate && existing.VersionID != pin.VersionID {
			return 0, conflict("memory migration backup label is ambiguous")
		}
		byLabel[pin.Label] = pin
	}
	created := 0
	for _, reference := range plan.References {
		if reference.Kind != "backup" {
			continue
		}
		version := versions[reference.CommitSHA]
		if version.VersionID == "" {
			return 0, conflict("memory migration backup target mapping is missing")
		}
		if existing, ok := byLabel[reference.Label]; ok {
			if existing.VersionID != version.VersionID {
				return 0, conflict("memory migration backup label changed target")
			}
			continue
		}
		if len(byLabel) >= int(memoryContentMaxPins) {
			return 0, conflict("memory migration backup quota exceeded")
		}
		pin, err := s.migrationContent.CreatePin(pinCtx, contentservice.CreatePinRequest{
			WorkspaceID: workspaceID, ContentID: content.ID, VersionID: version.VersionID, Label: reference.Label, Actor: actor,
		})
		if err != nil {
			if !contentservice.IsConflict(err) {
				return 0, mapNativeMemoryContentError(err)
			}
			reloaded, reloadErr := s.migrationContent.ListPins(pinCtx, workspaceID, content.ID, int(memoryContentMaxPins))
			if reloadErr != nil {
				return 0, mapNativeMemoryContentError(reloadErr)
			}
			matched := false
			for _, candidate := range reloaded {
				if candidate.Label == reference.Label && candidate.VersionID == version.VersionID {
					pin = candidate
					matched = true
					break
				}
			}
			if !matched {
				return 0, conflict("memory migration backup pin conflicted")
			}
		}
		byLabel[reference.Label] = pin
		created++
	}
	return created, nil
}
