package permissions

import (
	"context"
	"encoding/json"
	"fmt"
	"slices"
	"sort"
	"strings"
	"unicode/utf8"

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

const (
	assignmentPolicyOperationMaximumActorBytes  = 255
	assignmentPolicyOperationMaximumReasonBytes = 1024
)

// AssignmentPolicyOperation is an internal trusted operation. These values are
// deliberately not exposed as record or HTTP operations; the single-process
// runtime adapter is their only intended consumer.
type AssignmentPolicyOperation string

const (
	AssignmentPolicyOperationReconcile AssignmentPolicyOperation = "reconcile"
	AssignmentPolicyOperationRepair    AssignmentPolicyOperation = "repair"
	AssignmentPolicyOperationSuspend   AssignmentPolicyOperation = "suspend"
	AssignmentPolicyOperationResume    AssignmentPolicyOperation = "resume"
)

// AssignmentPolicyOperationRequest identifies one target-started operation.
// Actor and Reason are attribution, not authorization; the caller must already
// be a trusted runtime path before it can construct this request.
type AssignmentPolicyOperationRequest struct {
	PermissionSet string
	Operation     AssignmentPolicyOperation
	Actor         string
	Reason        string
}

type assignmentPolicyOperationPlan struct {
	Request             AssignmentPolicyOperationRequest `json:"request"`
	TargetID            string                           `json:"targetId"`
	TargetName          string                           `json:"targetName"`
	DefinitionOwnerPack string                           `json:"definitionOwnerPack"`
	ClaimID             string                           `json:"claimId"`
	OwnerPack           string                           `json:"ownerPack"`
	PolicyKey           string                           `json:"policyKey"`
	Profiles            []string                         `json:"profiles"`
	Eligible            []string                         `json:"eligible"`
	ActiveAssignments   []string                         `json:"activeAssignments"`
	DeletedAssignments  []string                         `json:"deletedAssignments"`
	State               assignmentPolicyOperationState   `json:"state"`
	Resolution          string                           `json:"resolution"`
	EligibilityItems    int                              `json:"eligibilityItems"`
	Desired             []string                         `json:"desired"`
	FinalAssignmentRows int                              `json:"finalAssignmentRows"`
	FinalGeneration     uint64                           `json:"finalGeneration"`
	FinalSuspended      bool                             `json:"finalSuspended"`
	AssignmentWrites    int                              `json:"assignmentWrites"`
	StateWrite          bool                             `json:"stateWrite"`
	SafeProjection      bool                             `json:"safeProjection"`
}

type assignmentPolicyOperationState struct {
	ID                string `json:"id"`
	Suspended         bool   `json:"suspended"`
	WorkGeneration    uint64 `json:"workGeneration"`
	AppliedGeneration uint64 `json:"appliedGeneration"`
	ResolutionState   string `json:"resolutionState"`
}

type assignmentPolicyOperationSnapshot struct {
	TargetID            string
	TargetName          string
	DefinitionOwnerPack string
	ClaimID             string
	OwnerPack           string
	PolicyKey           string
	Profiles            []string
	Eligible            []string
	ActiveAssignments   []string
	DeletedAssignments  []string
	State               assignmentPolicyOperationState
	Resolution          string
	EligibilityItems    int
	CurrentItems        int
}

// PlanAssignmentPolicyOperationWithEligibility plans one target-started
// operation through the product-owned opaque eligibility projection.
func PlanAssignmentPolicyOperationWithEligibility(
	ctx context.Context,
	store cp.ComponentManagedReadStore,
	request AssignmentPolicyOperationRequest,
	eligibility AssignmentPolicyEligibilityProjectionProvider,
) (cp.ComponentManagedPlan, error) {
	if store == nil {
		return cp.ComponentManagedPlan{}, fmt.Errorf("assignment policy operation read store is required")
	}
	if err := validateAssignmentPolicyOperationRequest(request); err != nil {
		return cp.ComponentManagedPlan{}, err
	}
	snapshot, err := readAssignmentPolicyOperationSnapshot(
		ctx,
		store,
		request.PermissionSet,
		assignmentPolicyManagedBudget().MaxCurrentItems,
		eligibility,
	)
	if err != nil {
		return cp.ComponentManagedPlan{}, err
	}
	if request.Operation == AssignmentPolicyOperationResume && !snapshot.State.Suspended {
		return cp.ComponentManagedPlan{}, fmt.Errorf("assignment policy target is not suspended")
	}

	finalSuspended := snapshot.State.Suspended
	switch request.Operation {
	case AssignmentPolicyOperationSuspend:
		finalSuspended = true
	case AssignmentPolicyOperationResume:
		finalSuspended = snapshot.Resolution != assignmentPolicyResolutionResolved
	}
	desired := append([]string(nil), snapshot.Eligible...)
	if finalSuspended || snapshot.Resolution != assignmentPolicyResolutionResolved {
		desired = nil
	} else {
		desired = assignmentPolicyRetainedOperationSubjectIDs(
			desired,
			snapshot.ActiveAssignments,
			snapshot.DeletedAssignments,
		)
	}
	assignmentWrites, missingAssignments := assignmentPolicyOperationAssignmentWrites(
		snapshot.ActiveAssignments, snapshot.DeletedAssignments, desired,
	)
	suspensionChanged := finalSuspended != snapshot.State.Suspended
	semanticStateChanged := assignmentWrites > 0 || suspensionChanged ||
		snapshot.State.ResolutionState != snapshot.Resolution
	stateWrite := semanticStateChanged ||
		snapshot.State.WorkGeneration != snapshot.State.AppliedGeneration
	finalGeneration := snapshot.State.WorkGeneration
	if stateWrite && snapshot.State.WorkGeneration == snapshot.State.AppliedGeneration {
		finalGeneration, err = nextAssignmentPolicyGeneration(snapshot.State.WorkGeneration)
		if err != nil {
			return cp.ComponentManagedPlan{}, err
		}
	}
	finalAssignmentRows := len(snapshot.ActiveAssignments) +
		len(snapshot.DeletedAssignments) + missingAssignments
	plan := assignmentPolicyOperationPlan{
		Request:             request,
		TargetID:            snapshot.TargetID,
		TargetName:          snapshot.TargetName,
		DefinitionOwnerPack: snapshot.DefinitionOwnerPack,
		ClaimID:             snapshot.ClaimID,
		OwnerPack:           snapshot.OwnerPack,
		PolicyKey:           snapshot.PolicyKey,
		Profiles:            append([]string(nil), snapshot.Profiles...),
		Eligible:            append([]string(nil), snapshot.Eligible...),
		ActiveAssignments:   append([]string(nil), snapshot.ActiveAssignments...),
		DeletedAssignments:  append([]string(nil), snapshot.DeletedAssignments...),
		State:               snapshot.State,
		Resolution:          snapshot.Resolution,
		EligibilityItems:    snapshot.EligibilityItems,
		Desired:             desired,
		FinalAssignmentRows: finalAssignmentRows,
		FinalGeneration:     finalGeneration,
		FinalSuspended:      finalSuspended,
		AssignmentWrites:    assignmentWrites,
		StateWrite:          stateWrite,
		SafeProjection:      finalSuspended || snapshot.Resolution != assignmentPolicyResolutionResolved,
	}
	opaque, err := json.Marshal(plan)
	if err != nil {
		return cp.ComponentManagedPlan{}, fmt.Errorf("encode assignment policy operation plan: %w", err)
	}
	source, err := NewPermissionSetAssignmentPolicySource(snapshot.OwnerPack, snapshot.PolicyKey)
	if err != nil {
		return cp.ComponentManagedPlan{}, err
	}
	targets, err := source.ManagedTargets(PermissionSetAssignmentPolicy{PermissionSet: snapshot.TargetName})
	if err != nil {
		return cp.ComponentManagedPlan{}, err
	}
	targets = append(targets, PermissionSetAssignmentPolicySerializationTarget())
	estimate := estimateAssignmentPolicyOperation(plan, snapshot.CurrentItems)
	if err := validateAssignmentPolicyOperationEstimate(estimate); err != nil {
		return cp.ComponentManagedPlan{}, err
	}
	effects := []cp.ComponentManagedEffectRequirement{}
	if semanticStateChanged {
		effects = assignmentPolicyEffects()
	}
	return cp.NewComponentManagedPlan(cp.ComponentManagedPlanSpec{
		Targets:              targets,
		RequiredCapabilities: assignmentPolicyCapabilities(),
		Estimate:             estimate,
		Effects:              effects,
		ProjectionIdentity: []byte(
			string(PermissionSetAssignmentPolicyComponentKind) + "\x00operator\x00" +
				string(request.Operation) + "\x00" + strings.ToLower(snapshot.TargetName),
		),
		OpaquePlan: opaque,
	})
}

// PermissionSetAssignmentPolicyTransactionOperationProviderWithEligibility
// binds the product projection while preserving caller-owned transaction
// boundaries.
func PermissionSetAssignmentPolicyTransactionOperationProviderWithEligibility(
	eligibility AssignmentPolicyEligibilityProjectionProvider,
) cp.ComponentManagedTransactionOperationProvider {
	return cp.ComponentManagedTransactionOperationProvider{
		Mutate: func(
			ctx context.Context,
			plan cp.ComponentManagedPlan,
			store cp.ComponentManagedTransactionMutationStore,
		) (cp.ComponentManagedMutationResult, error) {
			return mutateAssignmentPolicyOperation(ctx, plan, store, eligibility)
		},
		Project: func(
			ctx context.Context,
			plan cp.ComponentManagedPlan,
			store cp.ComponentManagedTransactionReadStore,
		) (cp.ComponentManagedProjection, error) {
			return projectAssignmentPolicyOperation(ctx, plan, store, eligibility)
		},
	}
}

// NewPermissionSetAssignmentPolicyPlannedOperationProviderWithEligibility
// freezes one operation and its product-owned eligibility projection.
func NewPermissionSetAssignmentPolicyPlannedOperationProviderWithEligibility(
	request AssignmentPolicyOperationRequest,
	eligibility AssignmentPolicyEligibilityProjectionProvider,
) cp.ComponentManagedPlannedTransactionOperationProvider {
	provider := PermissionSetAssignmentPolicyTransactionOperationProviderWithEligibility(eligibility)
	return cp.ComponentManagedPlannedTransactionOperationProvider{
		Plan: func(ctx context.Context, store cp.ComponentManagedTransactionReadStore) (cp.ComponentManagedPlan, error) {
			return PlanAssignmentPolicyOperationWithEligibility(ctx, store, request, eligibility)
		},
		Mutate:  provider.Mutate,
		Project: provider.Project,
	}
}

func mutateAssignmentPolicyOperation(
	ctx context.Context,
	planEnvelope cp.ComponentManagedPlan,
	store cp.ComponentManagedTransactionMutationStore,
	eligibility AssignmentPolicyEligibilityProjectionProvider,
) (cp.ComponentManagedMutationResult, error) {
	if store == nil {
		return cp.ComponentManagedMutationResult{}, fmt.Errorf("assignment policy operation mutation store is required")
	}
	decoded, err := decodeAssignmentPolicyOperationPlan(planEnvelope)
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	if err := lockAssignmentPolicyRoots(ctx, store, []assignmentPolicyRootLock{{
		PermissionSetID: decoded.TargetID,
		PermissionSet:   decoded.TargetName,
		OwnerPack:       decoded.DefinitionOwnerPack,
	}}); err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	claimRows, err := store.LockRows(ctx, assignmentPolicyQuery(
		schemacatalog.AssignmentPolicyClaimTable,
		[]string{"Id", "PermissionSetId", "OwnerPack", "PolicyKey"},
		cp.ComponentRow{"PermissionSetId": decoded.TargetID}, 1, []string{"PermissionSetId"},
	))
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	if len(claimRows) != 1 {
		return cp.ComponentManagedMutationResult{}, fmt.Errorf("assignment policy claim disappeared")
	}
	claimID, err := assignmentPolicyRequiredString(claimRows[0], "Id")
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	ownerPack, err := assignmentPolicyRequiredString(claimRows[0], "OwnerPack")
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	policyKey, err := assignmentPolicyRequiredString(claimRows[0], "PolicyKey")
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	if claimID != decoded.ClaimID || ownerPack != decoded.OwnerPack || policyKey != decoded.PolicyKey {
		return cp.ComponentManagedMutationResult{}, fmt.Errorf("assignment policy authority changed after locked planning")
	}
	selectorRows, exceeded, err := lockAssignmentPolicyRowsUpTo(
		ctx,
		store,
		assignmentPolicyOperationSelectorQuery(decoded.TargetID),
		len(decoded.Profiles),
	)
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	if exceeded {
		return cp.ComponentManagedMutationResult{}, fmt.Errorf(
			"assignment policy operation selector population grew after locked planning",
		)
	}
	profiles, err := assignmentPolicyOperationProfilesFromRows(decoded.TargetID, selectorRows)
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	if !slices.Equal(profiles, decoded.Profiles) {
		return cp.ComponentManagedMutationResult{}, fmt.Errorf(
			"assignment policy operation selector population changed after locked planning",
		)
	}
	stateRows, err := store.LockRows(ctx, assignmentPolicyQuery(
		schemacatalog.AssignmentPolicyTargetStateTable,
		[]string{
			"Id", "TargetDomain", "PhysicalKey", "PermissionSetId", "Suspended",
			"WorkGeneration", "AppliedGeneration", "ResolutionState",
		},
		cp.ComponentRow{"PermissionSetId": decoded.TargetID}, 1, []string{"PermissionSetId"},
	))
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	if len(stateRows) != 1 {
		return cp.ComponentManagedMutationResult{}, fmt.Errorf("assignment policy target state disappeared")
	}
	if err := assignmentPolicyValidateTargetStateIdentity(
		stateRows[0], decoded.TargetID, decoded.TargetName,
	); err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	state, err := assignmentPolicyStateFromRow(stateRows[0])
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	if state.ID != decoded.State.ID || state.Suspended != decoded.State.Suspended ||
		state.WorkGeneration != decoded.State.WorkGeneration ||
		state.AppliedGeneration != decoded.State.AppliedGeneration ||
		state.ResolutionState != decoded.State.ResolutionState {
		return cp.ComponentManagedMutationResult{}, fmt.Errorf("assignment policy target state changed after locked planning")
	}
	assignmentRows, exceeded, err := lockAssignmentPolicyRowsUpTo(
		ctx,
		store,
		assignmentPolicyOperationAssignmentQuery(decoded.TargetID),
		len(decoded.ActiveAssignments)+len(decoded.DeletedAssignments),
	)
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	if exceeded {
		return cp.ComponentManagedMutationResult{}, fmt.Errorf(
			"assignment policy operation assignment population grew after locked planning",
		)
	}
	active, deleted, err := assignmentPolicyOperationAssignmentSets(assignmentRows)
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	if !slices.Equal(active, decoded.ActiveAssignments) ||
		!slices.Equal(deleted, decoded.DeletedAssignments) {
		return cp.ComponentManagedMutationResult{}, fmt.Errorf(
			"assignment policy operation assignment population changed after locked planning",
		)
	}
	resolution, _, eligible, eligibilityItems, err := projectAssignmentPolicyEligibility(
		ctx,
		store,
		decoded.TargetID,
		profiles,
		eligibility,
		newAssignmentPolicyEligibilityReadBudget(decoded.EligibilityItems),
	)
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	if eligibilityItems != decoded.EligibilityItems ||
		resolution != decoded.Resolution || !slices.Equal(eligible, decoded.Eligible) {
		return cp.ComponentManagedMutationResult{}, fmt.Errorf(
			"assignment policy operation eligibility population changed after locked planning",
		)
	}
	assignmentChanged, err := reconcileAssignmentPolicyAssignmentRows(
		ctx,
		store,
		decoded.OwnerPack,
		decoded.PolicyKey,
		decoded.TargetID,
		decoded.FinalGeneration,
		false,
		nil,
		false,
		assignmentRows,
		decoded.Desired,
	)
	if err != nil {
		return cp.ComponentManagedMutationResult{}, err
	}
	if assignmentChanged != decoded.AssignmentWrites {
		return cp.ComponentManagedMutationResult{}, fmt.Errorf(
			"assignment policy operation wrote %d assignment rows, planned %d",
			assignmentChanged, decoded.AssignmentWrites,
		)
	}
	changed := assignmentChanged
	if decoded.StateWrite {
		values := cp.ComponentRow{
			"WorkGeneration":    decoded.FinalGeneration,
			"AppliedGeneration": decoded.FinalGeneration,
			"ResolutionState":   decoded.Resolution,
			"ResolutionDigest":  assignmentPolicyDigest(decoded.Resolution),
			"RetryCount":        uint64(0),
			"LastFailureCode":   nil,
			"LastFailureDigest": nil,
			"NextAttemptAt":     nil,
		}
		timestamps := []string{"LastModifiedDate"}
		if decoded.FinalSuspended != decoded.State.Suspended {
			values["Suspended"] = decoded.FinalSuspended
			if decoded.FinalSuspended {
				values["SuspensionActor"] = decoded.Request.Actor
				values["SuspensionReason"] = decoded.Request.Reason
				timestamps = append(timestamps, "SuspendedAt")
			} else {
				values["SuspensionActor"] = nil
				values["SuspensionReason"] = nil
				values["SuspendedAt"] = nil
			}
		}
		updated, updateErr := store.UpdateRows(ctx, cp.ComponentManagedUpdate{
			Table:                   schemacatalog.AssignmentPolicyTargetStateTable,
			Match:                   cp.ComponentRow{"Id": decoded.State.ID},
			Values:                  values,
			CurrentTimestampColumns: timestamps,
			MaximumAffectedRows:     1,
		})
		if err := assignmentPolicyRequireExactWrite(
			"update", schemacatalog.AssignmentPolicyTargetStateTable, updated, updateErr,
		); err != nil {
			return cp.ComponentManagedMutationResult{}, err
		}
		changed++
	}
	if changed == 0 {
		return cp.ComponentManagedMutationResult{Disposition: cp.ComponentManagedMutationNoChange}, nil
	}
	disposition := cp.ComponentManagedMutationDesiredProjectionStaged
	if decoded.SafeProjection {
		disposition = cp.ComponentManagedMutationSafeProjectionStaged
	}
	return cp.ComponentManagedMutationResult{Disposition: disposition}, nil
}

func projectAssignmentPolicyOperation(
	ctx context.Context,
	planEnvelope cp.ComponentManagedPlan,
	store cp.ComponentManagedTransactionReadStore,
	eligibility AssignmentPolicyEligibilityProjectionProvider,
) (cp.ComponentManagedProjection, error) {
	if store == nil {
		return cp.ComponentManagedProjection{}, fmt.Errorf("assignment policy operation projection store is required")
	}
	decoded, err := decodeAssignmentPolicyOperationPlan(planEnvelope)
	if err != nil {
		return cp.ComponentManagedProjection{}, err
	}
	snapshot, err := readAssignmentPolicyOperationSnapshot(
		ctx,
		store,
		decoded.TargetName,
		assignmentPolicyManagedBudget().MaxCurrentItems,
		eligibility,
	)
	if err != nil {
		return cp.ComponentManagedProjection{}, err
	}
	if snapshot.TargetID != decoded.TargetID || snapshot.DefinitionOwnerPack != decoded.DefinitionOwnerPack ||
		snapshot.ClaimID != decoded.ClaimID ||
		snapshot.OwnerPack != decoded.OwnerPack || snapshot.PolicyKey != decoded.PolicyKey {
		return cp.ComponentManagedProjection{}, fmt.Errorf("assignment policy operation projection authority changed")
	}
	if len(snapshot.ActiveAssignments)+len(snapshot.DeletedAssignments) != decoded.FinalAssignmentRows {
		return cp.ComponentManagedProjection{}, fmt.Errorf(
			"assignment policy operation projection assignment population changed",
		)
	}
	liveSnapshot := assignmentPolicyTargetSnapshot{
		PermissionSetID:     snapshot.TargetID,
		PermissionSet:       snapshot.TargetName,
		DefinitionOwnerPack: snapshot.DefinitionOwnerPack,
		ClaimID:             snapshot.ClaimID,
		OwnerPack:           snapshot.OwnerPack,
		PolicyKey:           snapshot.PolicyKey,
		Profiles:            append([]string(nil), snapshot.Profiles...),
		Eligible:            append([]string(nil), snapshot.Eligible...),
		Assignments:         make(map[string]assignmentPolicyAssignmentRow),
		State: &assignmentPolicyStateRow{
			ID:                snapshot.State.ID,
			Suspended:         snapshot.State.Suspended,
			WorkGeneration:    snapshot.State.WorkGeneration,
			AppliedGeneration: snapshot.State.AppliedGeneration,
			ResolutionState:   snapshot.State.ResolutionState,
		},
		Resolution: snapshot.Resolution,
	}
	for _, assignee := range snapshot.ActiveAssignments {
		liveSnapshot.Assignments[assignmentPolicyDatabaseIdentity(assignee)] = assignmentPolicyAssignmentRow{
			Assignee: assignee,
		}
	}
	for _, assignee := range snapshot.DeletedAssignments {
		liveSnapshot.Assignments[assignmentPolicyDatabaseIdentity(assignee)] = assignmentPolicyAssignmentRow{
			Assignee: assignee, IsDeleted: true,
		}
	}
	live := assignmentPolicyProjectionFromSnapshot(
		liveSnapshot,
		true,
		snapshot.OwnerPack,
		snapshot.PolicyKey,
		snapshot.Profiles,
		snapshot.Eligible,
		snapshot.Resolution,
	)
	expected := live
	if !decoded.FinalSuspended && decoded.Resolution == assignmentPolicyResolutionResolved {
		expected.EligibleAssignees = append([]string(nil), decoded.Eligible...)
	}
	expected.ActiveAssignments = append([]string{}, decoded.Desired...)
	expected.Suspended = decoded.FinalSuspended
	expected.ResolutionState = decoded.Resolution
	expected.WorkGeneration = decoded.FinalGeneration
	expected.AppliedGeneration = decoded.FinalGeneration
	expectedBytes, err := json.Marshal(expected)
	if err != nil {
		return cp.ComponentManagedProjection{}, fmt.Errorf("encode expected assignment policy operation projection: %w", err)
	}
	liveBytes, err := json.Marshal(live)
	if err != nil {
		return cp.ComponentManagedProjection{}, fmt.Errorf("encode live assignment policy operation projection: %w", err)
	}
	return cp.ComponentManagedProjection{
		Identity: planEnvelope.ProjectionIdentity(),
		Expected: expectedBytes,
		Live:     liveBytes,
	}, nil
}

func validateAssignmentPolicyOperationRequest(request AssignmentPolicyOperationRequest) error {
	if _, err := PermissionSetDefinitionManagedTarget(request.PermissionSet); err != nil {
		return fmt.Errorf("assignment policy operation target: %w", err)
	}
	switch request.Operation {
	case AssignmentPolicyOperationReconcile, AssignmentPolicyOperationRepair:
		if request.Actor != "" || request.Reason != "" {
			return fmt.Errorf("%s operation must not declare suspension attribution", request.Operation)
		}
	case AssignmentPolicyOperationSuspend:
		if err := validateAssignmentPolicyOperationAttribution(
			"actor", request.Actor, assignmentPolicyOperationMaximumActorBytes,
		); err != nil {
			return err
		}
		if err := validateAssignmentPolicyOperationAttribution(
			"reason", request.Reason, assignmentPolicyOperationMaximumReasonBytes,
		); err != nil {
			return err
		}
	case AssignmentPolicyOperationResume:
		if err := validateAssignmentPolicyOperationAttribution(
			"actor", request.Actor, assignmentPolicyOperationMaximumActorBytes,
		); err != nil {
			return err
		}
		if request.Reason != "" {
			return fmt.Errorf("resume operation must not declare a reason")
		}
	default:
		return fmt.Errorf("assignment policy operation %q is unsupported", request.Operation)
	}
	return nil
}

func validateAssignmentPolicyOperationAttribution(field, value string, maximumBytes int) error {
	if !utf8.ValidString(value) {
		return fmt.Errorf("assignment policy operation %s must be valid UTF-8", field)
	}
	if value == "" || len(value) > maximumBytes {
		return fmt.Errorf(
			"assignment policy operation %s must contain 1..%d bytes", field, maximumBytes,
		)
	}
	if strings.TrimSpace(value) != value {
		return fmt.Errorf("assignment policy operation %s must not have surrounding whitespace", field)
	}
	return nil
}

func readAssignmentPolicyOperationSnapshot(
	ctx context.Context,
	store cp.ComponentManagedReadStore,
	name string,
	maximumCurrentItems int,
	eligibility AssignmentPolicyEligibilityProjectionProvider,
) (assignmentPolicyOperationSnapshot, error) {
	if maximumCurrentItems <= 0 {
		return assignmentPolicyOperationSnapshot{}, fmt.Errorf("assignment policy operation current-item maximum is invalid")
	}
	snapshot := assignmentPolicyOperationSnapshot{}
	consume := func(count int) error {
		snapshot.CurrentItems += count
		if snapshot.CurrentItems > maximumCurrentItems {
			return fmt.Errorf(
				"assignment policy operation current items %d exceed registration budget %d",
				snapshot.CurrentItems, maximumCurrentItems,
			)
		}
		return nil
	}
	rootRows, err := store.ReadRows(ctx, assignmentPolicyRootQuery(cp.ComponentRow{"Name": name}))
	if err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	if err := consume(len(rootRows)); err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	if len(rootRows) != 1 {
		return assignmentPolicyOperationSnapshot{}, fmt.Errorf(
			"assignment policy target %q is not one live Permission Set Definition", name,
		)
	}
	snapshot.TargetID, snapshot.TargetName, snapshot.DefinitionOwnerPack, err =
		assignmentPolicyDefinitionRootFromRow(rootRows[0])
	if err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	claimRows, err := store.ReadRows(ctx, assignmentPolicyQuery(
		schemacatalog.AssignmentPolicyClaimTable,
		[]string{"Id", "PermissionSetId", "OwnerPack", "PolicyKey"},
		cp.ComponentRow{"PermissionSetId": snapshot.TargetID}, 1, nil,
	))
	if err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	if err := consume(len(claimRows)); err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	if len(claimRows) != 1 {
		return assignmentPolicyOperationSnapshot{}, fmt.Errorf(
			"Permission Set %s is not claimed by an assignment policy", snapshot.TargetName,
		)
	}
	snapshot.ClaimID, err = assignmentPolicyRequiredString(claimRows[0], "Id")
	if err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	snapshot.OwnerPack, err = assignmentPolicyRequiredString(claimRows[0], "OwnerPack")
	if err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	snapshot.PolicyKey, err = assignmentPolicyRequiredString(claimRows[0], "PolicyKey")
	if err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	remaining := maximumCurrentItems - snapshot.CurrentItems
	selectorLimit := min(remaining, assignmentPolicyMaximumSelectors)
	selectorRows, exceeded, err := readAssignmentPolicyRowsUpTo(
		ctx,
		store,
		assignmentPolicyOperationSelectorQuery(snapshot.TargetID),
		selectorLimit,
	)
	if err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	if err := consume(len(selectorRows)); err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	if exceeded {
		if selectorLimit < assignmentPolicyMaximumSelectors {
			return assignmentPolicyOperationSnapshot{}, fmt.Errorf(
				"assignment policy operation current items exceed registration budget %d",
				maximumCurrentItems,
			)
		}
		return assignmentPolicyOperationSnapshot{}, fmt.Errorf(
			"assignment policy target has more than %d selectors", assignmentPolicyMaximumSelectors,
		)
	}
	snapshot.Profiles, err = assignmentPolicyOperationProfilesFromRows(snapshot.TargetID, selectorRows)
	if err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	stateRows, err := store.ReadRows(ctx, assignmentPolicyQuery(
		schemacatalog.AssignmentPolicyTargetStateTable,
		[]string{
			"Id", "TargetDomain", "PhysicalKey", "PermissionSetId", "Suspended",
			"WorkGeneration", "AppliedGeneration", "ResolutionState",
		},
		cp.ComponentRow{"PermissionSetId": snapshot.TargetID}, 1, nil,
	))
	if err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	if err := consume(len(stateRows)); err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	if len(stateRows) != 1 {
		return assignmentPolicyOperationSnapshot{}, fmt.Errorf("assignment policy target state is missing")
	}
	if err := assignmentPolicyValidateTargetStateIdentity(
		stateRows[0], snapshot.TargetID, snapshot.TargetName,
	); err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	state, err := assignmentPolicyStateFromRow(stateRows[0])
	if err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	snapshot.State = assignmentPolicyOperationState{
		ID:                state.ID,
		Suspended:         state.Suspended,
		WorkGeneration:    state.WorkGeneration,
		AppliedGeneration: state.AppliedGeneration,
		ResolutionState:   state.ResolutionState,
	}
	assignmentRows, exceeded, err := readAssignmentPolicyRowsUpTo(
		ctx,
		store,
		assignmentPolicyOperationAssignmentQuery(snapshot.TargetID),
		maximumCurrentItems-snapshot.CurrentItems,
	)
	if err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	if err := consume(len(assignmentRows)); err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	if exceeded {
		return assignmentPolicyOperationSnapshot{}, fmt.Errorf(
			"assignment policy operation assignment population exceeds registration budget %d",
			maximumCurrentItems,
		)
	}
	snapshot.ActiveAssignments, snapshot.DeletedAssignments, err =
		assignmentPolicyOperationAssignmentSets(assignmentRows)
	if err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	resolution, _, eligible, eligibilityRows, err := projectAssignmentPolicyEligibility(
		ctx,
		store,
		snapshot.TargetID,
		snapshot.Profiles,
		eligibility,
		newAssignmentPolicyEligibilityReadBudget(
			maximumCurrentItems-snapshot.CurrentItems,
		),
	)
	if err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	if err := consume(eligibilityRows); err != nil {
		return assignmentPolicyOperationSnapshot{}, err
	}
	snapshot.Resolution = resolution
	snapshot.Eligible = eligible
	snapshot.EligibilityItems = eligibilityRows
	return snapshot, nil
}

func assignmentPolicyOperationAssignmentQuery(targetID string) cp.ComponentManagedRowQuery {
	return cp.ComponentManagedRowQuery{
		Table:   "PermissionSetAssignment",
		Columns: []string{"Id", "PermissionSetId", "AssigneeId", "IsDeleted", "LastModifiedDate"},
		Equal:   cp.ComponentRow{"PermissionSetId": targetID},
		OrderBy: []cp.ComponentManagedOrder{
			{Column: "PermissionSetId", Direction: cp.ComponentManagedOrderAscending},
			{Column: "AssigneeId", Direction: cp.ComponentManagedOrderAscending},
		},
		LogicalKeyColumns: []string{"PermissionSetId", "AssigneeId"},
		MaximumRows:       assignmentPolicyMaximumRows,
	}
}

func assignmentPolicyOperationSelectorQuery(targetID string) cp.ComponentManagedRowQuery {
	return cp.ComponentManagedRowQuery{
		Table:   schemacatalog.AssignmentPolicySelectorTable,
		Columns: []string{"PermissionSetId", "ProfileName"},
		Equal:   cp.ComponentRow{"PermissionSetId": targetID},
		OrderBy: []cp.ComponentManagedOrder{
			{Column: "PermissionSetId", Direction: cp.ComponentManagedOrderAscending},
			{Column: "ProfileName", Direction: cp.ComponentManagedOrderAscending},
		},
		LogicalKeyColumns: []string{"PermissionSetId", "ProfileName"},
		MaximumRows:       assignmentPolicyMaximumRows,
	}
}

func assignmentPolicyOperationProfilesFromRows(targetID string, rows []cp.ComponentRow) ([]string, error) {
	profiles := make([]string, 0, len(rows))
	for _, row := range rows {
		actualTargetID, err := assignmentPolicyRequiredString(row, "PermissionSetId")
		if err != nil {
			return nil, err
		}
		if actualTargetID != targetID {
			return nil, fmt.Errorf("assignment policy operation selector query returned another Permission Set")
		}
		profile, err := assignmentPolicyRequiredString(row, "ProfileName")
		if err != nil {
			return nil, err
		}
		profiles = append(profiles, profile)
	}
	sortAssignmentPolicyOperationIdentities(profiles)
	return profiles, nil
}

func assignmentPolicyOperationAssignmentSets(rows []cp.ComponentRow) ([]string, []string, error) {
	active := make([]string, 0, len(rows))
	deleted := make([]string, 0, len(rows))
	seen := make(map[string]struct{}, len(rows))
	for _, row := range rows {
		assignment, err := assignmentPolicyAssignmentFromRow(row)
		if err != nil {
			return nil, nil, err
		}
		key := assignmentPolicyDatabaseIdentity(assignment.Assignee)
		if _, duplicate := seen[key]; duplicate {
			return nil, nil, fmt.Errorf(
				"duplicate PermissionSetAssignment pair for %s", assignment.Assignee,
			)
		}
		seen[key] = struct{}{}
		if assignment.IsDeleted {
			deleted = append(deleted, assignment.Assignee)
		} else {
			active = append(active, assignment.Assignee)
		}
	}
	sortAssignmentPolicySubjectIDs(active)
	sortAssignmentPolicySubjectIDs(deleted)
	return active, deleted, nil
}

func assignmentPolicyOperationAssignmentWrites(active, deleted, desired []string) (int, int) {
	desiredSet := make(map[string]struct{}, len(desired))
	for _, assignee := range desired {
		desiredSet[assignmentPolicyDatabaseIdentity(assignee)] = struct{}{}
	}
	writes := 0
	for _, assignee := range active {
		key := assignmentPolicyDatabaseIdentity(assignee)
		if _, wanted := desiredSet[key]; !wanted {
			writes += 2
		}
		delete(desiredSet, key)
	}
	for _, assignee := range deleted {
		key := assignmentPolicyDatabaseIdentity(assignee)
		if _, wanted := desiredSet[key]; wanted {
			writes += 2
		}
		delete(desiredSet, key)
	}
	return writes + len(desiredSet), len(desiredSet)
}

func assignmentPolicyRetainedOperationSubjectIDs(
	desired, active, deleted []string,
) []string {
	current := make(map[string]string, len(active)+len(deleted))
	for _, subjectID := range active {
		current[assignmentPolicyDatabaseIdentity(subjectID)] = subjectID
	}
	for _, subjectID := range deleted {
		current[assignmentPolicyDatabaseIdentity(subjectID)] = subjectID
	}
	retained := make([]string, 0, len(desired))
	for _, subjectID := range desired {
		if existing, present := current[assignmentPolicyDatabaseIdentity(subjectID)]; present {
			retained = append(retained, existing)
			continue
		}
		retained = append(retained, subjectID)
	}
	sortAssignmentPolicySubjectIDs(retained)
	return retained
}

func estimateAssignmentPolicyOperation(
	plan assignmentPolicyOperationPlan,
	planCurrentItems int,
) cp.ComponentManagedUsage {
	assignmentRows := len(plan.ActiveAssignments) + len(plan.DeletedAssignments)
	projectCurrentItems := planCurrentItems - assignmentRows + plan.FinalAssignmentRows
	// One shared host attempt contains ambient Plan, locked Plan, Mutate, and
	// post-effect Project. Mutation locks root/claim/selectors/state and each
	// assignment, rechecks the non-locking Profile/User eligibility view, and
	// conservatively up to five additional provenance/release rows per existing
	// assignment before it can be reactivated or tombstoned.
	// Each bounded selector/eligibility recheck reserves one overflow probe so a
	// growing population fails inside the declared host receipt.
	currentItems := 2*planCurrentItems + 3 + len(plan.Profiles) + 1 +
		plan.EligibilityItems + 1 + 6*assignmentRows + projectCurrentItems
	mutationRows := plan.AssignmentWrites
	if plan.StateWrite {
		mutationRows++
	}
	mutationBytes := mutationRows*assignmentPolicyMutationBytesPerRow +
		len(plan.Request.Actor) + len(plan.Request.Reason)
	return cp.ComponentManagedUsage{
		CurrentItems:       currentItems,
		DesiredItems:       len(plan.Desired),
		DeltaRows:          mutationRows,
		MutationBytes:      mutationBytes,
		MutationStatements: mutationRows,
		BatchRows:          min(mutationRows, assignmentPolicyMaximumRows),
	}
}

func validateAssignmentPolicyOperationEstimate(usage cp.ComponentManagedUsage) error {
	budget := assignmentPolicyManagedBudget()
	limits := []struct {
		name   string
		actual int
		limit  int
	}{
		{name: "current items", actual: usage.CurrentItems, limit: budget.MaxCurrentItems},
		{name: "desired items", actual: usage.DesiredItems, limit: budget.MaxDesiredItems},
		{name: "delta rows", actual: usage.DeltaRows, limit: budget.MaxDeltaRows},
		{name: "mutation bytes", actual: usage.MutationBytes, limit: budget.MaxMutationBytes},
		{name: "mutation statements", actual: usage.MutationStatements, limit: budget.MaxMutationStatements},
		{name: "batch rows", actual: usage.BatchRows, limit: budget.MaxBatchRows},
	}
	for _, entry := range limits {
		if entry.actual > entry.limit {
			return fmt.Errorf(
				"assignment policy operation %s %d exceed registration budget %d",
				entry.name, entry.actual, entry.limit,
			)
		}
	}
	return nil
}

func decodeAssignmentPolicyOperationPlan(plan cp.ComponentManagedPlan) (assignmentPolicyOperationPlan, error) {
	if err := plan.Validate(); err != nil {
		return assignmentPolicyOperationPlan{}, fmt.Errorf("assignment policy operation plan: %w", err)
	}
	var decoded assignmentPolicyOperationPlan
	if err := json.Unmarshal(plan.OpaquePlan(), &decoded); err != nil {
		return assignmentPolicyOperationPlan{}, fmt.Errorf("decode assignment policy operation plan: %w", err)
	}
	if err := validateAssignmentPolicyOperationRequest(decoded.Request); err != nil {
		return assignmentPolicyOperationPlan{}, err
	}
	if decoded.TargetID == "" || decoded.TargetName == "" ||
		decoded.DefinitionOwnerPack == "" || decoded.ClaimID == "" || decoded.OwnerPack == "" ||
		decoded.PolicyKey == "" || decoded.State.ID == "" ||
		decoded.EligibilityItems < 0 || decoded.FinalAssignmentRows < 0 || decoded.AssignmentWrites < 0 {
		return assignmentPolicyOperationPlan{}, fmt.Errorf("assignment policy operation plan is incomplete")
	}
	if decoded.State.AppliedGeneration > decoded.State.WorkGeneration {
		return assignmentPolicyOperationPlan{}, fmt.Errorf("assignment policy operation generation state is invalid")
	}
	if !isSortedAssignmentPolicyOperationIdentities(decoded.Profiles) ||
		!isSortedAssignmentPolicyOperationIdentities(decoded.Eligible) ||
		!isSortedAssignmentPolicyOperationIdentities(decoded.ActiveAssignments) ||
		!isSortedAssignmentPolicyOperationIdentities(decoded.DeletedAssignments) ||
		!isSortedAssignmentPolicyOperationIdentities(decoded.Desired) {
		return assignmentPolicyOperationPlan{}, fmt.Errorf("assignment policy operation plan is not canonical")
	}
	return decoded, nil
}

func sortAssignmentPolicyOperationIdentities(values []string) {
	sort.Slice(values, func(i, j int) bool {
		left := assignmentPolicyDatabaseIdentity(values[i])
		right := assignmentPolicyDatabaseIdentity(values[j])
		if left != right {
			return left < right
		}
		return values[i] < values[j]
	})
}

func isSortedAssignmentPolicyOperationIdentities(values []string) bool {
	return slices.IsSortedFunc(values, func(left, right string) int {
		leftIdentity := assignmentPolicyDatabaseIdentity(left)
		rightIdentity := assignmentPolicyDatabaseIdentity(right)
		if leftIdentity != rightIdentity {
			return strings.Compare(leftIdentity, rightIdentity)
		}
		return strings.Compare(left, right)
	})
}
