package layoutvalidationviewv1

import (
	"bytes"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"strconv"
	"strings"
	"testing"

	"github.com/pingcap-inc/nexuscrm-contract/pkg/catalogassignmentidentityv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/catalogpublicationv1"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/internal/testvectors"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/layoutbundlekeyv1"
)

func TestConformanceVectors(t *testing.T) {
	document := readVectorDocument(t)
	if document.SchemaVersion != "nexuscrm.layout-validation-view-conformance/v1" {
		t.Fatalf("schema_version = %q", document.SchemaVersion)
	}
	vector := document.CanonicalView
	if vector.Name != "all-entry-kinds-permuted" {
		t.Fatalf("canonical vector name = %q", vector.Name)
	}
	view := vector.View.value(t)
	assignment := vector.AssignmentView.value(t)
	required := vector.RequiredBundleKeySet.value(t)
	if err := VerifyReferencedArtifacts(view, assignment, required); err != nil {
		t.Fatalf("referenced vector verification: %v", err)
	}
	canonical, err := CanonicalViewBytes(view)
	if err != nil {
		t.Fatal(err)
	}
	wantLength := vectorUint(t, "canonical_bytes_length", vector.CanonicalBytesLength)
	if uint64(len(canonical)) != wantLength {
		t.Fatalf("canonical length = %d, want %d", len(canonical), wantLength)
	}
	wantBytes, err := hex.DecodeString(vector.CanonicalBytesHex)
	if err != nil {
		t.Fatalf("canonical_bytes_hex: %v", err)
	}
	if !bytes.Equal(canonical, wantBytes) {
		first := 0
		for first < len(canonical) && first < len(wantBytes) && canonical[first] == wantBytes[first] {
			first++
		}
		start, end := first-16, first+32
		if start < 0 {
			start = 0
		}
		if end > len(canonical) {
			end = len(canonical)
		}
		wantEnd := end
		if wantEnd > len(wantBytes) {
			wantEnd = len(wantBytes)
		}
		t.Fatalf("canonical bytes differ at byte %d (got length %d, want length %d): got %s want %s", first, len(canonical), len(wantBytes), hex.EncodeToString(canonical[start:end]), hex.EncodeToString(wantBytes[start:wantEnd]))
	}
	digest, err := ViewDigest(view)
	if err != nil {
		t.Fatal(err)
	}
	if digest != vector.ViewDigest {
		t.Fatalf("view digest = %s, want %s", digest, vector.ViewDigest)
	}

	permuted := deepCopyView(t, view)
	reverse(permuted.Objects)
	reverse(permuted.Fields)
	reverse(permuted.Relationships)
	reverse(permuted.RelatedLists)
	reverse(permuted.Actions)
	reverse(permuted.RendererComponents)
	reverse(permuted.AcceptedLayoutFormats)
	reverse(permuted.BundleAuthorityEvidence)
	for index := range permuted.Objects {
		reverse(permuted.Objects[index].Capabilities)
	}
	for index := range permuted.Fields {
		reverse(permuted.Fields[index].ReferenceTargets)
	}
	for index := range permuted.RelatedLists {
		reverse(permuted.RelatedLists[index].Capabilities)
	}
	for index := range permuted.Actions {
		reverse(permuted.Actions[index].Capabilities)
	}
	for index := range permuted.RendererComponents {
		reverse(permuted.RendererComponents[index].Capabilities)
	}
	permutedBytes, err := CanonicalViewBytes(permuted)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(canonical, permutedBytes) {
		t.Fatal("vector permutation changed canonical bytes")
	}
	assertVectorCoverage(t, view)

	failureNames := map[string]bool{}
	for _, failure := range document.ValidationFailures {
		if failure.Name == "" || failureNames[failure.Name] {
			t.Fatalf("validation failure name %q is blank or duplicated", failure.Name)
		}
		failureNames[failure.Name] = true
		bad := deepCopyView(t, view)
		switch failure.Mutation {
		case "duplicate_first_object":
			bad.Objects = append(bad.Objects, bad.Objects[0])
		case "remove_first_relationship":
			bad.Relationships = bad.Relationships[1:]
		default:
			t.Fatalf("unknown validation mutation %q", failure.Mutation)
		}
		expectError(t, ValidateView(bad), failure.ErrorContains)
	}
	for _, requiredName := range []string{"duplicate-object", "missing-relationship"} {
		if !failureNames[requiredName] {
			t.Fatalf("required validation failure %q missing", requiredName)
		}
	}

	referencedNames := map[string]bool{}
	for _, failure := range document.ReferencedArtifactFailures {
		if failure.Name == "" || referencedNames[failure.Name] {
			t.Fatalf("referenced failure name %q is blank or duplicated", failure.Name)
		}
		referencedNames[failure.Name] = true
		badView := deepCopyView(t, view)
		badAssignment := assignment
		badRequired := required
		switch failure.Mutation {
		case "assignment_digest_mismatch":
			badView.CatalogAssignmentIdentityViewDigest = digestOf('9')
		case "assignment_source_mismatch":
			badAssignment.SourceCatalogSnapshot.CatalogRevision++
			badView.CatalogAssignmentIdentityViewDigest = mustAssignmentDigest(t, badAssignment)
		case "inactive_assignment_object":
			badAssignment.Objects = append([]catalogassignmentidentityv1.ObjectIdentity{}, assignment.Objects...)
			badAssignment.Objects[0].State = catalogassignmentidentityv1.IdentityStateTombstone
			badView.CatalogAssignmentIdentityViewDigest = mustAssignmentDigest(t, badAssignment)
		case "active_assignment_object_omitted_from_view":
			badAssignment.Objects = append(
				append([]catalogassignmentidentityv1.ObjectIdentity{}, assignment.Objects...),
				catalogassignmentidentityv1.ObjectIdentity{
					Key: objectKey("opportunity"), ResolvedObjectID: "object-opportunity",
					State: catalogassignmentidentityv1.IdentityStateActive,
				},
			)
			badView.CatalogAssignmentIdentityViewDigest = mustAssignmentDigest(t, badAssignment)
		case "required_digest_mismatch":
			badView.RequiredBundleKeySetDigest = digestOf('8')
		case "evidence_key_set_mismatch":
			badRequired.BundleKeys = append([]layoutbundlekeyv1.BundleKey{}, required.BundleKeys[1:]...)
			badView.RequiredBundleKeySetDigest = mustRequiredDigest(t, badRequired)
		default:
			t.Fatalf("unknown referenced mutation %q", failure.Mutation)
		}
		expectError(t, VerifyReferencedArtifacts(badView, badAssignment, badRequired), failure.ErrorContains)
	}
	for _, requiredName := range []string{
		"assignment-digest-mismatch", "assignment-source-mismatch", "inactive-assignment-object",
		"active-assignment-object-omitted-from-view", "required-digest-mismatch", "evidence-key-set-mismatch",
	} {
		if !referencedNames[requiredName] {
			t.Fatalf("required referenced failure %q missing", requiredName)
		}
	}

	fieldBoundaryNames := map[string]bool{}
	for _, boundary := range document.FieldNameBoundaries {
		if boundary.Name == "" || fieldBoundaryNames[boundary.Name] {
			t.Fatalf("field-name boundary %q is blank or duplicated", boundary.Name)
		}
		fieldBoundaryNames[boundary.Name] = true
		view := boundary.value(t)
		err := ValidateView(view)
		if boundary.Accepted {
			if err != nil {
				t.Fatalf("%s unexpectedly rejected: %v", boundary.Name, err)
			}
			continue
		}
		expectError(t, err, boundary.ErrorContains)
	}
	for _, requiredName := range []string{
		"ordinary-non-owner-64-accepted",
		"polymorphic-owner-59-accepted",
		"polymorphic-owner-60-rejected",
	} {
		if !fieldBoundaryNames[requiredName] {
			t.Fatalf("required field-name boundary %q missing", requiredName)
		}
	}

	recipeNames := map[string]bool{}
	for _, recipe := range document.UnsignedLEB128Recipes {
		if recipe.Name == "" || recipeNames[recipe.Name] {
			t.Fatalf("recipe name %q is blank or duplicated", recipe.Name)
		}
		recipeNames[recipe.Name] = true
		view := recipe.value(t)
		canonical, err := CanonicalViewBytes(view)
		if err != nil {
			t.Fatal(err)
		}
		wantSize := vectorUint(t, "canonical_bytes_length", recipe.CanonicalBytesLength)
		if uint64(len(canonical)) != wantSize {
			t.Fatalf("%s size = %d, want %d", recipe.Name, len(canonical), wantSize)
		}
		digest, err := ViewDigest(view)
		if err != nil {
			t.Fatal(err)
		}
		if digest != recipe.ViewDigest {
			t.Fatalf("%s digest = %s, want %s", recipe.Name, digest, recipe.ViewDigest)
		}
	}
	for _, requiredName := range []string{"count-and-length-127", "count-and-length-128"} {
		if !recipeNames[requiredName] {
			t.Fatalf("required recipe %q missing", requiredName)
		}
	}

	maximum := vectorUint(t, "maximum", document.AggregateSizeBoundary.Maximum)
	accepted := vectorUint(t, "accepted", document.AggregateSizeBoundary.Accepted)
	rejected := vectorUint(t, "rejected", document.AggregateSizeBoundary.Rejected)
	if maximum != MaxCanonicalViewBytes || accepted != maximum || rejected != maximum+1 {
		t.Fatalf("aggregate boundary = max %d accepted %d rejected %d", maximum, accepted, rejected)
	}
	measure := canonicalMeasure{limit: maximum}
	measure.add(accepted)
	if measure.exceeded {
		t.Fatal("aggregate accepted boundary rejected")
	}
	measure.add(rejected - accepted)
	if !measure.exceeded {
		t.Fatal("aggregate rejected boundary accepted")
	}
}

func TestConformanceVectorsJSONReturnsDefensiveCopy(t *testing.T) {
	testvectors.AssertDefensiveCopy(t, ConformanceVectorsJSON)
}

func assertVectorCoverage(t *testing.T, view View) {
	t.Helper()
	if len(view.Objects) == 0 || len(view.Fields) == 0 || len(view.Relationships) == 0 ||
		len(view.RelatedLists) == 0 || len(view.Actions) == 0 || len(view.RendererComponents) == 0 ||
		len(view.AcceptedLayoutFormats) == 0 || len(view.BundleAuthorityEvidence) != 3 {
		t.Fatal("canonical vector does not cover every entry kind")
	}
	boolFalse, boolTrue := [6]bool{}, [6]bool{}
	editAbsent, editPresent := false, false
	fieldRelationshipKinds := map[RelationshipKind]bool{}
	singleTargetOwnedLookup, multiTargetOwnedLookup := false, false
	multiObjectCapabilities, multiReferenceTargets := false, false
	multiRelatedListCapabilities, multiActionCapabilities, multiRendererCapabilities := false, false, false
	for _, object := range view.Objects {
		multiObjectCapabilities = multiObjectCapabilities || len(object.Capabilities) > 1
	}
	for _, field := range view.Fields {
		values := [6]bool{
			field.OwnsPolymorphicDiscriminator,
			field.RequiredOnCreate,
			field.Nillable,
			field.DefaultedOnCreate,
			field.Createable,
			field.Updateable,
		}
		for index, value := range values {
			boolTrue[index] = boolTrue[index] || value
			boolFalse[index] = boolFalse[index] || !value
		}
		editAbsent = editAbsent || field.EditContractKey == nil
		editPresent = editPresent || field.EditContractKey != nil
		fieldRelationshipKinds[field.RelationshipKind] = true
		if field.RelationshipKind == RelationshipKindLookup && field.OwnsPolymorphicDiscriminator {
			singleTargetOwnedLookup = singleTargetOwnedLookup || len(field.ReferenceTargets) == 1
			multiTargetOwnedLookup = multiTargetOwnedLookup || len(field.ReferenceTargets) > 1
		}
		multiReferenceTargets = multiReferenceTargets || len(field.ReferenceTargets) > 1
	}
	for index := range boolTrue {
		if !boolTrue[index] || !boolFalse[index] {
			t.Fatalf("canonical vector does not cover both boolean values at field index %d", index)
		}
	}
	if !editAbsent || !editPresent {
		t.Fatal("canonical vector does not cover both EditContractKey states")
	}
	targetAbsent, targetPresent := false, false
	relationshipKinds := map[RelationshipKind]bool{}
	ownerKinds := map[layoutbundlekeyv1.SlotOwnerKind]bool{}
	for _, action := range view.Actions {
		targetAbsent = targetAbsent || action.TargetObjectKey == nil
		targetPresent = targetPresent || action.TargetObjectKey != nil
		multiActionCapabilities = multiActionCapabilities || len(action.Capabilities) > 1
	}
	for _, relatedList := range view.RelatedLists {
		multiRelatedListCapabilities = multiRelatedListCapabilities || len(relatedList.Capabilities) > 1
	}
	for _, renderer := range view.RendererComponents {
		multiRendererCapabilities = multiRendererCapabilities || len(renderer.Capabilities) > 1
	}
	for _, relationship := range view.Relationships {
		relationshipKinds[relationship.Kind] = true
	}
	for _, evidence := range view.BundleAuthorityEvidence {
		ownerKinds[evidence.BundleKey.SlotOwnerKind] = true
	}
	if !targetAbsent || !targetPresent ||
		!fieldRelationshipKinds[RelationshipKindNone] ||
		!fieldRelationshipKinds[RelationshipKindLookup] ||
		!fieldRelationshipKinds[RelationshipKindMasterDetail] ||
		!singleTargetOwnedLookup || !multiTargetOwnedLookup ||
		!multiObjectCapabilities || !multiReferenceTargets ||
		!multiRelatedListCapabilities || !multiActionCapabilities || !multiRendererCapabilities ||
		!relationshipKinds[RelationshipKindLookup] || !relationshipKinds[RelationshipKindMasterDetail] ||
		!ownerKinds[layoutbundlekeyv1.SlotOwnerKindApp] || !ownerKinds[layoutbundlekeyv1.SlotOwnerKindTenant] || !ownerKinds[layoutbundlekeyv1.SlotOwnerKindSystem] {
		t.Fatal("canonical vector misses optional target, field-shape, relationship-kind, or evidence-owner coverage")
	}
	canonical, err := CanonicalizeView(view)
	if err != nil {
		t.Fatal(err)
	}
	formats := make([]LayoutFormatVersion, len(canonical.AcceptedLayoutFormats))
	for index, format := range canonical.AcceptedLayoutFormats {
		formats[index] = format.LayoutFormatVersion
	}
	if fmt.Sprint(formats) != fmt.Sprint([]LayoutFormatVersion{
		"layout.format.record.v1",
		"layout.format.record.v10",
		"layout.format.record.v2",
	}) {
		t.Fatalf("canonical vector does not prove v10 sorts before v2: %v", formats)
	}
}

func readVectorDocument(t *testing.T) vectorDocument {
	t.Helper()
	var document vectorDocument
	decoder := json.NewDecoder(bytes.NewReader(ConformanceVectorsJSON()))
	decoder.DisallowUnknownFields()
	if err := decoder.Decode(&document); err != nil {
		t.Fatal(err)
	}
	if err := decoder.Decode(&struct{}{}); err != io.EOF {
		t.Fatalf("unexpected trailing JSON: %v", err)
	}
	return document
}

type vectorDocument struct {
	SchemaVersion              string                 `json:"schema_version"`
	CanonicalView              canonicalViewVector    `json:"canonical_view"`
	ValidationFailures         []failureVector        `json:"validation_failures"`
	ReferencedArtifactFailures []failureVector        `json:"referenced_artifact_failures"`
	FieldNameBoundaries        []fieldNameBoundary    `json:"field_name_boundaries"`
	UnsignedLEB128Recipes      []unsignedLEB128Recipe `json:"unsigned_leb128_recipes"`
	AggregateSizeBoundary      aggregateSizeBoundary  `json:"aggregate_size_boundary"`
}

type canonicalViewVector struct {
	Name                 string               `json:"name"`
	View                 vectorView           `json:"view"`
	AssignmentView       vectorAssignmentView `json:"assignment_view"`
	RequiredBundleKeySet vectorRequiredSet    `json:"required_bundle_key_set"`
	CanonicalBytesLength string               `json:"canonical_bytes_length"`
	CanonicalBytesHex    string               `json:"canonical_bytes_hex"`
	ViewDigest           string               `json:"view_digest"`
}

type failureVector struct {
	Name          string `json:"name"`
	Mutation      string `json:"mutation"`
	ErrorContains string `json:"error_contains"`
}

type vectorSnapshot struct {
	OrgID                 string `json:"org_id"`
	CatalogRevision       string `json:"catalog_revision"`
	CatalogSnapshotDigest string `json:"catalog_snapshot_digest"`
	SchemaGeneration      string `json:"schema_generation"`
	EngineGeneration      string `json:"engine_generation"`
}

func (snapshot vectorSnapshot) value(t *testing.T) catalogpublicationv1.CatalogSnapshotBinding {
	t.Helper()
	return catalogpublicationv1.CatalogSnapshotBinding{
		OrgID:                 snapshot.OrgID,
		CatalogRevision:       vectorUint(t, "catalog_revision", snapshot.CatalogRevision),
		CatalogSnapshotDigest: snapshot.CatalogSnapshotDigest,
		SchemaGeneration:      vectorUint(t, "schema_generation", snapshot.SchemaGeneration),
		EngineGeneration:      vectorUint(t, "engine_generation", snapshot.EngineGeneration),
	}
}

type vectorView struct {
	CanonicalizationVersion             string               `json:"canonicalization_version"`
	KeyGrammarVersion                   string               `json:"key_grammar_version"`
	ObjectKeyNormalizationVersion       string               `json:"object_key_normalization_version"`
	FieldKeyNormalizationVersion        string               `json:"field_key_normalization_version"`
	SourceCatalogSnapshot               vectorSnapshot       `json:"source_catalog_snapshot"`
	CatalogAssignmentIdentityViewDigest string               `json:"catalog_assignment_identity_view_digest"`
	RequiredBundleKeySetDigest          string               `json:"required_bundle_key_set_digest"`
	Objects                             []vectorObject       `json:"objects"`
	Fields                              []vectorField        `json:"fields"`
	Relationships                       []vectorRelationship `json:"relationships"`
	RelatedLists                        []vectorRelatedList  `json:"related_lists"`
	Actions                             []vectorAction       `json:"actions"`
	RendererComponents                  []vectorRenderer     `json:"renderer_components"`
	AcceptedLayoutFormats               []vectorLayoutFormat `json:"accepted_layout_formats"`
	BundleAuthorityEvidence             []vectorEvidence     `json:"bundle_authority_evidence"`
}

type vectorObject struct {
	ObjectKey    string   `json:"object_key"`
	Capabilities []string `json:"capabilities"`
}

type vectorField struct {
	ObjectKey                    string               `json:"object_key"`
	FieldKey                     string               `json:"field_key"`
	DataTypeID                   string               `json:"data_type_id"`
	RelationshipKind             RelationshipKind     `json:"relationship_kind"`
	OwnsPolymorphicDiscriminator bool                 `json:"owns_polymorphic_discriminator"`
	RequiredOnCreate             bool                 `json:"required_on_create"`
	Nillable                     bool                 `json:"nillable"`
	DefaultedOnCreate            bool                 `json:"defaulted_on_create"`
	Createable                   bool                 `json:"createable"`
	Updateable                   bool                 `json:"updateable"`
	EditContractKey              *vectorNamespacedKey `json:"edit_contract_key"`
	RenderContractKey            vectorNamespacedKey  `json:"render_contract_key"`
	ReferenceTargets             []string             `json:"reference_targets"`
}

type vectorNamespacedKey struct {
	NamespaceID string `json:"namespace_id"`
	LocalKey    string `json:"local_key"`
}

func (key vectorNamespacedKey) value() NamespacedContractKey {
	return NamespacedContractKey{NamespaceID: key.NamespaceID, LocalKey: key.LocalKey}
}

type vectorRelationship struct {
	ReferenceObjectKey string           `json:"reference_object_key"`
	ReferenceFieldKey  string           `json:"reference_field_key"`
	TargetObjectKey    string           `json:"target_object_key"`
	Kind               RelationshipKind `json:"kind"`
}

type vectorRelatedList struct {
	ParentObjectKey    string   `json:"parent_object_key"`
	ReferenceObjectKey string   `json:"reference_object_key"`
	ReferenceFieldKey  string   `json:"reference_field_key"`
	Capabilities       []string `json:"capabilities"`
}

type vectorAction struct {
	ObjectKey       string              `json:"object_key"`
	Key             vectorNamespacedKey `json:"key"`
	ActionKindID    string              `json:"action_kind_id"`
	TargetObjectKey *string             `json:"target_object_key"`
	ContractVersion string              `json:"contract_version"`
	ContractDigest  string              `json:"contract_digest"`
	Capabilities    []string            `json:"capabilities"`
}

type vectorRenderer struct {
	Key             vectorNamespacedKey `json:"key"`
	ContractVersion string              `json:"contract_version"`
	ContractDigest  string              `json:"contract_digest"`
	Capabilities    []string            `json:"capabilities"`
}

type vectorLayoutFormat struct {
	LayoutFormatVersion string `json:"layout_format_version"`
	ContractDigest      string `json:"contract_digest"`
}

type vectorBundleKey struct {
	SlotOwnerKind      layoutbundlekeyv1.SlotOwnerKind `json:"slot_owner_kind"`
	SlotOwnerNamespace string                          `json:"slot_owner_namespace"`
	LocalComponentKey  string                          `json:"local_component_key"`
}

func (key vectorBundleKey) value() layoutbundlekeyv1.BundleKey {
	return layoutbundlekeyv1.BundleKey{
		SlotOwnerKind: key.SlotOwnerKind, SlotOwnerNamespace: key.SlotOwnerNamespace,
		LocalComponentKey: layoutbundlekeyv1.LocalComponentKey(key.LocalComponentKey),
	}
}

type vectorEvidence struct {
	BundleKey       vectorBundleKey `json:"bundle_key"`
	EvidenceVersion string          `json:"evidence_version"`
	EvidenceDigest  string          `json:"evidence_digest"`
}

func (wire vectorView) value(t *testing.T) View {
	t.Helper()
	if wire.Objects == nil || wire.Fields == nil || wire.Relationships == nil ||
		wire.RelatedLists == nil || wire.Actions == nil || wire.RendererComponents == nil ||
		wire.AcceptedLayoutFormats == nil || wire.BundleAuthorityEvidence == nil {
		t.Fatal("vector view omits a required top-level array")
	}
	for index, object := range wire.Objects {
		if object.Capabilities == nil {
			t.Fatalf("vector view objects[%d] omits capabilities", index)
		}
	}
	for index, field := range wire.Fields {
		if field.ReferenceTargets == nil {
			t.Fatalf("vector view fields[%d] omits reference_targets", index)
		}
	}
	for index, relatedList := range wire.RelatedLists {
		if relatedList.Capabilities == nil {
			t.Fatalf("vector view related_lists[%d] omits capabilities", index)
		}
	}
	for index, action := range wire.Actions {
		if action.Capabilities == nil {
			t.Fatalf("vector view actions[%d] omits capabilities", index)
		}
	}
	for index, renderer := range wire.RendererComponents {
		if renderer.Capabilities == nil {
			t.Fatalf("vector view renderer_components[%d] omits capabilities", index)
		}
	}
	view := View{
		CanonicalizationVersion:             wire.CanonicalizationVersion,
		KeyGrammarVersion:                   wire.KeyGrammarVersion,
		ObjectKeyNormalizationVersion:       wire.ObjectKeyNormalizationVersion,
		FieldKeyNormalizationVersion:        wire.FieldKeyNormalizationVersion,
		SourceCatalogSnapshot:               wire.SourceCatalogSnapshot.value(t),
		CatalogAssignmentIdentityViewDigest: wire.CatalogAssignmentIdentityViewDigest,
		RequiredBundleKeySetDigest:          wire.RequiredBundleKeySetDigest,
		Objects:                             make([]ObjectContract, len(wire.Objects)),
		Fields:                              make([]FieldContract, len(wire.Fields)),
		Relationships:                       make([]RelationshipContract, len(wire.Relationships)),
		RelatedLists:                        make([]RelatedListContract, len(wire.RelatedLists)),
		Actions:                             make([]ActionContract, len(wire.Actions)),
		RendererComponents:                  make([]RendererComponentContract, len(wire.RendererComponents)),
		AcceptedLayoutFormats:               make([]LayoutFormatContract, len(wire.AcceptedLayoutFormats)),
		BundleAuthorityEvidence:             make([]BundleAuthorityEvidenceRef, len(wire.BundleAuthorityEvidence)),
	}
	for index, object := range wire.Objects {
		view.Objects[index] = ObjectContract{Key: objectKey(object.ObjectKey), Capabilities: capabilityValues(object.Capabilities)}
	}
	for index, field := range wire.Fields {
		var edit *NamespacedContractKey
		if field.EditContractKey != nil {
			value := field.EditContractKey.value()
			edit = &value
		}
		targets := make([]ObjectKey, len(field.ReferenceTargets))
		for targetIndex, target := range field.ReferenceTargets {
			targets[targetIndex] = objectKey(target)
		}
		view.Fields[index] = FieldContract{
			Key: fieldKey(field.ObjectKey, field.FieldKey), DataTypeID: DataTypeID(field.DataTypeID),
			RelationshipKind: field.RelationshipKind, OwnsPolymorphicDiscriminator: field.OwnsPolymorphicDiscriminator,
			RequiredOnCreate: field.RequiredOnCreate, Nillable: field.Nillable, DefaultedOnCreate: field.DefaultedOnCreate,
			Createable: field.Createable, Updateable: field.Updateable, EditContractKey: edit,
			RenderContractKey: field.RenderContractKey.value(), ReferenceTargets: targets,
		}
	}
	for index, relationship := range wire.Relationships {
		view.Relationships[index] = RelationshipContract{
			ReferenceFieldKey: fieldKey(relationship.ReferenceObjectKey, relationship.ReferenceFieldKey),
			TargetObjectKey:   objectKey(relationship.TargetObjectKey), Kind: relationship.Kind,
		}
	}
	for index, relatedList := range wire.RelatedLists {
		view.RelatedLists[index] = RelatedListContract{
			ParentObjectKey:   objectKey(relatedList.ParentObjectKey),
			ReferenceFieldKey: fieldKey(relatedList.ReferenceObjectKey, relatedList.ReferenceFieldKey),
			Capabilities:      capabilityValues(relatedList.Capabilities),
		}
	}
	for index, action := range wire.Actions {
		var target *ObjectKey
		if action.TargetObjectKey != nil {
			target = objectKeyPointer(*action.TargetObjectKey)
		}
		view.Actions[index] = ActionContract{
			ObjectKey: objectKey(action.ObjectKey), Key: action.Key.value(), ActionKindID: ActionKindID(action.ActionKindID),
			TargetObjectKey: target, ContractVersion: vectorUint(t, "contract_version", action.ContractVersion),
			ContractDigest: action.ContractDigest, Capabilities: capabilityValues(action.Capabilities),
		}
	}
	for index, renderer := range wire.RendererComponents {
		view.RendererComponents[index] = RendererComponentContract{
			Key: renderer.Key.value(), ContractVersion: vectorUint(t, "contract_version", renderer.ContractVersion),
			ContractDigest: renderer.ContractDigest, Capabilities: capabilityValues(renderer.Capabilities),
		}
	}
	for index, format := range wire.AcceptedLayoutFormats {
		view.AcceptedLayoutFormats[index] = LayoutFormatContract{LayoutFormatVersion: LayoutFormatVersion(format.LayoutFormatVersion), ContractDigest: format.ContractDigest}
	}
	for index, evidence := range wire.BundleAuthorityEvidence {
		view.BundleAuthorityEvidence[index] = BundleAuthorityEvidenceRef{
			BundleKey: evidence.BundleKey.value(), EvidenceVersion: evidence.EvidenceVersion, EvidenceDigest: evidence.EvidenceDigest,
		}
	}
	return view
}

func capabilityValues(values []string) []CapabilityID {
	result := make([]CapabilityID, len(values))
	for index, value := range values {
		result[index] = CapabilityID(value)
	}
	return result
}

type vectorAssignmentView struct {
	SourceCatalogSnapshot         vectorSnapshot               `json:"source_catalog_snapshot"`
	CanonicalizationVersion       string                       `json:"canonicalization_version"`
	KeyGrammarVersion             string                       `json:"key_grammar_version"`
	ObjectKeyNormalizationVersion string                       `json:"object_key_normalization_version"`
	Objects                       []vectorAssignmentObject     `json:"objects"`
	RecordTypes                   []struct{}                   `json:"record_types"`
	ProductApps                   []vectorAssignmentProductApp `json:"product_apps"`
	NavigationApps                []struct{}                   `json:"navigation_apps"`
}

type vectorAssignmentObject struct {
	ObjectKey        string                                    `json:"object_key"`
	ResolvedObjectID string                                    `json:"resolved_object_id"`
	State            catalogassignmentidentityv1.IdentityState `json:"state"`
}

type vectorAssignmentProductApp struct {
	AppID          string                                    `json:"app_id"`
	State          catalogassignmentidentityv1.IdentityState `json:"state"`
	ResolvedTarget struct {
		Kind                      string `json:"kind"`
		ResolvedAppInstallationID string `json:"resolved_app_installation_id"`
	} `json:"resolved_target"`
}

func (wire vectorAssignmentView) value(t *testing.T) catalogassignmentidentityv1.View {
	t.Helper()
	if wire.Objects == nil || wire.RecordTypes == nil || wire.ProductApps == nil || wire.NavigationApps == nil {
		t.Fatal("vector assignment view omits a required identity array")
	}
	view := catalogassignmentidentityv1.View{
		SourceCatalogSnapshot:         wire.SourceCatalogSnapshot.value(t),
		CanonicalizationVersion:       wire.CanonicalizationVersion,
		KeyGrammarVersion:             wire.KeyGrammarVersion,
		ObjectKeyNormalizationVersion: wire.ObjectKeyNormalizationVersion,
		Objects:                       make([]catalogassignmentidentityv1.ObjectIdentity, len(wire.Objects)),
		RecordTypes:                   []catalogassignmentidentityv1.RecordTypeIdentity{},
		ProductApps:                   make([]catalogassignmentidentityv1.ProductAppIdentity, len(wire.ProductApps)),
		NavigationApps:                []catalogassignmentidentityv1.NavigationAppIdentity{},
	}
	for index, object := range wire.Objects {
		view.Objects[index] = catalogassignmentidentityv1.ObjectIdentity{
			Key: objectKey(object.ObjectKey), ResolvedObjectID: object.ResolvedObjectID, State: object.State,
		}
	}
	for index, productApp := range wire.ProductApps {
		if productApp.ResolvedTarget.Kind != "APP_INSTALLATION_ID" {
			t.Fatalf("assignment product_apps[%d] resolved target kind = %q", index, productApp.ResolvedTarget.Kind)
		}
		view.ProductApps[index] = catalogassignmentidentityv1.ProductAppIdentity{
			Key:   catalogassignmentidentityv1.ProductAppKey{AppID: productApp.AppID},
			State: productApp.State,
			ResolvedTarget: catalogassignmentidentityv1.ProductAppResolvedTarget{
				Kind:                      catalogassignmentidentityv1.ProductAppResolvedTargetKindAppInstallationID,
				ResolvedAppInstallationID: productApp.ResolvedTarget.ResolvedAppInstallationID,
			},
		}
	}
	return view
}

type fieldNameBoundary struct {
	Name                         string           `json:"name"`
	FieldNameLength              string           `json:"field_name_length"`
	RelationshipKind             RelationshipKind `json:"relationship_kind"`
	OwnsPolymorphicDiscriminator bool             `json:"owns_polymorphic_discriminator"`
	Accepted                     bool             `json:"accepted"`
	ErrorContains                string           `json:"error_contains"`
}

func (boundary fieldNameBoundary) value(t *testing.T) View {
	t.Helper()
	nameLength := vectorUint(t, "field_name_length", boundary.FieldNameLength)
	view := emptyView()
	sourceObject := objectKey("source")
	targetObject := objectKey("target")
	view.Objects = []ObjectContract{
		{Key: sourceObject, Capabilities: []CapabilityID{}},
		{Key: targetObject, Capabilities: []CapabilityID{}},
	}
	renderKey := NamespacedContractKey{
		NamespaceID: "io.nexuscrm.ui",
		LocalKey:    "field.text-render.v1",
	}
	targets := []ObjectKey{}
	relationships := []RelationshipContract{}
	field := FieldContract{
		Key: FieldKey{
			ObjectKey:              sourceObject,
			NormalizedFieldAPIName: strings.Repeat("f", int(nameLength)),
		},
		DataTypeID:                   "catalog.data-type.string.v1",
		RelationshipKind:             boundary.RelationshipKind,
		OwnsPolymorphicDiscriminator: boundary.OwnsPolymorphicDiscriminator,
		EditContractKey:              nil,
		RenderContractKey:            renderKey,
		ReferenceTargets:             targets,
	}
	if boundary.RelationshipKind != RelationshipKindNone {
		field.DataTypeID = "catalog.data-type.reference.v1"
		field.ReferenceTargets = []ObjectKey{targetObject}
		relationships = append(relationships, RelationshipContract{
			ReferenceFieldKey: field.Key,
			TargetObjectKey:   targetObject,
			Kind:              boundary.RelationshipKind,
		})
	}
	view.Fields = []FieldContract{field}
	view.Relationships = relationships
	view.RendererComponents = []RendererComponentContract{{
		Key: renderKey, ContractVersion: 1, ContractDigest: digestOf('e'), Capabilities: []CapabilityID{},
	}}
	return view
}

type vectorRequiredSet struct {
	Version    string            `json:"version"`
	BundleKeys []vectorBundleKey `json:"bundle_keys"`
}

func (wire vectorRequiredSet) value(t *testing.T) layoutbundlekeyv1.RequiredBundleKeySet {
	t.Helper()
	if wire.BundleKeys == nil {
		t.Fatal("vector required BundleKey set omits bundle_keys")
	}
	set := layoutbundlekeyv1.RequiredBundleKeySet{Version: wire.Version, BundleKeys: make([]layoutbundlekeyv1.BundleKey, len(wire.BundleKeys))}
	for index, key := range wire.BundleKeys {
		set.BundleKeys[index] = key.value()
	}
	return set
}

type unsignedLEB128Recipe struct {
	Name                                string `json:"name"`
	OrgIDLength                         string `json:"org_id_length"`
	CatalogRevision                     string `json:"catalog_revision"`
	SchemaGeneration                    string `json:"schema_generation"`
	EngineGeneration                    string `json:"engine_generation"`
	ObjectCount                         string `json:"object_count"`
	CatalogAssignmentIdentityViewDigest string `json:"catalog_assignment_identity_view_digest"`
	RequiredBundleKeySetDigest          string `json:"required_bundle_key_set_digest"`
	CanonicalBytesLength                string `json:"canonical_bytes_length"`
	ViewDigest                          string `json:"view_digest"`
}

func (recipe unsignedLEB128Recipe) value(t *testing.T) View {
	t.Helper()
	view := emptyView()
	orgLength := vectorUint(t, "org_id_length", recipe.OrgIDLength)
	view.SourceCatalogSnapshot.OrgID = string(bytes.Repeat([]byte{'o'}, int(orgLength)))
	view.SourceCatalogSnapshot.CatalogRevision = vectorUint(t, "catalog_revision", recipe.CatalogRevision)
	view.SourceCatalogSnapshot.SchemaGeneration = vectorUint(t, "schema_generation", recipe.SchemaGeneration)
	view.SourceCatalogSnapshot.EngineGeneration = vectorUint(t, "engine_generation", recipe.EngineGeneration)
	view.CatalogAssignmentIdentityViewDigest = recipe.CatalogAssignmentIdentityViewDigest
	view.RequiredBundleKeySetDigest = recipe.RequiredBundleKeySetDigest
	count := int(vectorUint(t, "object_count", recipe.ObjectCount))
	view.Objects = make([]ObjectContract, count)
	for index := count - 1; index >= 0; index-- {
		view.Objects[count-1-index] = ObjectContract{Key: objectKey(fmt.Sprintf("o%03d", index)), Capabilities: []CapabilityID{}}
	}
	return view
}

type aggregateSizeBoundary struct {
	Maximum  string `json:"maximum"`
	Accepted string `json:"accepted"`
	Rejected string `json:"rejected"`
}

func vectorUint(t *testing.T, label, value string) uint64 {
	t.Helper()
	if value == "" || (len(value) > 1 && value[0] == '0') {
		t.Fatalf("%s = %q is not canonical uint64", label, value)
	}
	parsed, err := strconv.ParseUint(value, 10, 64)
	if err != nil {
		t.Fatalf("%s = %q: %v", label, value, err)
	}
	return parsed
}
