package runtimeapi

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"strings"
	"testing"
	"time"

	"github.com/nexuscrm/automation"
	apperrors "github.com/nexuscrm/kernel/pkg/errors"
	"github.com/nexuscrm/kernel/pkg/ports"
	"github.com/nexuscrm/metadata"
	"github.com/nexuscrm/metadata/catalogsnapshot"
	"github.com/nexuscrm/persistence"
	"github.com/nexuscrm/shared/pkg/models"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/approvalir"
	approvalsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/approvalv1"
	commonsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/commonv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/delegationv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/permissionstatev1"
	recordsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordsv1"
	runtimev1 "github.com/pingcap-inc/nexuscrm-contract/wire-go/gen/runtime/v1"
	"github.com/pingcap-inc/nexuscrm-contract/wire-go/mapping"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

type approvalServerTransactionKey struct{}

type approvalServerTestStore struct {
	t          *testing.T
	row        persistence.RuntimeApprovalInvocationRow
	acceptance persistence.RuntimeApprovalInvocationAcceptance
	present    bool
}

func (s *approvalServerTestStore) Lookup(ctx context.Context, scopeDigest, idempotencyKey string) (persistence.RuntimeApprovalInvocationRow, bool, error) {
	s.t.Helper()
	if active, _ := ctx.Value(approvalServerTransactionKey{}).(bool); !active {
		s.t.Fatal("Approval invocation lookup escaped the transaction")
	}
	if !s.present || s.row.ScopeDigest != scopeDigest || s.row.IdempotencyKey != idempotencyKey {
		return persistence.RuntimeApprovalInvocationRow{}, false, nil
	}
	return s.row, true, nil
}

func (s *approvalServerTestStore) Accept(ctx context.Context, input persistence.RuntimeApprovalInvocationAcceptance) (persistence.RuntimeApprovalInvocationRow, bool, error) {
	s.t.Helper()
	if active, _ := ctx.Value(approvalServerTransactionKey{}).(bool); !active {
		s.t.Fatal("Approval invocation acceptance escaped the transaction")
	}
	if s.present {
		return s.row, true, nil
	}
	s.acceptance = input
	s.row = persistence.RuntimeApprovalInvocationRow{
		RowID: input.RowID, ScopeDigest: input.ScopeDigest, IdempotencyKey: input.IdempotencyKey,
		Operation: input.Operation, DefinitionID: input.DefinitionID,
		DefinitionVersion: input.DefinitionVersion, ClosureDigest: input.ClosureDigest,
		RequestDigest: input.RequestDigest, Receipts: append([]byte(nil), input.Receipts...),
		State: persistence.RuntimeApprovalInvocationAccepted,
	}
	s.present = true
	return s.row, false, nil
}

func (s *approvalServerTestStore) Complete(ctx context.Context, rowID string, result []byte) error {
	s.t.Helper()
	if active, _ := ctx.Value(approvalServerTransactionKey{}).(bool); !active {
		s.t.Fatal("Approval invocation completion escaped the transaction")
	}
	if !s.present || s.row.RowID != rowID {
		s.t.Fatalf("completed unknown Approval invocation %q", rowID)
	}
	s.row.State = persistence.RuntimeApprovalInvocationCompleted
	s.row.ResultPayload = append([]byte(nil), result...)
	return nil
}

type approvalServerTestRunner struct {
	store                *approvalServerTestStore
	effect               *bool
	wrapError            func(error) error
	completionOverride   *ports.TransactionCompletionOutcome
	preserveEffectsOnErr bool
	attempts             int
}

func (r *approvalServerTestRunner) RunInPessimisticTransactionWithOutcome(
	ctx context.Context,
	run func(context.Context) error,
) (ports.TransactionCompletionOutcome, error) {
	r.attempts++
	originalRow, originalAcceptance, originalPresent := r.store.row, r.store.acceptance, r.store.present
	originalEffect := false
	if r.effect != nil {
		originalEffect = *r.effect
	}
	err := run(context.WithValue(ctx, approvalServerTransactionKey{}, true))
	if err != nil && !r.preserveEffectsOnErr {
		r.store.row, r.store.acceptance, r.store.present = originalRow, originalAcceptance, originalPresent
		if r.effect != nil {
			*r.effect = originalEffect
		}
	}
	if err != nil {
		if r.wrapError != nil {
			err = r.wrapError(err)
		}
	}
	completion := ports.TransactionCompletionCommitted
	if err != nil {
		completion = ports.TransactionCompletionRolledBack
	}
	if r.completionOverride != nil {
		completion = *r.completionOverride
	}
	return completion, err
}

type approvalServerTestEngine struct {
	t             *testing.T
	resolveCalls  int
	executeCalls  int
	readCalls     int
	cancelCaller  context.CancelFunc
	wantProfile   catalogsnapshot.ProjectionProfile
	resolveFunc   func(*catalogsnapshot.RuntimeMetadataView, approvalsemantic.ExecuteRequest) (approvalResolvedExecution, error)
	readResponse  approvalsemantic.ReadResponse
	executeResult approvalsemantic.ExecuteResponse
	executeErr    error
	effect        *bool
}

type approvalServerTestPermissionFence struct {
	t     *testing.T
	calls int
	err   error
}

func (f *approvalServerTestPermissionFence) FencePermissionFloorWithinTransaction(ctx context.Context, _ permissionstatev1.Version) error {
	f.t.Helper()
	if active, _ := ctx.Value(approvalServerTransactionKey{}).(bool); !active {
		f.t.Fatal("Approval permission fence escaped the transaction")
	}
	f.calls++
	return f.err
}

func (e *approvalServerTestEngine) resolve(ctx context.Context, view *catalogsnapshot.RuntimeMetadataView, request approvalsemantic.ExecuteRequest, _ *models.UserSession) (approvalResolvedExecution, error) {
	e.t.Helper()
	e.resolveCalls++
	bound, ok := metadata.RuntimeMetadataViewFromContext(ctx)
	if !ok || bound != view {
		e.t.Fatalf("Approval resolve context view = %p, %t; want admitted view %p", bound, ok, view)
	}
	if e.resolveFunc != nil {
		return e.resolveFunc(view, request)
	}
	if view == nil || view.Profile() != e.wantProfile || request.Operation != approvalsemantic.OperationSubmit {
		e.t.Fatalf("resolve view/request = %#v / %#v", view, request)
	}
	return approvalResolvedExecution{
		definitionID: approvalTestDefinitionID, definitionVersion: "version-1",
		closureDigest: "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
	}, nil
}

func (e *approvalServerTestEngine) execute(ctx context.Context, _ approvalResolvedExecution, request approvalsemantic.ExecuteRequest, _ *models.UserSession) (approvalsemantic.ExecuteResponse, error) {
	e.t.Helper()
	e.executeCalls++
	if active, _ := ctx.Value(approvalServerTransactionKey{}).(bool); !active {
		e.t.Fatal("Approval effect escaped the invocation transaction")
	}
	if e.cancelCaller != nil {
		e.cancelCaller()
	}
	if e.effect != nil {
		*e.effect = true
	}
	result := e.executeResult
	result.TargetRecordID = request.TargetRecordID
	return result, e.executeErr
}

func (e *approvalServerTestEngine) read(_ context.Context, view *catalogsnapshot.RuntimeMetadataView, _ approvalsemantic.ReadRequest, _ *models.UserSession) (approvalsemantic.ReadResponse, error) {
	e.t.Helper()
	e.readCalls++
	if view == nil || view.Profile() != e.wantProfile {
		e.t.Fatalf("read view = %#v, want profile %q", view, e.wantProfile)
	}
	return e.readResponse, nil
}

func TestApprovalServerCommitsAndReplaysBeforeMutableResolution(t *testing.T) {
	view := approvalAuthorityTestView(t, approvalsemantic.ExecuteCapabilityName)
	store := &approvalServerTestStore{t: t}
	runner := &approvalServerTestRunner{store: store}
	engine := &approvalServerTestEngine{
		t: t, wantProfile: catalogsnapshot.ProjectionApprovalExecutionV1,
		executeResult: approvalsemantic.ExecuteResponse{
			InstanceID: "instance-1", State: approvalsemantic.InstanceStatePending,
			PendingWorkItems: []approvalsemantic.WorkItemAssignment{{WorkItemID: "work-1", ActorID: "user-2"}},
		},
	}
	permissions := &approvalServerTestPermissionFence{t: t}
	server, err := NewApprovalServer(engine, store, runner, permissions)
	if err != nil {
		t.Fatal(err)
	}
	ctx := approvalServerTestContext(t, context.Background(), approvalsemantic.ExecuteCapabilityName, view)
	wireRequest := approvalServerTestSubmitRequest(t, ctx, "approval-request-1", "record-1")
	first, err := server.ExecuteApproval(ctx, wireRequest)
	if err != nil {
		t.Fatal(err)
	}
	second, err := server.ExecuteApproval(ctx, wireRequest)
	if err != nil {
		t.Fatal(err)
	}
	firstResult, err := mapping.FromWireExecuteApprovalResponse(approvalsemantic.ExecuteRequest{
		Operation: approvalsemantic.OperationSubmit, IdempotencyKey: "approval-request-1",
		ObjectID: "WorkItem", TargetRecordID: "record-1",
	}, first)
	if err != nil {
		t.Fatal(err)
	}
	secondResult, err := mapping.FromWireExecuteApprovalResponse(approvalsemantic.ExecuteRequest{
		Operation: approvalsemantic.OperationSubmit, IdempotencyKey: "approval-request-1",
		ObjectID: "WorkItem", TargetRecordID: "record-1",
	}, second)
	if err != nil {
		t.Fatal(err)
	}
	if engine.resolveCalls != 1 || engine.executeCalls != 1 || runner.attempts != 2 || permissions.calls != 2 ||
		firstResult.ExecutionID == "" || firstResult.ExecutionID != secondResult.ExecutionID ||
		firstResult.ActingPrincipalID != "user-1" || secondResult.ActingPrincipalID != "user-1" ||
		store.row.State != persistence.RuntimeApprovalInvocationCompleted {
		t.Fatalf("execution/replay calls=%d/%d attempts=%d first=%#v second=%#v row=%#v",
			engine.resolveCalls, engine.executeCalls, runner.attempts, firstResult, secondResult, store.row)
	}
	if store.acceptance.DefinitionID != approvalTestDefinitionID || store.acceptance.DefinitionVersion != "version-1" ||
		!bytes.Equal(store.acceptance.Receipts, store.row.Receipts) {
		t.Fatalf("durable binding = %#v", store.acceptance)
	}

	conflicting := approvalServerTestSubmitRequest(t, ctx, "approval-request-1", "record-2")
	_, conflictErr := server.ExecuteApproval(ctx, conflicting)
	if status.Code(conflictErr) != codes.InvalidArgument {
		t.Fatalf("changed replay error = %v, want InvalidArgument", conflictErr)
	}
	var conflictFailure *recordsemantic.Failure
	if decoded := mapping.FromPlatformStatusError(conflictErr, approvalsemantic.ExecuteCapabilityName); !errors.As(decoded, &conflictFailure) || conflictFailure.Category != recordsemantic.FailureInvalidRequest {
		t.Fatalf("changed replay detail = %v, want Approval execute INVALID_REQUEST", decoded)
	}
	if engine.resolveCalls != 1 || engine.executeCalls != 1 {
		t.Fatal("conflicting replay reached mutable resolution")
	}
}

func TestApprovalServerReturnsNormalSubmitRejectionsWithoutAcceptingInvocation(t *testing.T) {
	tests := []struct {
		name       string
		resolveErr error
		wantReason approvalsemantic.SubmitRejectionReason
	}{
		{
			name:       "no active process",
			resolveErr: automation.ErrNoActiveApprovalProcess,
			wantReason: approvalsemantic.SubmitRejectionNoActiveProcess,
		},
		{
			name:       "entry criteria not met",
			resolveErr: automation.ErrEntryCriteriaNotMet,
			wantReason: approvalsemantic.SubmitRejectionEntryCriteriaMiss,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			view := approvalAuthorityTestView(t, approvalsemantic.ExecuteCapabilityName)
			store := &approvalServerTestStore{t: t}
			runner := &approvalServerTestRunner{store: store}
			engine := &approvalServerTestEngine{
				t: t,
				resolveFunc: func(*catalogsnapshot.RuntimeMetadataView, approvalsemantic.ExecuteRequest) (approvalResolvedExecution, error) {
					return approvalResolvedExecution{}, test.resolveErr
				},
			}
			permissions := &approvalServerTestPermissionFence{t: t}
			server, err := NewApprovalServer(engine, store, runner, permissions)
			if err != nil {
				t.Fatal(err)
			}
			ctx := approvalServerTestContext(t, context.Background(), approvalsemantic.ExecuteCapabilityName, view)
			request := approvalsemantic.ExecuteRequest{
				Operation: approvalsemantic.OperationSubmit, IdempotencyKey: "rejected-submit",
				ObjectID: "WorkItem", TargetRecordID: "record-1",
			}
			wireRequest, err := mapping.ToWireExecuteApprovalRequest(ctx, request)
			if err != nil {
				t.Fatal(err)
			}
			wireResponse, err := server.ExecuteApproval(ctx, wireRequest)
			if err != nil {
				t.Fatal(err)
			}
			response, err := mapping.FromWireExecuteApprovalResponse(request, wireResponse)
			if err != nil {
				t.Fatal(err)
			}
			if response.SubmitRejection == nil || response.SubmitRejection.Reason != test.wantReason ||
				response.TargetRecordID != request.TargetRecordID || response.ExecutionID != "" ||
				response.InstanceID != "" || response.ActingPrincipalID != "" ||
				engine.resolveCalls != 1 || engine.executeCalls != 0 || runner.attempts != 1 ||
				permissions.calls != 1 || store.present {
				t.Fatalf(
					"response=%#v resolve=%d execute=%d attempts=%d permissions=%d stored=%v",
					response, engine.resolveCalls, engine.executeCalls, runner.attempts, permissions.calls, store.present,
				)
			}
		})
	}
}

func TestApprovalServerRollsBackValidationRejectionBeforePresentation(t *testing.T) {
	view := approvalAuthorityTestView(t, approvalsemantic.ExecuteCapabilityName)
	store := &approvalServerTestStore{t: t}
	transactionalEffect := false
	runner := &approvalServerTestRunner{store: store, effect: &transactionalEffect}
	engine := &approvalServerTestEngine{
		t: t, wantProfile: catalogsnapshot.ProjectionApprovalExecutionV1,
		executeErr: fmt.Errorf("initial submission field update: %w", apperrors.NewValidationRuleFailures(
			[]apperrors.ValidationRuleFailure{
				{
					RuleName: "Quote_Submit_Requires_Complete_Lines",
					Message:  "Cannot submit: the quote needs at least one complete line item.",
				},
				{
					RuleName: "Quote_Submit_Requires_Service_Dates",
					Field:    "EndDate",
					Message:  "Cannot submit: complete the quote service dates.",
				},
			},
		)),
		effect: &transactionalEffect,
	}
	permissions := &approvalServerTestPermissionFence{t: t}
	server, err := NewApprovalServer(engine, store, runner, permissions)
	if err != nil {
		t.Fatal(err)
	}
	ctx := approvalServerTestContext(t, context.Background(), approvalsemantic.ExecuteCapabilityName, view)
	request := approvalsemantic.ExecuteRequest{
		Operation: approvalsemantic.OperationSubmit, IdempotencyKey: "validation-rejected-submit",
		ObjectID: "WorkItem", TargetRecordID: "record-1",
	}
	wireRequest, err := mapping.ToWireExecuteApprovalRequest(ctx, request)
	if err != nil {
		t.Fatal(err)
	}
	wireResponse, err := server.ExecuteApproval(ctx, wireRequest)
	if err != nil {
		t.Fatalf("ExecuteApproval() error = %v, want normal validation rejection", err)
	}
	response, err := mapping.FromWireExecuteApprovalResponse(request, wireResponse)
	if err != nil {
		t.Fatal(err)
	}
	wantIssues := []approvalsemantic.ValidationIssue{
		{
			RuleName: "Quote_Submit_Requires_Complete_Lines",
			Message:  "Cannot submit: the quote needs at least one complete line item.",
		},
		{
			RuleName: "Quote_Submit_Requires_Service_Dates",
			Field:    "EndDate",
			Message:  "Cannot submit: complete the quote service dates.",
		},
	}
	if response.SubmitRejection == nil ||
		response.SubmitRejection.Reason != approvalsemantic.SubmitRejectionRecordValidationFailed ||
		!reflect.DeepEqual(response.SubmitRejection.ValidationIssues, wantIssues) ||
		response.TargetRecordID != request.TargetRecordID || response.ExecutionID != "" ||
		response.InstanceID != "" || response.ActingPrincipalID != "" ||
		engine.resolveCalls != 1 || engine.executeCalls != 1 || runner.attempts != 1 ||
		permissions.calls != 1 || store.present || transactionalEffect {
		t.Fatalf(
			"response=%#v resolve=%d execute=%d attempts=%d permissions=%d stored=%v effect=%v",
			response, engine.resolveCalls, engine.executeCalls, runner.attempts,
			permissions.calls, store.present, transactionalEffect,
		)
	}
}

func TestApprovalServerDoesNotPresentValidationAfterPermissionRevocation(t *testing.T) {
	view := approvalAuthorityTestView(t, approvalsemantic.ExecuteCapabilityName)
	store := &approvalServerTestStore{t: t}
	transactionalEffect := false
	runner := &approvalServerTestRunner{store: store, effect: &transactionalEffect}
	engine := &approvalServerTestEngine{
		t: t, wantProfile: catalogsnapshot.ProjectionApprovalExecutionV1,
		executeErr: apperrors.NewValidationRuleError(
			"Quote_Submit_Requires_Complete_Lines",
			"This message must not escape after permission revocation.",
		),
		effect: &transactionalEffect,
	}
	permissions := &approvalServerTestPermissionFence{
		t: t, err: &recordsemantic.Failure{Category: recordsemantic.FailureForbidden},
	}
	server, err := NewApprovalServer(engine, store, runner, permissions)
	if err != nil {
		t.Fatal(err)
	}
	ctx := approvalServerTestContext(t, context.Background(), approvalsemantic.ExecuteCapabilityName, view)
	_, executeErr := server.ExecuteApproval(
		ctx,
		approvalServerTestSubmitRequest(t, ctx, "revoked-validation-submit", "record-1"),
	)
	if status.Code(executeErr) != codes.PermissionDenied ||
		strings.Contains(executeErr.Error(), "must not escape") || permissions.calls != 1 ||
		store.present || transactionalEffect {
		t.Fatalf(
			"revoked response=%v permissions=%d stored=%v effect=%v, want opaque denial with rollback",
			executeErr, permissions.calls, store.present, transactionalEffect,
		)
	}
}

func TestApprovalServerDoesNotPresentValidationWhenRollbackFails(t *testing.T) {
	view := approvalAuthorityTestView(t, approvalsemantic.ExecuteCapabilityName)
	store := &approvalServerTestStore{t: t}
	transactionalEffect := false
	rollbackError := ports.TransactionCompletionRollbackError
	runner := &approvalServerTestRunner{
		store: store, effect: &transactionalEffect, completionOverride: &rollbackError,
		wrapError: func(err error) error {
			return apperrors.NewInternalError("rollback failed", err)
		},
	}
	engine := &approvalServerTestEngine{
		t: t, wantProfile: catalogsnapshot.ProjectionApprovalExecutionV1,
		executeErr: apperrors.NewValidationRuleError(
			"Quote_Submit_Requires_Complete_Lines",
			"This message must not escape an uncertain rollback.",
		),
		effect: &transactionalEffect,
	}
	server, err := NewApprovalServer(
		engine,
		store,
		runner,
		&approvalServerTestPermissionFence{t: t},
	)
	if err != nil {
		t.Fatal(err)
	}
	ctx := approvalServerTestContext(t, context.Background(), approvalsemantic.ExecuteCapabilityName, view)
	_, executeErr := server.ExecuteApproval(
		ctx,
		approvalServerTestSubmitRequest(t, ctx, "rollback-failed-submit", "record-1"),
	)
	if status.Code(executeErr) != codes.Internal ||
		strings.Contains(executeErr.Error(), "must not escape") || store.present || transactionalEffect {
		t.Fatalf(
			"rollback failure response=%v stored=%v effect=%v, want opaque Internal with rollback",
			executeErr, store.present, transactionalEffect,
		)
	}
}

func TestApprovalServerDoesNotPresentValidationWithoutRollbackProof(t *testing.T) {
	view := approvalAuthorityTestView(t, approvalsemantic.ExecuteCapabilityName)
	store := &approvalServerTestStore{t: t}
	transactionalEffect := false
	noCompletionProof := ports.TransactionCompletionOutcome("")
	runner := &approvalServerTestRunner{
		store: store, effect: &transactionalEffect,
		completionOverride: &noCompletionProof, preserveEffectsOnErr: true,
	}
	engine := &approvalServerTestEngine{
		t: t, wantProfile: catalogsnapshot.ProjectionApprovalExecutionV1,
		executeErr: apperrors.NewValidationRuleError(
			"Quote_Submit_Requires_Complete_Lines",
			"This message must not escape an ambient transaction.",
		),
		effect: &transactionalEffect,
	}
	server, err := NewApprovalServer(
		engine,
		store,
		runner,
		&approvalServerTestPermissionFence{t: t},
	)
	if err != nil {
		t.Fatal(err)
	}
	ctx := approvalServerTestContext(t, context.Background(), approvalsemantic.ExecuteCapabilityName, view)
	_, executeErr := server.ExecuteApproval(
		ctx,
		approvalServerTestSubmitRequest(t, ctx, "ambient-validation-submit", "record-1"),
	)
	if status.Code(executeErr) != codes.Internal ||
		strings.Contains(executeErr.Error(), "must not escape") || !store.present || !transactionalEffect {
		t.Fatalf(
			"ambient response=%v stored=%v effect=%v, want opaque Internal without a rollback claim",
			executeErr, store.present, transactionalEffect,
		)
	}
}

func TestApprovalServerRejectsUnsafeTypedValidationIssue(t *testing.T) {
	view := approvalAuthorityTestView(t, approvalsemantic.ExecuteCapabilityName)
	store := &approvalServerTestStore{t: t}
	transactionalEffect := false
	runner := &approvalServerTestRunner{store: store, effect: &transactionalEffect}
	engine := &approvalServerTestEngine{
		t: t, wantProfile: catalogsnapshot.ProjectionApprovalExecutionV1,
		executeErr: apperrors.NewValidationRuleError(
			" unsafe_rule_name",
			"This malformed typed issue must remain private.",
		),
		effect: &transactionalEffect,
	}
	server, err := NewApprovalServer(
		engine,
		store,
		runner,
		&approvalServerTestPermissionFence{t: t},
	)
	if err != nil {
		t.Fatal(err)
	}
	ctx := approvalServerTestContext(t, context.Background(), approvalsemantic.ExecuteCapabilityName, view)
	_, executeErr := server.ExecuteApproval(
		ctx,
		approvalServerTestSubmitRequest(t, ctx, "unsafe-validation-submit", "record-1"),
	)
	if status.Code(executeErr) != codes.Internal ||
		strings.Contains(executeErr.Error(), "must remain private") || store.present || transactionalEffect {
		t.Fatalf(
			"unsafe validation response=%v stored=%v effect=%v, want opaque Internal with rollback",
			executeErr, store.present, transactionalEffect,
		)
	}
}

func TestApprovalServerPreservesMissingRecordAsTopLevelFailure(t *testing.T) {
	view := approvalAuthorityTestView(t, approvalsemantic.ExecuteCapabilityName)
	store := &approvalServerTestStore{t: t}
	runner := &approvalServerTestRunner{store: store}
	engine := &approvalServerTestEngine{
		t: t,
		resolveFunc: func(*catalogsnapshot.RuntimeMetadataView, approvalsemantic.ExecuteRequest) (approvalResolvedExecution, error) {
			return approvalResolvedExecution{}, apperrors.NewNotFoundError("record", "record-1")
		},
	}
	permissions := &approvalServerTestPermissionFence{t: t}
	server, err := NewApprovalServer(engine, store, runner, permissions)
	if err != nil {
		t.Fatal(err)
	}
	ctx := approvalServerTestContext(t, context.Background(), approvalsemantic.ExecuteCapabilityName, view)
	_, executeErr := server.ExecuteApproval(
		ctx,
		approvalServerTestSubmitRequest(t, ctx, "missing-record", "record-1"),
	)
	if status.Code(executeErr) != codes.NotFound {
		t.Fatalf("missing record error = %v, want NotFound", executeErr)
	}
	var failure *recordsemantic.Failure
	decoded := mapping.FromPlatformStatusError(executeErr, approvalsemantic.ExecuteCapabilityName)
	if !errors.As(decoded, &failure) || failure.Category != recordsemantic.FailureMissing {
		t.Fatalf("missing record detail = %#v, want MISSING", decoded)
	}
	if engine.resolveCalls != 1 || engine.executeCalls != 0 || runner.attempts != 1 ||
		permissions.calls != 0 || store.present {
		t.Fatalf(
			"resolve=%d execute=%d attempts=%d permissions=%d stored=%v",
			engine.resolveCalls, engine.executeCalls, runner.attempts, permissions.calls, store.present,
		)
	}
}

func TestApprovalServerRejectsEmptyCatalogAuthorityBeforeTransaction(t *testing.T) {
	view := emptyApprovalExecutionTestView(t)
	store := &approvalServerTestStore{t: t}
	runner := &approvalServerTestRunner{store: store}
	engine := &approvalServerTestEngine{t: t, wantProfile: catalogsnapshot.ProjectionApprovalExecutionV1}
	permissions := &approvalServerTestPermissionFence{t: t}
	server, err := NewApprovalServer(engine, store, runner, permissions)
	if err != nil {
		t.Fatal(err)
	}
	ctx := approvalServerTestContext(t, context.Background(), approvalsemantic.ExecuteCapabilityName, view)
	_, executeErr := server.ExecuteApproval(ctx, approvalServerTestSubmitRequest(t, ctx, "empty-authority", "record-1"))
	var failure *recordsemantic.Failure
	decoded := mapping.FromPlatformStatusError(executeErr, approvalsemantic.ExecuteCapabilityName)
	if !errors.As(decoded, &failure) || failure.Category != recordsemantic.FailureUnavailable {
		t.Fatalf("empty authority error = %#v, want UNAVAILABLE", decoded)
	}
	if runner.attempts != 0 || engine.resolveCalls != 0 || engine.executeCalls != 0 ||
		permissions.calls != 0 || store.present {
		t.Fatalf("empty authority reached transaction/effect: attempts=%d resolve=%d execute=%d permissions=%d stored=%v",
			runner.attempts, engine.resolveCalls, engine.executeCalls, permissions.calls, store.present)
	}
}

func emptyApprovalExecutionTestView(t *testing.T) *catalogsnapshot.RuntimeMetadataView {
	t.Helper()
	revision := catalogsnapshot.CatalogRevision(71)
	input := catalogsnapshot.CompileInput{
		OrgID: "org-approval-test",
		Lineage: catalogsnapshot.Lineage{
			CatalogRevision: revision, SchemaGeneration: 8, EngineGeneration: 9,
		},
	}
	objectNames := make([]string, 0, len(approvalRuntimeViewTestObjects()))
	for _, object := range approvalRuntimeViewTestObjects() {
		input.Objects = append(input.Objects, catalogsnapshot.ObjectInput{
			CatalogRevision: revision, Metadata: object,
		})
		objectNames = append(objectNames, object.APIName)
	}
	input.Projections = []catalogsnapshot.RuntimeProjectionInput{{
		CatalogRevision: revision, AppInstallationID: approvalTestInstallation,
		CapabilityID: approvalsemantic.ExecuteCapabilityName,
		Profile:      catalogsnapshot.ProjectionApprovalExecutionV1, ObjectAPINames: objectNames,
	}}
	snapshotArtifact, err := catalogsnapshot.CompileCatalogSnapshot(input)
	if err != nil {
		t.Fatal(err)
	}
	snapshot, err := catalogsnapshot.OpenCatalogSnapshot(snapshotArtifact)
	if err != nil {
		t.Fatal(err)
	}
	viewArtifact, err := catalogsnapshot.ProjectRuntimeMetadataView(snapshot, catalogsnapshot.ProjectionKey{
		AppInstallationID: approvalTestInstallation,
		CapabilityID:      approvalsemantic.ExecuteCapabilityName,
	})
	if err != nil {
		t.Fatal(err)
	}
	view, err := catalogsnapshot.OpenRuntimeMetadataView(viewArtifact)
	if err != nil {
		t.Fatal(err)
	}
	if view.SupportsMutationClosure() {
		t.Fatal("empty Approval execution view carries mutation authority")
	}
	return view
}

func TestApprovalServerCancellationRollsBackAcceptanceAndEffect(t *testing.T) {
	view := approvalAuthorityTestView(t, approvalsemantic.ExecuteCapabilityName)
	store := &approvalServerTestStore{t: t}
	runner := &approvalServerTestRunner{store: store}
	base, cancel := context.WithCancel(context.Background())
	engine := &approvalServerTestEngine{
		t: t, wantProfile: catalogsnapshot.ProjectionApprovalExecutionV1, cancelCaller: cancel,
		executeResult: approvalsemantic.ExecuteResponse{
			InstanceID: "instance-1", State: approvalsemantic.InstanceStatePending,
			PendingWorkItems: []approvalsemantic.WorkItemAssignment{{WorkItemID: "work-1", ActorID: "user-2"}},
		},
	}
	server, err := NewApprovalServer(engine, store, runner, &approvalServerTestPermissionFence{t: t})
	if err != nil {
		t.Fatal(err)
	}
	ctx := approvalServerTestContext(t, base, approvalsemantic.ExecuteCapabilityName, view)
	_, err = server.ExecuteApproval(ctx, approvalServerTestSubmitRequest(t, ctx, "cancel-request", "record-1"))
	if status.Code(err) != codes.Canceled || store.present {
		t.Fatalf("cancellation error=%v durable row present=%v", err, store.present)
	}
}

func TestApprovalServerPermissionFloorFenceRollsBackAcceptanceAndEffect(t *testing.T) {
	view := approvalAuthorityTestView(t, approvalsemantic.ExecuteCapabilityName)
	store := &approvalServerTestStore{t: t}
	runner := &approvalServerTestRunner{store: store}
	engine := &approvalServerTestEngine{
		t: t, wantProfile: catalogsnapshot.ProjectionApprovalExecutionV1,
		executeResult: approvalsemantic.ExecuteResponse{
			InstanceID: "instance-1", State: approvalsemantic.InstanceStatePending,
			PendingWorkItems: []approvalsemantic.WorkItemAssignment{{WorkItemID: "work-1", ActorID: "user-2"}},
		},
	}
	permissions := &approvalServerTestPermissionFence{
		t: t, err: &recordsemantic.Failure{Category: recordsemantic.FailureUnavailable},
	}
	server, err := NewApprovalServer(engine, store, runner, permissions)
	if err != nil {
		t.Fatal(err)
	}
	ctx := approvalServerTestContext(t, context.Background(), approvalsemantic.ExecuteCapabilityName, view)
	_, err = server.ExecuteApproval(ctx, approvalServerTestSubmitRequest(t, ctx, "revoked-request", "record-1"))
	if status.Code(err) != codes.Unavailable || store.present || permissions.calls != 1 {
		t.Fatalf("permission fence error=%v durable row present=%v calls=%d", err, store.present, permissions.calls)
	}
}

func TestApprovalServerRejectsCatalogDisallowedRecallBeforeDurableAcceptance(t *testing.T) {
	view := approvalAuthorityTestViewWithMutation(t, func(definition *approvalir.Definition) {
		definition.AllowRecall = false
	})
	store := &approvalServerTestStore{t: t}
	runner := &approvalServerTestRunner{store: store}
	engine := &approvalServerTestEngine{
		t: t, wantProfile: catalogsnapshot.ProjectionApprovalExecutionV1,
		resolveFunc: func(view *catalogsnapshot.RuntimeMetadataView, request approvalsemantic.ExecuteRequest) (approvalResolvedExecution, error) {
			if view == nil || view.Profile() != catalogsnapshot.ProjectionApprovalExecutionV1 ||
				request.Operation != approvalsemantic.OperationRecall {
				t.Fatalf("recall resolution view/request = %#v / %#v", view, request)
			}
			authority, err := newCatalogApprovalAuthority(view, approvalAuthorityAnchors())
			if err != nil {
				return approvalResolvedExecution{}, err
			}
			binding, err := authority.bindingForStorageID(t.Context(), approvalTestStorageID)
			if err != nil {
				return approvalResolvedExecution{}, err
			}
			return approvalResolvedExecution{}, requireCatalogApprovalOperation(binding, request.Operation)
		},
	}
	permissions := &approvalServerTestPermissionFence{t: t}
	server, err := NewApprovalServer(engine, store, runner, permissions)
	if err != nil {
		t.Fatal(err)
	}
	ctx := approvalServerTestContext(t, context.Background(), approvalsemantic.ExecuteCapabilityName, view)
	wireRequest, err := mapping.ToWireExecuteApprovalRequest(ctx, approvalsemantic.ExecuteRequest{
		Operation: approvalsemantic.OperationRecall, IdempotencyKey: "recall-disallowed-1",
		WorkItemID: "work-item-1",
	})
	if err != nil {
		t.Fatal(err)
	}
	_, err = server.ExecuteApproval(ctx, wireRequest)
	if status.Code(err) != codes.PermissionDenied {
		t.Fatalf("disallowed recall error = %v, want PermissionDenied", err)
	}
	if engine.resolveCalls != 1 || engine.executeCalls != 0 || runner.attempts != 1 ||
		store.present || permissions.calls != 0 {
		t.Fatalf(
			"disallowed recall crossed authority boundary: resolve=%d execute=%d attempts=%d durable=%v permissionFences=%d",
			engine.resolveCalls, engine.executeCalls, runner.attempts, store.present, permissions.calls,
		)
	}
}

func TestApprovalServerReadUsesReadProjectionAndExactReceipts(t *testing.T) {
	view := approvalAuthorityTestView(t, approvalsemantic.ReadCapabilityName)
	store := &approvalServerTestStore{t: t}
	engine := &approvalServerTestEngine{
		t: t, wantProfile: catalogsnapshot.ProjectionApprovalReadV1,
		readResponse: approvalsemantic.ReadResponse{Pending: []approvalsemantic.PendingItem{{
			WorkItemID: "work-1", InstanceID: "instance-1", DefinitionID: approvalTestDefinitionID,
			TargetRecordID: "record-1", ObjectID: "WorkItem", SubmittedByID: "user-1",
			SubmittedAt: "2026-08-03T00:00:00Z", ActorID: "user-2",
		}}},
	}
	server, err := NewApprovalServer(engine, store, &approvalServerTestRunner{store: store}, nil, false, true)
	if err != nil {
		t.Fatal(err)
	}
	ctx := approvalServerTestContext(t, context.Background(), approvalsemantic.ReadCapabilityName, view)
	wireRequest, err := mapping.ToWireReadApprovalRequest(ctx, approvalsemantic.ReadRequest{Kind: approvalsemantic.ReadPendingForCaller})
	if err != nil {
		t.Fatal(err)
	}
	wireResponse, err := server.ReadApproval(ctx, wireRequest)
	if err != nil {
		t.Fatal(err)
	}
	response, err := mapping.FromWireReadApprovalResponse(approvalsemantic.ReadRequest{Kind: approvalsemantic.ReadPendingForCaller}, wireResponse)
	if err != nil {
		t.Fatal(err)
	}
	if engine.readCalls != 1 || len(response.Pending) != 1 ||
		response.Receipts.CapabilityVersion != approvalsemantic.ReadCapabilityName ||
		response.Receipts.CatalogRevision != uint64(view.Lineage().CatalogRevision) {
		t.Fatalf("read response = %#v calls=%d", response, engine.readCalls)
	}
	wrongScope := approvalServerTestContext(t, context.Background(), approvalsemantic.ExecuteCapabilityName, view)
	_, wrongScopeErr := server.ReadApproval(wrongScope, wireRequest)
	var wrongScopeFailure *recordsemantic.Failure
	if decoded := mapping.FromPlatformStatusError(wrongScopeErr, approvalsemantic.ReadCapabilityName); !errors.As(decoded, &wrongScopeFailure) || wrongScopeFailure.Category != recordsemantic.FailureForbidden {
		t.Fatalf("read authority detail = %v, want Approval read FORBIDDEN", decoded)
	}
}

func approvalServerTestContext(t *testing.T, parent context.Context, capability string, view *catalogsnapshot.RuntimeMetadataView) context.Context {
	t.Helper()
	ctx, cancel := context.WithTimeout(parent, time.Second)
	t.Cleanup(cancel)
	lineage := view.Lineage()
	ctx = context.WithValue(ctx, runtimeExecutionScopeContextKey{}, RuntimeExecutionScope{
		view: view, orgID: "org-approval-test", appInstallationID: approvalTestInstallation,
		workloadID: "sfcrm-workload", capability: capability,
		receipts: recordsemantic.Receipts{
			ProtocolVersion: "1.0", CapabilityVersion: capability,
			CatalogRevision: uint64(lineage.CatalogRevision), SchemaGeneration: uint64(lineage.SchemaGeneration),
			EngineGeneration: uint64(lineage.EngineGeneration), SecurityEpoch: 3,
		},
	})
	return context.WithValue(ctx, trustedCallContextKey{}, newTrustedCall(delegationv1.Claims{
		DelegationID: "delegation-user-1", OrgID: "org-approval-test", PrincipalID: "user-1",
		SessionID: "session-user-1", CallerWorkloadID: "sfcrm-workload",
		AppInstallationID: approvalTestInstallation, RuntimeAudience: "runtime-test",
		Capabilities: []string{capability}, AuthEpoch: 2, SecurityEpoch: 3,
	}, models.UserSession{ID: "user-1"}))
}

func approvalServerTestSubmitRequest(t *testing.T, ctx context.Context, key, recordID string) *runtimev1.ExecuteApprovalRequest {
	t.Helper()
	wireRequest, err := mapping.ToWireExecuteApprovalRequest(ctx, approvalsemantic.ExecuteRequest{
		Operation: approvalsemantic.OperationSubmit, IdempotencyKey: key,
		ObjectID: "WorkItem", TargetRecordID: recordID,
	})
	if err != nil {
		t.Fatal(err)
	}
	return wireRequest
}

func TestReplayApprovalInvocationRejectsMalformedCompletedResult(t *testing.T) {
	request := approvalsemantic.ExecuteRequest{
		Operation: approvalsemantic.OperationSubmit, IdempotencyKey: "request-1",
		ObjectID: "WorkItem", TargetRecordID: "record-1",
	}
	receipts := approvalsemantic.Receipts{
		ProtocolVersion: "1.0", CapabilityVersion: approvalsemantic.ExecuteCapabilityName,
		CatalogRevision: 71, SchemaGeneration: 8, EngineGeneration: 9, SecurityEpoch: 3,
	}
	receiptJSON, _ := json.Marshal(receipts)
	row := persistence.RuntimeApprovalInvocationRow{
		Operation: string(request.Operation), RequestDigest: "request-digest", Receipts: receiptJSON,
		State: persistence.RuntimeApprovalInvocationCompleted, ResultPayload: []byte(`{"state":"PENDING"}`),
	}
	var response approvalsemantic.ExecuteResponse
	err := replayApprovalInvocation(row, request, "request-digest", receipts, &response)
	var failure *recordsemantic.Failure
	if !errors.As(err, &failure) || failure.Category != recordsemantic.FailureInternal {
		t.Fatalf("malformed completed result error = %v", err)
	}
}

func TestClassifyApprovalEngineErrorKeepsClosedContractCategories(t *testing.T) {
	tests := []struct {
		name          string
		err           error
		wantCategory  recordsemantic.FailureCategory
		wantComponent commonsemantic.InvalidComponent
	}{
		{name: "missing", err: apperrors.NewNotFoundError("work item", ""), wantCategory: recordsemantic.FailureMissing},
		{name: "forbidden", err: apperrors.NewPermissionError("approve", "work item"), wantCategory: recordsemantic.FailureForbidden},
		{name: "invalid", err: apperrors.NewValidationError("entryCriteria", "not matched"), wantCategory: recordsemantic.FailureInvalidRequest, wantComponent: commonsemantic.InvalidComponentCommandData},
		{name: "already pending", err: automation.ErrRecordAlreadyPending, wantCategory: recordsemantic.FailureInvalidRequest, wantComponent: commonsemantic.InvalidComponentOperation},
		{name: "transparently wrapped already pending", err: fmt.Errorf("approval target: %w", automation.ErrRecordAlreadyPending), wantCategory: recordsemantic.FailureInvalidRequest, wantComponent: commonsemantic.InvalidComponentOperation},
		{name: "instance not pending", err: automation.ErrInstanceNotPending, wantCategory: recordsemantic.FailureInvalidRequest, wantComponent: commonsemantic.InvalidComponentOperation},
		{name: "other conflict", err: apperrors.NewConflictError("approval", "submit plan", "definition changed"), wantCategory: recordsemantic.FailureInvalidRequest, wantComponent: commonsemantic.InvalidComponentCommandData},
		{name: "rollback failure owns wrapped conflict", err: apperrors.NewInternalError("rollback failed", automation.ErrRecordAlreadyPending), wantCategory: recordsemantic.FailureInternal},
		{name: "joined conflict is ambiguous", err: errors.Join(automation.ErrRecordAlreadyPending, errors.New("rollback outcome unknown")), wantCategory: recordsemantic.FailureInternal},
		{name: "cancellation owns joined conflict", err: errors.Join(context.Canceled, automation.ErrRecordAlreadyPending), wantCategory: recordsemantic.FailureUnavailable},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			classified := classifyApprovalEngineError(t.Context(), test.err)
			decoded := mapping.FromPlatformStatusError(
				approvalExecuteStatus(classified),
				approvalsemantic.ExecuteCapabilityName,
			)
			var failure *recordsemantic.Failure
			if !errors.As(decoded, &failure) ||
				failure.Category != test.wantCategory || failure.InvalidComponent != test.wantComponent {
				t.Fatalf("wire classification = %#v, want category=%s component=%s", failure, test.wantCategory, test.wantComponent)
			}
		})
	}
}

func TestApprovalSubmitRejectionResponseMapsOnlyClosedBusinessOutcomes(t *testing.T) {
	baseRequest := approvalsemantic.ExecuteRequest{
		Operation: approvalsemantic.OperationSubmit, IdempotencyKey: "request-1",
		ObjectID: "Account", TargetRecordID: "record-1",
	}
	tests := []struct {
		name       string
		request    approvalsemantic.ExecuteRequest
		err        error
		wantOK     bool
		wantReason approvalsemantic.SubmitRejectionReason
	}{
		{
			name: "no active process", request: baseRequest,
			err: automation.ErrNoActiveApprovalProcess, wantOK: true,
			wantReason: approvalsemantic.SubmitRejectionNoActiveProcess,
		},
		{
			name: "wrapped entry criteria miss", request: baseRequest,
			err: fmt.Errorf("approval eligibility: %w", automation.ErrEntryCriteriaNotMet), wantOK: true,
			wantReason: approvalsemantic.SubmitRejectionEntryCriteriaMiss,
		},
		{
			name: "skip entry criteria cannot reject for criteria", request: func() approvalsemantic.ExecuteRequest {
				request := baseRequest
				request.SkipEntryCriteria = true
				return request
			}(),
			err: automation.ErrEntryCriteriaNotMet,
		},
		{
			name: "ordinary missing record remains failure", request: baseRequest,
			err: apperrors.NewNotFoundError("record", "record-1"),
		},
		{
			name: "internal wrapper owns sentinel", request: baseRequest,
			err: apperrors.NewInternalError("eligibility lookup failed", automation.ErrEntryCriteriaNotMet),
		},
		{
			name: "joined result is ambiguous", request: baseRequest,
			err: errors.Join(automation.ErrEntryCriteriaNotMet, errors.New("rollback outcome unknown")),
		},
		{
			name: "non-submit operation remains failure",
			request: approvalsemantic.ExecuteRequest{
				Operation: approvalsemantic.OperationApprove, IdempotencyKey: "request-1", WorkItemID: "work-1",
			},
			err: automation.ErrEntryCriteriaNotMet,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			response, ok := approvalSubmitRejectionResponse(t.Context(), test.request, test.err)
			if ok != test.wantOK {
				t.Fatalf("mapped=%v response=%#v, want mapped=%v", ok, response, test.wantOK)
			}
			if test.wantOK && (response.SubmitRejection == nil ||
				response.SubmitRejection.Reason != test.wantReason ||
				response.TargetRecordID != test.request.TargetRecordID) {
				t.Fatalf("response=%#v, want reason=%s target=%s", response, test.wantReason, test.request.TargetRecordID)
			}
		})
	}
}

func TestApprovalSubmitValidationRejectionResponseMapsOnlyTypedRuleFailures(t *testing.T) {
	request := approvalsemantic.ExecuteRequest{
		Operation: approvalsemantic.OperationSubmit, IdempotencyKey: "request-1",
		ObjectID: "Account", TargetRecordID: "record-1",
	}
	twoRules := apperrors.NewValidationRuleFailures([]apperrors.ValidationRuleFailure{
		{RuleName: "Rule_One", Message: "Correct the first condition."},
		{RuleName: "Rule_Two", Field: "Status", Message: "Correct the second condition."},
	})
	overLimit := make([]apperrors.ValidationRuleFailure, approvalsemantic.MaxValidationIssues+1)
	for index := range overLimit {
		overLimit[index] = apperrors.ValidationRuleFailure{
			RuleName: fmt.Sprintf("Rule_%d", index),
			Message:  "Correct the record.",
		}
	}
	tests := []struct {
		name       string
		request    approvalsemantic.ExecuteRequest
		err        error
		wantIssues []approvalsemantic.ValidationIssue
	}{
		{
			name: "all typed rule failures", request: request, err: fmt.Errorf("save failed: %w", twoRules),
			wantIssues: []approvalsemantic.ValidationIssue{
				{RuleName: "Rule_One", Message: "Correct the first condition."},
				{RuleName: "Rule_Two", Field: "Status", Message: "Correct the second condition."},
			},
		},
		{
			name: "joined typed rule failures", request: request,
			err: errors.Join(
				apperrors.NewValidationRuleError("Rule_One", "Correct the first condition."),
				apperrors.NewValidationRuleError("Rule_Two", "Correct the second condition."),
			),
			wantIssues: []approvalsemantic.ValidationIssue{
				{RuleName: "Rule_One", Message: "Correct the first condition."},
				{RuleName: "Rule_Two", Message: "Correct the second condition."},
			},
		},
		{name: "ordinary validation error", request: request, err: apperrors.NewValidationError("Status", "invalid")},
		{
			name: "mixed client-visible aggregate", request: request,
			err: apperrors.NewClientValidationErrors(
				apperrors.NewValidationRuleError("Rule_One", "Correct the record."),
				apperrors.NewValidationError("Status", "invalid"),
			),
		},
		{
			name: "internal wrapper owns typed cause", request: request,
			err: apperrors.NewInternalError(
				"record write failed",
				apperrors.NewValidationRuleError("Rule_One", "Correct the record."),
			),
		},
		{name: "over issue limit", request: request, err: apperrors.NewValidationRuleFailures(overLimit)},
		{
			name: "non-submit operation",
			request: approvalsemantic.ExecuteRequest{
				Operation:      approvalsemantic.OperationApprove,
				IdempotencyKey: "request-1",
				WorkItemID:     "work-1",
			},
			err: twoRules,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			response, ok := approvalSubmitValidationRejectionResponse(test.request, test.err)
			wantOK := len(test.wantIssues) != 0
			if ok != wantOK {
				t.Fatalf("mapped=%v response=%#v, want mapped=%v", ok, response, wantOK)
			}
			if wantOK && (response.SubmitRejection == nil ||
				response.SubmitRejection.Reason != approvalsemantic.SubmitRejectionRecordValidationFailed ||
				!reflect.DeepEqual(response.SubmitRejection.ValidationIssues, test.wantIssues) ||
				response.TargetRecordID != test.request.TargetRecordID) {
				t.Fatalf("response=%#v, want issues=%#v", response, test.wantIssues)
			}
		})
	}
}

func TestApprovalResponseAfterRollbackRejectsUncertainRollbackOutcomes(t *testing.T) {
	response := approvalsemantic.ExecuteResponse{TargetRecordID: "record-1"}
	presentation := &approvalPresentationRollback{response: response}
	for _, test := range []struct {
		name       string
		completion ports.TransactionCompletionOutcome
		err        error
		wantOK     bool
	}{
		{
			name: "direct presentation", completion: ports.TransactionCompletionRolledBack,
			err: presentation, wantOK: true,
		},
		{
			name: "transparent wrapper", completion: ports.TransactionCompletionRolledBack,
			err: fmt.Errorf("transaction: %w", presentation), wantOK: true,
		},
		{
			name: "internal rollback failure", completion: ports.TransactionCompletionRollbackError,
			err: apperrors.NewInternalError("rollback failed", presentation),
		},
		{
			name: "joined rollback outcome", completion: ports.TransactionCompletionRolledBack,
			err: errors.Join(presentation, errors.New("rollback outcome unknown")),
		},
		{name: "committed", completion: ports.TransactionCompletionCommitted, err: presentation},
		{name: "ambient transaction without terminal outcome", err: presentation},
	} {
		t.Run(test.name, func(t *testing.T) {
			got, ok := approvalResponseAfterRollback(test.completion, test.err)
			if ok != test.wantOK || (ok && !reflect.DeepEqual(got, response)) {
				t.Fatalf("response=%#v mapped=%v, want response=%#v mapped=%v", got, ok, response, test.wantOK)
			}
		})
	}
}

func TestApprovalExecutionAdapterPreservesEveryPublishedOperationShape(t *testing.T) {
	tests := []struct {
		name      string
		operation approvalsemantic.Operation
		state     string
		wantState approvalsemantic.InstanceState
		pending   bool
	}{
		{name: "submit", operation: approvalsemantic.OperationSubmit, state: "Pending", wantState: approvalsemantic.InstanceStatePending, pending: true},
		{name: "approve", operation: approvalsemantic.OperationApprove, state: "Approved", wantState: approvalsemantic.InstanceStateApproved},
		{name: "reject", operation: approvalsemantic.OperationReject, state: "Rejected", wantState: approvalsemantic.InstanceStateRejected},
		{name: "recall", operation: approvalsemantic.OperationRecall, state: "Pending", wantState: approvalsemantic.InstanceStateWithdrawn},
		{name: "reassign", operation: approvalsemantic.OperationReassign, state: "Pending", wantState: approvalsemantic.InstanceStatePending, pending: true},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			request := approvalsemantic.ExecuteRequest{
				Operation: test.operation, IdempotencyKey: "approval-operation-1",
				WorkItemID: "work-source-1",
			}
			if test.operation == approvalsemantic.OperationSubmit {
				request.ObjectID = "WorkItem"
				request.TargetRecordID = "record-1"
				request.WorkItemID = ""
			}
			if test.operation == approvalsemantic.OperationReassign {
				request.NextActorID = "user-next-1"
			}
			result := models.SObject{
				"ProcessInstanceId": "instance-1",
				"TargetObjectId":    "record-1",
				"InstanceStatus":    test.state,
			}
			if test.pending {
				result["ActorIds"] = []string{"user-next-1"}
				result["NewWorkitemIds"] = []string{"work-next-1"}
			}
			response, err := approvalExecuteResponseFromEngine(request, result)
			if err != nil {
				t.Fatal(err)
			}
			if response.State != test.wantState || response.InstanceID != "instance-1" ||
				response.TargetRecordID != "record-1" {
				t.Fatalf("operation response = %#v", response)
			}
			if test.operation == approvalsemantic.OperationSubmit {
				if response.SourceWorkItemID != "" {
					t.Fatalf("submit source work item = %q", response.SourceWorkItemID)
				}
			} else if response.SourceWorkItemID != request.WorkItemID {
				t.Fatalf("source work item = %q", response.SourceWorkItemID)
			}
			if test.pending != (len(response.PendingWorkItems) == 1) {
				t.Fatalf("pending work items = %#v", response.PendingWorkItems)
			}
		})
	}
}
