package issuetrackerconformance

import (
	"bytes"
	"context"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"reflect"
	"sort"
	"strings"
	"testing"

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

func TestIssueWorkflowManagedRegistrationIsSealedNeutralAndDeep(t *testing.T) {
	base, lifecycle, err := NewIssueWorkflowManagedLifecycleRegistration()
	if err != nil {
		t.Fatal(err)
	}
	if base.ManagedProvider != nil {
		t.Fatal("CI-only lifecycle fixture unexpectedly exposes the legacy five-callback provider")
	}
	if base.Contract.Kind != IssueWorkflowComponentKind || lifecycle.Kind() != IssueWorkflowComponentKind {
		t.Fatalf("registration kinds = %q/%q", base.Contract.Kind, lifecycle.Kind())
	}
	if len(base.Contract.WriteSet) != 3 || len(lifecycle.ReadSet()) != 4 {
		t.Fatalf("write/read surfaces = %#v/%#v", base.Contract.WriteSet, lifecycle.ReadSet())
	}
	writeTables := map[string]bool{}
	for _, surface := range base.Contract.WriteSet {
		writeTables[surface.Table] = true
	}
	if writeTables[issueWorkflowOwnerGuardTable] {
		t.Fatal("read-only owner guard leaked into the write set")
	}
	readGuard := false
	for _, surface := range lifecycle.ReadSet() {
		readGuard = readGuard || surface.Table == issueWorkflowOwnerGuardTable
	}
	if !readGuard {
		t.Fatal("read-only owner guard is absent from the read set")
	}
	if got := lifecycle.EffectClasses(); !reflect.DeepEqual(got, []cp.ComponentManagedEffectClass{IssueWorkflowRevisionEffectClass}) {
		t.Fatalf("effect classes = %#v", got)
	}
	if got := lifecycle.Budget().MaxBatchRows; got != issueWorkflowMaximumChildRows {
		t.Fatalf("managed maximum batch rows = %d, want %d", got, issueWorkflowMaximumChildRows)
	}
	if _, err := base.WithManagedLifecycle(lifecycle); err != nil {
		t.Fatalf("bind lifecycle: %v", err)
	}

	payload := issueWorkflowPayloadForTest(t, []byte{0, 'P'}, []byte{0xff, 0, 'W'}, []IssueWorkflowStatus{{Key: "Open", Label: "Open"}}, nil)
	request, err := NewIssueWorkflowManagedRequest("fixture", payload)
	if err != nil {
		t.Fatal(err)
	}
	build := &issueWorkflowBuildContextForTest{packName: "fixture"}
	if err := base.BuildHandler(build, cp.ComponentBuildRequest{PackName: "fixture", Component: request.Component, Payload: payload}); err != nil {
		t.Fatal(err)
	}
	if len(build.managed) != 1 || !bytes.Equal(build.managed[0].ExpectedProjection, request.ExpectedProjection) || len(build.managed[0].CollisionClaims) != 1 {
		t.Fatalf("managed build descriptor = %#v", build.managed)
	}
}

func TestIssueWorkflowManagedItemUsesCompoundBinaryTargetAndUnorderedProjection(t *testing.T) {
	_, lifecycle, err := NewIssueWorkflowManagedLifecycleRegistration()
	if err != nil {
		t.Fatal(err)
	}
	projectKey, workflowKey := []byte{0, 'P'}, []byte{0xff, 0, 'W'}
	payload := issueWorkflowPayloadForTest(t, projectKey, workflowKey,
		[]IssueWorkflowStatus{{Key: "Closed", Label: "Closed"}, {Key: "Open", Label: "Open"}},
		[]IssueWorkflowTransition{{Key: "Reopen", From: "Closed", To: "Open"}, {Key: "Close", From: "Open", To: "Closed"}},
	)
	managed, err := NewIssueWorkflowManagedRequest("fixture", payload)
	if err != nil {
		t.Fatal(err)
	}
	request := cp.NewComponentManagedItemLifecycleRequest(managed)
	store := newIssueWorkflowMemoryStore("fixture")
	plan, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeItem, request, store)
	if err != nil {
		t.Fatal(err)
	}
	wantTarget := []byte{1, 0, 0, 0, 2, 0, 'P', 0, 0, 0, 3, 0xff, 0, 'W'}
	foundItem, foundSet := false, false
	for _, target := range plan.Targets() {
		switch target.TargetDomain {
		case issueWorkflowTargetDomain:
			foundItem = bytes.Equal(target.PhysicalKeyBytes, wantTarget)
		case issueWorkflowSetTargetDomain:
			foundSet = bytes.Equal(target.PhysicalKeyBytes, []byte{0})
		}
	}
	if !foundItem || !foundSet {
		t.Fatalf("item serialization footprint = %#v", plan.Targets())
	}
	if got := plan.Effects(); len(got) != 1 || got[0].Class != IssueWorkflowRevisionEffectClass || len(got[0].Triggers) != 2 {
		t.Fatalf("item effect requirement = %#v", got)
	}
	if err := lifecycle.ValidatePlanCapabilities(plan); err != nil {
		t.Fatalf("item plan registration validation: %v", err)
	}
	result, err := lifecycle.Lifecycle().Mutate(context.Background(), cp.ComponentManagedScopeItem, request, plan, store)
	if err != nil {
		t.Fatal(err)
	}
	if result.Disposition != cp.ComponentManagedMutationDesiredProjectionStaged {
		t.Fatalf("mutation result = %#v", result)
	}
	reverseIssueWorkflowRows(store.rows[issueWorkflowStatusTable])
	reverseIssueWorkflowRows(store.rows[issueWorkflowTransitionTable])
	projection, err := lifecycle.Lifecycle().Project(context.Background(), cp.ComponentManagedScopeItem, request, store)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(projection.Expected, projection.Live) {
		t.Fatalf("unordered keyed projection differs:\n%s\n%s", projection.Expected, projection.Live)
	}
	if err := projection.Validate(); err != nil {
		t.Fatal(err)
	}

	noChangePlan, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeItem, request, store)
	if err != nil {
		t.Fatal(err)
	}
	mutations := store.mutations
	noChange, err := lifecycle.Lifecycle().Mutate(context.Background(), cp.ComponentManagedScopeItem, request, noChangePlan, store)
	if err != nil {
		t.Fatal(err)
	}
	if noChange.Disposition != cp.ComponentManagedMutationNoChange || store.mutations != mutations {
		t.Fatalf("no-change result/mutations = %#v/%d->%d", noChange, mutations, store.mutations)
	}
	store.rows[issueWorkflowStatusTable][0]["Label"] = "Drifted"
	drifted, err := lifecycle.Lifecycle().Project(context.Background(), cp.ComponentManagedScopeItem, request, store)
	if err != nil {
		t.Fatal(err)
	}
	if bytes.Equal(drifted.Expected, drifted.Live) {
		t.Fatal("fresh item projection concealed status drift")
	}

	otherOwner, err := NewIssueWorkflowManagedRequest("other", payload)
	if err != nil {
		t.Fatal(err)
	}
	otherStore := newIssueWorkflowMemoryStore("other")
	otherPlan, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeItem, cp.NewComponentManagedItemLifecycleRequest(otherOwner), otherStore)
	if err != nil {
		t.Fatal(err)
	}
	if !sameIssueWorkflowTarget(plan.Targets(), otherPlan.Targets(), issueWorkflowTargetDomain) || !sameIssueWorkflowTarget(plan.Targets(), otherPlan.Targets(), issueWorkflowSetTargetDomain) {
		t.Fatalf("owner-independent item and set targets = %#v / %#v", plan.Targets(), otherPlan.Targets())
	}
}

func TestIssueWorkflowManagedCanonicalizesEmptyCollections(t *testing.T) {
	_, lifecycle, err := NewIssueWorkflowManagedLifecycleRegistration()
	if err != nil {
		t.Fatal(err)
	}
	payload := issueWorkflowPayloadForTest(t, []byte("P"), []byte("W"), []IssueWorkflowStatus{{Key: "Open", Label: "Open"}}, nil)
	managed, err := NewIssueWorkflowManagedRequest("fixture", payload)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Contains(managed.ExpectedProjection, []byte(`"transitions":[]`)) {
		t.Fatalf("zero-transition projection is not canonical: %s", managed.ExpectedProjection)
	}
	request := cp.NewComponentManagedItemLifecycleRequest(managed)
	store := newIssueWorkflowMemoryStore("fixture")
	plan, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeItem, request, store)
	if err != nil {
		t.Fatal(err)
	}
	if _, err := lifecycle.Lifecycle().Mutate(context.Background(), cp.ComponentManagedScopeItem, request, plan, store); err != nil {
		t.Fatal(err)
	}
	projection, err := lifecycle.Lifecycle().Project(context.Background(), cp.ComponentManagedScopeItem, request, store)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(projection.Expected, projection.Live) {
		t.Fatalf("zero-transition projection differs: %s / %s", projection.Expected, projection.Live)
	}

	set := cp.ComponentManagedSetRequest{PackName: "fixture", Kind: IssueWorkflowComponentKind}
	emptyRequest, err := cp.NewComponentManagedSetLifecycleRequest(set, nil)
	if err != nil {
		t.Fatal(err)
	}
	emptyProjection, err := lifecycle.Lifecycle().Project(context.Background(), cp.ComponentManagedScopeSet, emptyRequest, newIssueWorkflowMemoryStore("fixture"))
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(emptyProjection.Expected, emptyProjection.Live) || !bytes.Contains(emptyProjection.Expected, []byte(`"business_keys":[]`)) {
		t.Fatalf("empty set projection differs: %s / %s", emptyProjection.Expected, emptyProjection.Live)
	}
}

func TestIssueWorkflowManagedSetProjectionCanonicalizesDesiredOrder(t *testing.T) {
	_, lifecycle, err := NewIssueWorkflowManagedLifecycleRegistration()
	if err != nil {
		t.Fatal(err)
	}
	store := newIssueWorkflowMemoryStore("fixture")
	keys := []string{
		issueWorkflowBusinessKey([]byte("B"), []byte("W")),
		issueWorkflowBusinessKey([]byte("A"), []byte("W")),
	}
	for _, businessKey := range keys {
		projectKey, workflowKey, err := parseIssueWorkflowBusinessKey(businessKey)
		if err != nil {
			t.Fatal(err)
		}
		store.rows[issueWorkflowTable] = append(store.rows[issueWorkflowTable], cp.ComponentRow{
			"ProjectKey": projectKey, "WorkflowKey": workflowKey, "OwnerPack": "fixture", "Name": "Fixture workflow",
		})
	}
	request, err := cp.NewComponentManagedSetLifecycleRequest(
		cp.ComponentManagedSetRequest{PackName: "fixture", Kind: IssueWorkflowComponentKind}, keys,
	)
	if err != nil {
		t.Fatal(err)
	}
	projection, err := lifecycle.Lifecycle().Project(context.Background(), cp.ComponentManagedScopeSet, request, store)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(projection.Expected, projection.Live) {
		t.Fatalf("unordered desired set projection differs: %s / %s", projection.Expected, projection.Live)
	}
}

func TestIssueWorkflowManagedSetRemovesOwnerScopedOrphanChildren(t *testing.T) {
	_, lifecycle, err := NewIssueWorkflowManagedLifecycleRegistration()
	if err != nil {
		t.Fatal(err)
	}
	store := newIssueWorkflowMemoryStore("fixture")
	projectKey, workflowKey := []byte("P"), []byte("orphan")
	store.rows[issueWorkflowStatusTable] = []cp.ComponentRow{{
		"ProjectKey": projectKey, "WorkflowKey": workflowKey, "OwnerPack": "fixture", "StatusKey": "Open", "Label": "Open",
	}}
	store.rows[issueWorkflowTransitionTable] = []cp.ComponentRow{{
		"ProjectKey": projectKey, "WorkflowKey": workflowKey, "OwnerPack": "fixture", "TransitionKey": "Stay",
		"FromStatusKey": "Open", "ToStatusKey": "Open",
	}}
	request, err := cp.NewComponentManagedSetLifecycleRequest(
		cp.ComponentManagedSetRequest{PackName: "fixture", Kind: IssueWorkflowComponentKind}, nil,
	)
	if err != nil {
		t.Fatal(err)
	}
	if _, err := lifecycle.Lifecycle().Project(context.Background(), cp.ComponentManagedScopeSet, request, store); err == nil || !strings.Contains(err.Error(), "orphaned child rows") {
		t.Fatalf("orphaned set projection error = %v", err)
	}
	plan, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeSet, request, store)
	if err != nil {
		t.Fatal(err)
	}
	if len(plan.Targets()) != 2 || plan.Estimate().DeltaRows != 1+2*issueWorkflowMaximumRows || plan.Estimate().MutationStatements != 3 {
		t.Fatalf("orphan plan = targets %#v estimate %#v", plan.Targets(), plan.Estimate())
	}
	result, err := lifecycle.Lifecycle().Mutate(context.Background(), cp.ComponentManagedScopeSet, request, plan, store)
	if err != nil {
		t.Fatal(err)
	}
	if result.Disposition != cp.ComponentManagedMutationDesiredProjectionStaged {
		t.Fatalf("orphan mutation result = %#v", result)
	}
	if len(store.rows[issueWorkflowStatusTable]) != 0 || len(store.rows[issueWorkflowTransitionTable]) != 0 {
		t.Fatalf("orphan rows remain: %#v / %#v", store.rows[issueWorkflowStatusTable], store.rows[issueWorkflowTransitionTable])
	}
	projection, err := lifecycle.Lifecycle().Project(context.Background(), cp.ComponentManagedScopeSet, request, store)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(projection.Expected, projection.Live) {
		t.Fatalf("post-orphan set projection differs: %s / %s", projection.Expected, projection.Live)
	}
}

func TestIssueWorkflowManagedRejectsUntrustedDeclarationBeforeStoreRead(t *testing.T) {
	valid := issueWorkflowPayloadForTest(t, []byte("P"), []byte("W"), []IssueWorkflowStatus{{Key: "Open", Label: "Open"}}, nil)
	for name, edit := range map[string]func(*cp.ComponentManagedRequest){
		"source owner": func(request *cp.ComponentManagedRequest) { request.SourceOwner = "source" },
		"business key": func(request *cp.ComponentManagedRequest) { request.Component.BusinessKey += "x" },
		"projection":   func(request *cp.ComponentManagedRequest) { request.ExpectedProjection = []byte(`{}`) },
	} {
		t.Run(name, func(t *testing.T) {
			managed, err := NewIssueWorkflowManagedRequest("fixture", valid)
			if err != nil {
				t.Fatal(err)
			}
			edit(&managed)
			store := &issueWorkflowReadCountingStore{}
			if _, err := issueWorkflowLifecyclePlan(context.Background(), cp.ComponentManagedScopeItem, cp.NewComponentManagedItemLifecycleRequest(managed), store); err == nil {
				t.Fatal("untrusted request was accepted")
			}
			if store.reads != 0 {
				t.Fatalf("untrusted request reached store %d times", store.reads)
			}
		})
	}
	tooLong := strings.Repeat("x", issueWorkflowMaximumText+1)
	if _, err := NewIssueWorkflowManagedRequest("fixture", issueWorkflowPayloadForTest(t, []byte("P"), []byte("W"), []IssueWorkflowStatus{{Key: "Open", Label: tooLong}}, nil)); err == nil {
		t.Fatal("oversized status label was accepted")
	}
	unknown := append(valid[:len(valid)-1], []byte(`,"unknown":true}`)...)
	if _, err := NewIssueWorkflowManagedRequest("fixture", unknown); err == nil {
		t.Fatal("unknown declaration field was accepted")
	}
}

func TestIssueWorkflowManagedSetRemovesStaleAggregateExactly(t *testing.T) {
	_, lifecycle, err := NewIssueWorkflowManagedLifecycleRegistration()
	if err != nil {
		t.Fatal(err)
	}
	store := newIssueWorkflowMemoryStore("fixture")
	requests := make([]cp.ComponentManagedRequest, 0, 2)
	for index := 1; index <= 2; index++ {
		payload := issueWorkflowPayloadForTest(t, []byte{byte(index)}, []byte{0, byte(index)},
			[]IssueWorkflowStatus{{Key: "Open", Label: "Open"}, {Key: "Closed", Label: "Closed"}},
			[]IssueWorkflowTransition{{Key: "Close", From: "Open", To: "Closed"}},
		)
		managed, err := NewIssueWorkflowManagedRequest("fixture", payload)
		if err != nil {
			t.Fatal(err)
		}
		requests = append(requests, managed)
		item := cp.NewComponentManagedItemLifecycleRequest(managed)
		plan, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeItem, item, store)
		if err != nil {
			t.Fatal(err)
		}
		if _, err := lifecycle.Lifecycle().Mutate(context.Background(), cp.ComponentManagedScopeItem, item, plan, store); err != nil {
			t.Fatal(err)
		}
	}
	set := cp.ComponentManagedSetRequest{PackName: "fixture", Kind: IssueWorkflowComponentKind}
	setRequest, err := cp.NewComponentManagedSetLifecycleRequest(set, []string{requests[0].Component.BusinessKey})
	if err != nil {
		t.Fatal(err)
	}
	plan, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeSet, setRequest, store)
	if err != nil {
		t.Fatal(err)
	}
	if len(plan.Targets()) != 3 || plan.Estimate().DeltaRows != 1+2*issueWorkflowMaximumRows || plan.Estimate().MutationStatements != 3 {
		t.Fatalf("set plan = targets %#v estimate %#v", plan.Targets(), plan.Estimate())
	}
	if err := lifecycle.ValidatePlanCapabilities(plan); err != nil {
		t.Fatalf("set plan registration validation: %v", err)
	}
	result, err := lifecycle.Lifecycle().Mutate(context.Background(), cp.ComponentManagedScopeSet, setRequest, plan, store)
	if err != nil {
		t.Fatal(err)
	}
	if result.Disposition != cp.ComponentManagedMutationDesiredProjectionStaged {
		t.Fatalf("set mutation result = %#v", result)
	}
	projection, err := lifecycle.Lifecycle().Project(context.Background(), cp.ComponentManagedScopeSet, setRequest, store)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(projection.Expected, projection.Live) {
		t.Fatalf("set projection differs: %s / %s", projection.Expected, projection.Live)
	}
	staleProject, staleWorkflow, _ := parseIssueWorkflowBusinessKey(requests[1].Component.BusinessKey)
	for _, table := range []string{issueWorkflowTable, issueWorkflowStatusTable, issueWorkflowTransitionTable} {
		for _, row := range store.rows[table] {
			if issueWorkflowValueEqual(row["ProjectKey"], staleProject) && issueWorkflowValueEqual(row["WorkflowKey"], staleWorkflow) {
				t.Fatalf("stale aggregate remains in %s: %#v", table, row)
			}
		}
	}
}

func TestIssueWorkflowManagedBoundsDesiredRowsBeforeStoreRead(t *testing.T) {
	_, lifecycle, err := NewIssueWorkflowManagedLifecycleRegistration()
	if err != nil {
		t.Fatal(err)
	}
	for _, child := range []string{"status", "transition"} {
		t.Run(child, func(t *testing.T) {
			managed := issueWorkflowCardinalityRequestForTest(t, child, issueWorkflowMaximumRows+1)
			store := &issueWorkflowReadCountingStore{}
			_, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeItem, cp.NewComponentManagedItemLifecycleRequest(managed), store)
			want := fmt.Sprintf("%d desired %s rows; maximum is %d", issueWorkflowMaximumRows+1, child, issueWorkflowMaximumRows)
			if err == nil || !strings.Contains(err.Error(), want) {
				t.Fatalf("overflow error = %v", err)
			}
			if store.reads != 0 {
				t.Fatalf("store reads before desired bound = %d", store.reads)
			}
		})
	}
	for _, child := range []string{"status", "transition"} {
		t.Run("exact_"+child, func(t *testing.T) {
			managed := issueWorkflowCardinalityRequestForTest(t, child, issueWorkflowMaximumRows)
			if _, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeItem, cp.NewComponentManagedItemLifecycleRequest(managed), newIssueWorkflowMemoryStore("fixture")); err != nil {
				t.Fatalf("exact %s limit rejected: %v", child, err)
			}
		})
	}
	set := cp.ComponentManagedSetRequest{PackName: "fixture", Kind: IssueWorkflowComponentKind}
	keys := make([]string, issueWorkflowMaximumRows+1)
	for index := range keys {
		keys[index] = issueWorkflowBusinessKey([]byte{byte(index + 1)}, []byte("W"))
	}
	setRequest, err := cp.NewComponentManagedSetLifecycleRequest(set, keys)
	if err != nil {
		t.Fatal(err)
	}
	counting := &issueWorkflowReadCountingStore{}
	if _, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeSet, setRequest, counting); err == nil || !strings.Contains(err.Error(), "9 desired workflows; maximum is 8") {
		t.Fatalf("desired set overflow error = %v", err)
	}
	if counting.reads != 0 {
		t.Fatalf("store reads before desired set bound = %d", counting.reads)
	}
	exactRequest, err := cp.NewComponentManagedSetLifecycleRequest(set, keys[:issueWorkflowMaximumRows])
	if err != nil {
		t.Fatal(err)
	}
	exactPlan, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeSet, exactRequest, newIssueWorkflowMemoryStore("fixture"))
	if err != nil {
		t.Fatalf("exact desired workflow limit rejected: %v", err)
	}
	if err := lifecycle.ValidatePlanCapabilities(exactPlan); err != nil {
		t.Fatalf("exact desired workflow plan validation: %v", err)
	}
	overflowCurrent := newIssueWorkflowMemoryStore("fixture")
	for index := 0; index < issueWorkflowMaximumChildRows+1; index++ {
		overflowCurrent.rows[issueWorkflowStatusTable] = append(overflowCurrent.rows[issueWorkflowStatusTable], cp.ComponentRow{
			"ProjectKey": []byte("P"), "WorkflowKey": []byte("W"), "OwnerPack": "fixture",
			"StatusKey": fmt.Sprintf("S%03d", index), "Label": "Overflow",
		})
	}
	emptySet, err := cp.NewComponentManagedSetLifecycleRequest(set, nil)
	if err != nil {
		t.Fatal(err)
	}
	if _, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeSet, emptySet, overflowCurrent); err == nil || !strings.Contains(err.Error(), "maximum rows 64") {
		t.Fatalf("current child-row overflow error = %v", err)
	}
	overflowPerTarget := newIssueWorkflowMemoryStore("fixture")
	for index := 0; index < issueWorkflowMaximumRows+1; index++ {
		overflowPerTarget.rows[issueWorkflowStatusTable] = append(overflowPerTarget.rows[issueWorkflowStatusTable], cp.ComponentRow{
			"ProjectKey": []byte("P"), "WorkflowKey": []byte("W"), "OwnerPack": "fixture",
			"StatusKey": fmt.Sprintf("S%03d", index), "Label": "Overflow",
		})
	}
	if _, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeSet, emptySet, overflowPerTarget); err == nil || !strings.Contains(err.Error(), "9 status rows; maximum is 8") {
		t.Fatalf("current per-target overflow error = %v", err)
	}
	overflowTargets := newIssueWorkflowMemoryStore("fixture")
	for index := 0; index < issueWorkflowMaximumRows+1; index++ {
		overflowTargets.rows[issueWorkflowStatusTable] = append(overflowTargets.rows[issueWorkflowStatusTable], cp.ComponentRow{
			"ProjectKey": []byte{byte(index + 1)}, "WorkflowKey": []byte("W"), "OwnerPack": "fixture",
			"StatusKey": "Open", "Label": "Open",
		})
	}
	if _, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeSet, emptySet, overflowTargets); err == nil || !strings.Contains(err.Error(), "9 physical workflows; maximum is 8") {
		t.Fatalf("current target overflow error = %v", err)
	}
}

func TestIssueWorkflowManagedSetFitsExactDeclaredBudgetBoundary(t *testing.T) {
	_, lifecycle, err := NewIssueWorkflowManagedLifecycleRegistration()
	if err != nil {
		t.Fatal(err)
	}
	store := newIssueWorkflowMemoryStore("fixture")
	desiredKeys := make([]string, issueWorkflowMaximumRows)
	for workflow := 0; workflow < issueWorkflowMaximumRows; workflow++ {
		projectKey, workflowKey := []byte{byte(workflow + 1)}, []byte("live")
		store.rows[issueWorkflowTable] = append(store.rows[issueWorkflowTable], cp.ComponentRow{
			"ProjectKey": projectKey, "WorkflowKey": workflowKey, "OwnerPack": "fixture", "Name": "Live",
		})
		for child := 0; child < issueWorkflowMaximumRows; child++ {
			statusKey := fmt.Sprintf("S%02d", child)
			store.rows[issueWorkflowStatusTable] = append(store.rows[issueWorkflowStatusTable], cp.ComponentRow{
				"ProjectKey": projectKey, "WorkflowKey": workflowKey, "OwnerPack": "fixture", "StatusKey": statusKey, "Label": statusKey,
			})
			store.rows[issueWorkflowTransitionTable] = append(store.rows[issueWorkflowTransitionTable], cp.ComponentRow{
				"ProjectKey": projectKey, "WorkflowKey": workflowKey, "OwnerPack": "fixture", "TransitionKey": fmt.Sprintf("T%02d", child),
				"FromStatusKey": statusKey, "ToStatusKey": statusKey,
			})
		}
		desiredKeys[workflow] = issueWorkflowBusinessKey([]byte{byte(workflow + 1)}, []byte("desired"))
	}
	request, err := cp.NewComponentManagedSetLifecycleRequest(
		cp.ComponentManagedSetRequest{PackName: "fixture", Kind: IssueWorkflowComponentKind}, desiredKeys,
	)
	if err != nil {
		t.Fatal(err)
	}
	plan, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeSet, request, store)
	if err != nil {
		t.Fatal(err)
	}
	want := cp.ComponentManagedUsage{
		CurrentItems: 273, DesiredItems: 8, DeltaRows: 136, MutationStatements: 24,
		EvidenceWrites: 1, EffectCalls: 1, BatchRows: issueWorkflowMaximumChildRows,
	}
	if len(plan.Targets()) != 17 || plan.Estimate() != want {
		t.Fatalf("exact budget plan = targets %d estimate %#v, want 17/%#v", len(plan.Targets()), plan.Estimate(), want)
	}
	if err := lifecycle.ValidatePlanCapabilities(plan); err != nil {
		t.Fatalf("exact budget plan registration validation: %v", err)
	}
}

func TestIssueWorkflowManagedFailsClosedOnGuardCollisionAndReadOverflow(t *testing.T) {
	_, lifecycle, err := NewIssueWorkflowManagedLifecycleRegistration()
	if err != nil {
		t.Fatal(err)
	}
	managed, err := NewIssueWorkflowManagedRequest("fixture", issueWorkflowPayloadForTest(t, []byte("P"), []byte("W"), []IssueWorkflowStatus{{Key: "Open", Label: "Open"}}, nil))
	if err != nil {
		t.Fatal(err)
	}
	request := cp.NewComponentManagedItemLifecycleRequest(managed)
	for name, store := range map[string]cp.ComponentManagedReadStore{
		"missing guard":  &issueWorkflowMemoryStore{rows: map[string][]cp.ComponentRow{}},
		"disabled guard": &issueWorkflowMemoryStore{rows: map[string][]cp.ComponentRow{issueWorkflowOwnerGuardTable: {{"OwnerPack": "fixture", "Enabled": false}}}},
		"over-return":    issueWorkflowOverReturnStore{},
	} {
		t.Run(name, func(t *testing.T) {
			if _, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeItem, request, store); err == nil {
				t.Fatal("unsafe state was accepted")
			}
		})
	}
	collision := newIssueWorkflowMemoryStore("fixture")
	projectKey, workflowKey, _ := parseIssueWorkflowBusinessKey(managed.Component.BusinessKey)
	collision.rows[issueWorkflowTable] = []cp.ComponentRow{{"ProjectKey": projectKey, "WorkflowKey": workflowKey, "OwnerPack": "other", "Name": "Collision"}}
	if _, err := lifecycle.Lifecycle().Plan(context.Background(), cp.ComponentManagedScopeItem, request, collision); err == nil || !strings.Contains(err.Error(), "owned by \"other\"") {
		t.Fatalf("owner collision error = %v", err)
	}
}

func issueWorkflowPayloadForTest(t *testing.T, projectKey, workflowKey []byte, statuses []IssueWorkflowStatus, transitions []IssueWorkflowTransition) []byte {
	t.Helper()
	payload, err := json.Marshal(IssueWorkflowDeclaration{
		ProjectKey: base64.RawURLEncoding.EncodeToString(projectKey), WorkflowKey: base64.RawURLEncoding.EncodeToString(workflowKey),
		Name: "Fixture workflow", Statuses: statuses, Transitions: transitions,
	})
	if err != nil {
		t.Fatal(err)
	}
	return payload
}

func issueWorkflowCardinalityRequestForTest(t *testing.T, child string, count int) cp.ComponentManagedRequest {
	t.Helper()
	statuses := []IssueWorkflowStatus{{Key: "Open", Label: "Open"}, {Key: "Closed", Label: "Closed"}}
	transitions := []IssueWorkflowTransition(nil)
	switch child {
	case "status":
		statuses = make([]IssueWorkflowStatus, count)
		for index := range statuses {
			statuses[index] = IssueWorkflowStatus{Key: fmt.Sprintf("S%03d", index), Label: fmt.Sprintf("Status %03d", index)}
		}
	case "transition":
		transitions = make([]IssueWorkflowTransition, count)
		for index := range transitions {
			transitions[index] = IssueWorkflowTransition{Key: fmt.Sprintf("T%03d", index), From: "Open", To: "Closed"}
		}
	default:
		t.Fatalf("unsupported child %q", child)
	}
	managed, err := NewIssueWorkflowManagedRequest("fixture", issueWorkflowPayloadForTest(t, []byte("P"), []byte("W"), statuses, transitions))
	if err != nil {
		t.Fatal(err)
	}
	return managed
}

func sameIssueWorkflowTarget(left, right []cp.ComponentManagedTarget, domain string) bool {
	var leftKey, rightKey []byte
	for _, target := range left {
		if target.TargetDomain == domain {
			leftKey = target.PhysicalKeyBytes
		}
	}
	for _, target := range right {
		if target.TargetDomain == domain {
			rightKey = target.PhysicalKeyBytes
		}
	}
	return len(leftKey) != 0 && bytes.Equal(leftKey, rightKey)
}

func reverseIssueWorkflowRows(rows []cp.ComponentRow) {
	for left, right := 0, len(rows)-1; left < right; left, right = left+1, right-1 {
		rows[left], rows[right] = rows[right], rows[left]
	}
}

type issueWorkflowBuildContextForTest struct {
	packName string
	managed  []cp.ComponentBuildManagedComponent
}

func (c *issueWorkflowBuildContextForTest) PackName() string { return c.packName }
func (*issueWorkflowBuildContextForTest) LookupObjectSchema(string) (cp.ComponentObjectSchema, bool) {
	return cp.ComponentObjectSchema{}, false
}
func (c *issueWorkflowBuildContextForTest) AddManagedComponent(value cp.ComponentBuildManagedComponent) error {
	c.managed = append(c.managed, value)
	return nil
}
func (*issueWorkflowBuildContextForTest) AddRuntimeStartupShallowDeclaration(cp.ComponentKind, string, []byte) error {
	return fmt.Errorf("unexpected runtime startup declaration")
}

type issueWorkflowMemoryStore struct {
	rows      map[string][]cp.ComponentRow
	reads     int
	locks     int
	mutations int
}

func newIssueWorkflowMemoryStore(packName string) *issueWorkflowMemoryStore {
	return &issueWorkflowMemoryStore{rows: map[string][]cp.ComponentRow{
		issueWorkflowOwnerGuardTable: {{"OwnerPack": packName, "Enabled": true}},
	}}
}

func (s *issueWorkflowMemoryStore) ReadRows(_ context.Context, query cp.ComponentManagedRowQuery) ([]cp.ComponentRow, error) {
	s.reads++
	return s.read(query)
}

func (s *issueWorkflowMemoryStore) LockRows(_ context.Context, query cp.ComponentManagedRowQuery) ([]cp.ComponentRow, error) {
	s.locks++
	return s.read(query)
}

func (s *issueWorkflowMemoryStore) read(query cp.ComponentManagedRowQuery) ([]cp.ComponentRow, error) {
	if err := query.Validate(issueWorkflowMaximumChildRows); err != nil {
		return nil, err
	}
	rows := make([]cp.ComponentRow, 0)
	for _, row := range s.rows[query.Table] {
		if !issueWorkflowRowMatches(row, query.Equal) {
			continue
		}
		projection := make(cp.ComponentRow, len(query.Columns))
		for _, column := range query.Columns {
			if value, ok := row[column]; ok {
				projection[column] = issueWorkflowCloneValue(value)
			}
		}
		rows = append(rows, projection)
	}
	sort.Slice(rows, func(i, j int) bool { return issueWorkflowRowsLess(rows[i], rows[j], query.OrderBy) })
	if len(rows) > query.MaximumRows {
		return nil, fmt.Errorf("test issue workflow read exceeded maximum rows %d", query.MaximumRows)
	}
	return rows, nil
}

func (*issueWorkflowMemoryStore) NewID() (string, error) { return "unused", nil }

func (s *issueWorkflowMemoryStore) InsertRows(_ context.Context, batch cp.ComponentManagedInsertBatch) (int64, error) {
	if err := batch.Validate(issueWorkflowMaximumChildRows); err != nil {
		return 0, err
	}
	s.mutations++
	for _, insert := range batch.Rows {
		row := make(cp.ComponentRow, len(insert.Values))
		for column, value := range insert.Values {
			row[column] = issueWorkflowCloneValue(value)
		}
		s.rows[batch.Table] = append(s.rows[batch.Table], row)
	}
	return int64(len(batch.Rows)), nil
}

func (s *issueWorkflowMemoryStore) UpdateRows(_ context.Context, update cp.ComponentManagedUpdate) (int64, error) {
	if err := update.Validate(issueWorkflowMaximumChildRows); err != nil {
		return 0, err
	}
	s.mutations++
	affected := 0
	for _, row := range s.rows[update.Table] {
		if !issueWorkflowRowMatches(row, update.Match) {
			continue
		}
		for column, value := range update.Values {
			row[column] = issueWorkflowCloneValue(value)
		}
		affected++
	}
	if affected > update.MaximumAffectedRows {
		return 0, fmt.Errorf("test update affected %d rows, maximum %d", affected, update.MaximumAffectedRows)
	}
	return int64(affected), nil
}

func (s *issueWorkflowMemoryStore) DeleteRows(_ context.Context, deletion cp.ComponentManagedDelete) (int64, error) {
	if err := deletion.Validate(issueWorkflowMaximumChildRows); err != nil {
		return 0, err
	}
	s.mutations++
	kept := s.rows[deletion.Table][:0]
	affected := 0
	for _, row := range s.rows[deletion.Table] {
		if issueWorkflowRowMatches(row, deletion.Match) {
			affected++
			continue
		}
		kept = append(kept, row)
	}
	if affected > deletion.MaximumAffectedRows {
		return 0, fmt.Errorf("test delete affected %d rows, maximum %d", affected, deletion.MaximumAffectedRows)
	}
	s.rows[deletion.Table] = kept
	return int64(affected), nil
}

func (*issueWorkflowMemoryStore) ActualReceipt() cp.ComponentManagedMutationReceipt {
	return cp.ComponentManagedMutationReceipt{}
}

func issueWorkflowRowMatches(row, equal cp.ComponentRow) bool {
	for column, want := range equal {
		got, ok := row[column]
		if !ok || !issueWorkflowValueEqual(got, want) {
			return false
		}
	}
	return true
}

func issueWorkflowValueEqual(left, right any) bool {
	leftBytes, leftOK := left.([]byte)
	rightBytes, rightOK := right.([]byte)
	if leftOK || rightOK {
		return leftOK && rightOK && bytes.Equal(leftBytes, rightBytes)
	}
	return reflect.DeepEqual(left, right)
}

func issueWorkflowCloneValue(value any) any {
	if raw, ok := value.([]byte); ok {
		return append([]byte(nil), raw...)
	}
	return value
}

func issueWorkflowRowsLess(left, right cp.ComponentRow, order []cp.ComponentManagedOrder) bool {
	for _, item := range order {
		comparison := issueWorkflowCompareValue(left[item.Column], right[item.Column])
		if comparison == 0 {
			continue
		}
		if item.Direction == cp.ComponentManagedOrderDescending {
			return comparison > 0
		}
		return comparison < 0
	}
	return false
}

func issueWorkflowCompareValue(left, right any) int {
	leftBytes, leftOK := left.([]byte)
	rightBytes, rightOK := right.([]byte)
	if leftOK && rightOK {
		return bytes.Compare(leftBytes, rightBytes)
	}
	return strings.Compare(fmt.Sprint(left), fmt.Sprint(right))
}

type issueWorkflowReadCountingStore struct{ reads int }

func (s *issueWorkflowReadCountingStore) ReadRows(context.Context, cp.ComponentManagedRowQuery) ([]cp.ComponentRow, error) {
	s.reads++
	return nil, nil
}

type issueWorkflowOverReturnStore struct{}

func (issueWorkflowOverReturnStore) ReadRows(_ context.Context, query cp.ComponentManagedRowQuery) ([]cp.ComponentRow, error) {
	return make([]cp.ComponentRow, query.MaximumRows+1), nil
}
