package mapping

import (
	"errors"

	analyticssemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/analyticsauthoringv1"
	approvalsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/approvalv1"
	commonsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/commonv1"
	flowsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/flowv1"
	layoutauthoringsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/layoutauthoringv1"
	layoutauthoringv2 "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/layoutauthoringv2"
	metadataadminsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/metadataadminreadv1"
	pagelayoutresolutionsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/pagelayoutresolutionv1"
	permissionsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/permissionadminv1"
	permissionauthoringsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/permissionauthoringv1"
	historysemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/queryv1"
	resourceaccesssemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/resourceaccessv1"
	sessionsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/sessionv1"
	"github.com/pingcap-inc/nexuscrm-contract/wire-go/envelope"
	runtimev1 "github.com/pingcap-inc/nexuscrm-contract/wire-go/gen/runtime/v1"
	"google.golang.org/protobuf/encoding/protowire"
	"google.golang.org/protobuf/proto"
)

// ErrMalformedPlatformWire identifies malformed or unsupported protobuf wire
// grammar found before unmarshal. Resource-limit failures are returned
// separately as typed commonv1.Failure values.
var ErrMalformedPlatformWire = errors.New("malformed runtime protobuf wire payload")

// PreflightPlatformWirePayload enforces repeated-message bounds directly on
// protobuf bytes before proto.Unmarshal materializes attacker-controlled nested
// messages. Transport hosts call it from their selected Runtime codec; semantic
// mappings repeat the checks because they are also callable without gRPC.
func PreflightPlatformWirePayload(data []byte, destination proto.Message) error {
	switch destination.(type) {
	case *runtimev1.ReadSessionRequest:
		if err := preflightPlatformRequestFrame(data); err != nil {
			return err
		}
		return preflightSessionDocumentPolicy(data, sessionsemantic.MaxDocumentLinkRoutes, requestOperationCountLimit)
	case *runtimev1.ReadSessionResponse:
		if err := preflightPlatformResponseFrame(data); err != nil {
			return err
		}
		return preflightSessionDocumentPolicy(data, sessionsemantic.MaxDocumentAllowedLinks, responseWireLimit)

	case *runtimev1.AccessResourceRequest:
		if err := preflightPlatformRequestFrame(data); err != nil {
			return err
		}
		return preflightRepeatedMessageFields(data, map[protowire.Number]int{
			6: resourceaccesssemantic.MaxGrants,
		}, resourceaccesssemantic.MaxGrants, requestOperationCountLimit)
	case *runtimev1.AccessResourceResponse:
		if err := preflightPlatformResponseFrame(data); err != nil {
			return err
		}
		return preflightRepeatedMessageFields(data, map[protowire.Number]int{
			2: resourceaccesssemantic.MaxGrants,
		}, resourceaccesssemantic.MaxGrants, responseWireLimit)
	case *runtimev1.ExecuteApprovalResponse:
		if err := preflightPlatformResponseFrame(data); err != nil {
			return err
		}
		return preflightApprovalExecuteResponse(data)
	case *runtimev1.ExecuteFlowResponse:
		if err := preflightPlatformResponseFrame(data); err != nil {
			return err
		}
		return preflightFlowExecuteResponse(data)
	case *runtimev1.MutatePermissionAdministrationRequest:
		if err := preflightPlatformRequestFrame(data); err != nil {
			return err
		}
		return preflightRepeatedMessageFields(data, map[protowire.Number]int{
			3: permissionsemantic.MaxGrants,
		}, permissionsemantic.MaxGrants, requestOperationCountLimit)
	case *runtimev1.ReadPermissionAdministrationResponse:
		if err := preflightPlatformResponseFrame(data); err != nil {
			return err
		}
		return preflightRepeatedMessageFields(data, map[protowire.Number]int{
			1: permissionsemantic.MaxCatalogEntries,
			2: permissionsemantic.MaxGrants,
			3: permissionsemantic.MaxCatalogEntries,
			4: permissionsemantic.MaxGrants,
			5: permissionsemantic.MaxCatalogEntries,
			6: permissionsemantic.MaxGrants,
		}, max(permissionsemantic.MaxCatalogEntries, permissionsemantic.MaxGrants), responseWireLimit)
	case *runtimev1.SavePermissionAuthoringRequest:
		if err := preflightPlatformRequestFrame(data); err != nil {
			return err
		}
		return preflightPermissionAuthoringSaveWire(data)
	case *runtimev1.ReadPermissionAuthoringSnapshotResponse:
		if err := preflightPlatformResponseFrame(data); err != nil {
			return err
		}
		return preflightPermissionAuthoringSnapshotWire(data)
	case *runtimev1.MutateAnalyticsDefinitionRequest:
		if err := preflightPlatformRequestFrame(data); err != nil {
			return err
		}
		return preflightAnalyticsDefinitionCounts(data)
	case *runtimev1.LayoutAuthoringServiceSubmitRequest:
		if err := preflightPlatformRequestFrame(data); err != nil {
			return err
		}
		return preflightLayoutAuthoringSubmit(data, false)
	case *runtimev1.LayoutAuthoringServiceGetCommandRequest,
		*runtimev1.LayoutAuthoringServiceReadWorkspaceRequest,
		*runtimev1.LayoutAuthoringServiceReadStoredLayoutRequest:
		return preflightPlatformRequestFrame(data)
	case *runtimev1.LayoutAuthoringServiceSubmitResponse:
		if err := preflightPlatformResponseFrame(data); err != nil {
			return err
		}
		return preflightLayoutAuthoringSubmitResponse(data)
	case *runtimev1.LayoutAuthoringServiceGetCommandResponse:
		if err := preflightPlatformResponseFrame(data); err != nil {
			return err
		}
		return preflightLayoutAuthoringStatus(data, true)
	case *runtimev1.LayoutAuthoringServiceReadWorkspaceResponse:
		if err := preflightPlatformResponseFrame(data); err != nil {
			return err
		}
		return preflightLayoutAuthoringWorkspace(data)
	case *runtimev1.LayoutAuthoringServiceReadStoredLayoutResponse:
		if err := preflightPlatformResponseFrame(data); err != nil {
			return err
		}
		return preflightLayoutAuthoringStoredLayout(data)
	case *runtimev1.LayoutAuthoringV2ServiceReadWorkspaceRequest,
		*runtimev1.LayoutAuthoringV2ServiceReadStoredLayoutRequest:
		return preflightPlatformRequestFrame(data)
	case *runtimev1.LayoutAuthoringV2ServiceMutateRequest:
		if err := preflightPlatformRequestFrame(data); err != nil {
			return err
		}
		return preflightLayoutAuthoringV2Mutate(data)
	case *runtimev1.LayoutAuthoringV2ServiceReadWorkspaceResponse:
		if err := preflightPlatformResponseFrame(data); err != nil {
			return err
		}
		return preflightLayoutAuthoringV2Workspace(data)
	case *runtimev1.LayoutAuthoringV2ServiceReadStoredLayoutResponse:
		if err := preflightPlatformResponseFrame(data); err != nil {
			return err
		}
		return preflightLayoutAuthoringV2StoredLayout(data)
	case *runtimev1.LayoutAuthoringV2ServiceMutateResponse:
		return preflightPlatformResponseFrame(data)
	case *runtimev1.ReadObjectListFieldsRequest:
		if err := preflightPlatformRequestFrame(data); err != nil {
			return err
		}
		return preflightReadObjectListFieldsRequest(data)
	case *runtimev1.ReadObjectListFieldsResponse:
		if err := preflightPlatformResponseFrame(data); err != nil {
			return err
		}
		return preflightReadObjectListFieldsResponse(data)
	default:
		return nil
	}
}

// Both session envelopes carry document_policy at field 4, whose repeated
// values are at field 2. Count across duplicate singular-message occurrences:
// protobuf merges them, so resetting the count per occurrence permits bypass.
func preflightSessionDocumentPolicy(data []byte, maximum int, limitFailure func(int) error) error {
	count := 0
	return visitWireBytesFields(data, func(number protowire.Number, policy []byte) error {
		if number != 4 {
			return nil
		}
		return visitWireBytesFields(policy, func(number protowire.Number, _ []byte) error {
			if number != 2 {
				return nil
			}
			count++
			if count > maximum {
				return limitFailure(maximum)
			}
			return nil
		})
	})
}

func preflightReadObjectListFieldsRequest(data []byte) error {
	objects := 0
	return visitWireBytesFields(data, func(number protowire.Number, _ []byte) error {
		if number != 1 {
			return nil
		}
		objects++
		if objects > pagelayoutresolutionsemantic.MaxObjectSelectors {
			return platformLimitFailure(commonsemantic.LimitRecordCount, pagelayoutresolutionsemantic.MaxObjectSelectors)
		}
		return nil
	})
}

func preflightReadObjectListFieldsResponse(data []byte) error {
	objects := 0
	fields := 0
	return visitWireBytesFields(data, func(number protowire.Number, object []byte) error {
		if number != 1 {
			return nil
		}
		objects++
		if objects > pagelayoutresolutionsemantic.MaxObjectSelectors {
			return internalPlatformWire()
		}
		objectFields := 0
		fieldsSeen := false
		return visitWireBytesFields(object, func(number protowire.Number, fieldsWire []byte) error {
			if number != 2 {
				return nil
			}
			if fieldsSeen {
				return ErrMalformedPlatformWire
			}
			fieldsSeen = true
			return visitWireBytesFields(fieldsWire, func(number protowire.Number, _ []byte) error {
				if number != 1 {
					return nil
				}
				objectFields++
				fields++
				if objectFields > pagelayoutresolutionsemantic.MaxListFieldsPerObject ||
					fields > pagelayoutresolutionsemantic.MaxResolutionProjectionEntries {
					return internalPlatformWire()
				}
				return nil
			})
		})
	})
}

func preflightFlowExecuteResponse(data []byte) error {
	executionErrors := 0
	return visitWireBytesFields(data, func(number protowire.Number, executionError []byte) error {
		if number != 6 {
			return nil
		}
		executionErrors++
		if executionErrors > flowsemantic.MaxExecutionErrors {
			return internalPlatformWire()
		}
		fields := 0
		return visitWireBytesFields(executionError, func(number protowire.Number, value []byte) error {
			switch number {
			case 1:
				if len(value) > flowsemantic.MaxIdentifierBytes {
					return internalPlatformWire()
				}
			case 2:
				if len(value) > flowsemantic.MaxErrorMessageBytes {
					return internalPlatformWire()
				}
			case 3:
				fields++
				if fields > flowsemantic.MaxFieldsPerExecutionError ||
					len(value) > commonsemantic.MaxFieldIdentifierBytes {
					return internalPlatformWire()
				}
			}
			return nil
		})
	})
}

func preflightApprovalExecuteResponse(data []byte) error {
	validationIssues := 0
	return visitWireBytesFields(data, func(number protowire.Number, submitRejection []byte) error {
		if number != 10 {
			return nil
		}
		return visitWireBytesFields(submitRejection, func(number protowire.Number, _ []byte) error {
			if number != 2 {
				return nil
			}
			validationIssues++
			if validationIssues > approvalsemantic.MaxValidationIssues {
				return internalPlatformWire()
			}
			return nil
		})
	})
}

type permissionAuthoringWireLimit struct {
	maximum int
	kind    commonsemantic.LimitKind
}

var permissionAuthoringChangeWireLimits = [6]permissionAuthoringWireLimit{
	1: {maximum: permissionauthoringsemantic.MaxSystemChanges, kind: commonsemantic.LimitOperationCount},
	2: {maximum: permissionauthoringsemantic.MaxObjectChanges, kind: commonsemantic.LimitOperationCount},
	3: {maximum: permissionauthoringsemantic.MaxFieldChanges, kind: commonsemantic.LimitFieldCount},
	4: {maximum: permissionauthoringsemantic.MaxRecordTypeChanges, kind: commonsemantic.LimitOperationCount},
	5: {maximum: permissionauthoringsemantic.MaxCustomChanges, kind: commonsemantic.LimitOperationCount},
}

var permissionAuthoringCatalogWireLimits = [6]permissionAuthoringWireLimit{
	1: {maximum: permissionauthoringsemantic.MaxSystemChanges},
	2: {maximum: permissionauthoringsemantic.MaxRecordTypeChanges},
	3: {maximum: permissionauthoringsemantic.MaxCustomChanges},
}

var permissionAuthoringGrantWireLimits = [6]permissionAuthoringWireLimit{
	1: {maximum: permissionauthoringsemantic.MaxSystemChanges},
	2: {maximum: permissionauthoringsemantic.MaxObjectChanges},
	3: {maximum: permissionauthoringsemantic.MaxFieldChanges},
	4: {maximum: permissionauthoringsemantic.MaxRecordTypeChanges},
	5: {maximum: permissionauthoringsemantic.MaxCustomChanges},
}

func preflightPermissionAuthoringSaveWire(data []byte) error {
	counts := [6]int{}
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		if number != 4 {
			return nil
		}
		return preflightPermissionAuthoringRepeatedWireFields(
			value, &counts, permissionAuthoringChangeWireLimits, true,
		)
	})
}

func preflightPermissionAuthoringSnapshotWire(data []byte) error {
	catalogCounts := [6]int{}
	grantCounts := [6]int{}
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		switch number {
		case 3:
			return preflightPermissionAuthoringRepeatedWireFields(
				value, &catalogCounts, permissionAuthoringCatalogWireLimits, false,
			)
		case 4:
			return preflightPermissionAuthoringRepeatedWireFields(
				value, &grantCounts, permissionAuthoringGrantWireLimits, false,
			)
		default:
			return nil
		}
	})
}

func preflightPermissionAuthoringRepeatedWireFields(
	data []byte,
	counts *[6]int,
	limits [6]permissionAuthoringWireLimit,
	request bool,
) error {
	return visitWireBytesFields(data, func(number protowire.Number, _ []byte) error {
		index := int(number)
		if index <= 0 || index >= len(limits) || limits[index].maximum == 0 {
			return nil
		}
		counts[index]++
		limit := limits[index]
		if counts[index] <= limit.maximum {
			return nil
		}
		if request {
			return platformLimitFailure(limit.kind, limit.maximum)
		}
		return internalPlatformWire()
	})
}

func preflightLayoutAuthoringSubmit(data []byte, response bool) error {
	budget := newLayoutAuthoringWireBudget(response)
	operationCount := 0
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		if number >= 10 && number <= 17 {
			operationCount++
			if operationCount > 1 {
				return ErrMalformedPlatformWire
			}
		}
		switch number {
		case 10:
			seen := map[protowire.Number]bool{}
			return visitWireBytesFields(value, func(number protowire.Number, nested []byte) error {
				if (number == 1 || number == 2) && duplicateLayoutAuthoringSingular(seen, number) {
					return ErrMalformedPlatformWire
				}
				if number == 1 {
					return preflightLayoutAuthoringDocument(nested, budget)
				}
				if number == 2 {
					return preflightLayoutAuthoringStringListChange(nested, layoutauthoringsemantic.MaxListFields, commonsemantic.LimitFieldCount, budget)
				}
				return nil
			})
		case 11:
			seen := map[protowire.Number]bool{}
			return visitWireBytesFields(value, func(number protowire.Number, nested []byte) error {
				if (number == 3 || number == 4) && duplicateLayoutAuthoringSingular(seen, number) {
					return ErrMalformedPlatformWire
				}
				switch number {
				case 3:
					return preflightLayoutAuthoringChanges(nested, budget)
				case 4:
					return preflightLayoutAuthoringStringListChange(nested, layoutauthoringsemantic.MaxListFields, commonsemantic.LimitFieldCount, budget)
				default:
					return nil
				}
			})
		default:
			return nil
		}
	})
}

func preflightLayoutAuthoringSubmitResponse(data []byte) error {
	commandSeen := false
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		if number == 2 {
			if commandSeen {
				return ErrMalformedPlatformWire
			}
			commandSeen = true
			return preflightLayoutAuthoringStatus(value, true)
		}
		return nil
	})
}

func preflightLayoutAuthoringStatus(data []byte, response bool) error {
	budget := newLayoutAuthoringWireBudget(response)
	resultCount := 0
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		if number >= 10 && number <= 17 {
			resultCount++
			if resultCount > 1 {
				return ErrMalformedPlatformWire
			}
		}
		switch number {
		case 10, 11, 12:
			snapshotSeen := false
			return visitWireBytesFields(value, func(number protowire.Number, nested []byte) error {
				if number == 1 {
					if snapshotSeen {
						return ErrMalformedPlatformWire
					}
					snapshotSeen = true
					return preflightLayoutAuthoringSnapshot(nested, budget)
				}
				return nil
			})
		case 15:
			snapshotSeen := false
			return visitWireBytesFields(value, func(number protowire.Number, nested []byte) error {
				if number == 1 {
					if snapshotSeen {
						return ErrMalformedPlatformWire
					}
					snapshotSeen = true
					return preflightLayoutAuthoringSnapshot(nested, budget)
				}
				return nil
			})
		default:
			return nil
		}
	})
}

func preflightLayoutAuthoringWorkspace(data []byte) error {
	budget := newLayoutAuthoringResponseWireBudget()
	layouts := 0
	assignments := 0
	return visitWireBytesFields(data, func(number protowire.Number, _ []byte) error {
		switch number {
		case 3:
			layouts++
			if layouts > layoutauthoringsemantic.MaxWorkspaceLayouts {
				return budget.fail(commonsemantic.LimitRecordCount, layoutauthoringsemantic.MaxWorkspaceLayouts)
			}
			return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.layoutSummary)
		case 4:
			assignments++
			if assignments > layoutauthoringsemantic.MaxWorkspaceAssignments {
				return budget.fail(commonsemantic.LimitRecordCount, layoutauthoringsemantic.MaxWorkspaceAssignments)
			}
			return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.assignmentSummary)
		}
		return nil
	})
}

func preflightLayoutAuthoringStoredLayout(data []byte) error {
	budget := newLayoutAuthoringResponseWireBudget()
	listFields := 0
	documentSeen := false
	createContextSeen := false
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		switch number {
		case 1:
			if documentSeen {
				return ErrMalformedPlatformWire
			}
			documentSeen = true
			return preflightLayoutAuthoringDocument(value, budget)
		case 9:
			if createContextSeen {
				return ErrMalformedPlatformWire
			}
			createContextSeen = true
			if err := budget.takeSemanticFloor(layoutAuthoringSemanticFloors.createContext); err != nil {
				return err
			}
			requiredFields := 0
			return visitWireBytesFields(value, func(number protowire.Number, field []byte) error {
				if number != 1 {
					return nil
				}
				requiredFields++
				if requiredFields > layoutauthoringsemantic.MaxCreateRequiredFields {
					return budget.fail(commonsemantic.LimitFieldCount, layoutauthoringsemantic.MaxCreateRequiredFields)
				}
				if len(field) == 0 || len(field) > commonsemantic.MaxFieldIdentifierBytes {
					return budget.malformed()
				}
				return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.stringValue + len(field))
			})
		case 2:
			listFields++
			if listFields > layoutauthoringsemantic.MaxListFields {
				return budget.fail(commonsemantic.LimitFieldCount, layoutauthoringsemantic.MaxListFields)
			}
			return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.stringValue)
		}
		return nil
	})
}

func preflightLayoutAuthoringV2Mutate(data []byte) error {
	budget := newLayoutAuthoringWireBudget(false)
	operationCount := 0
	projections := 0
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		if number >= 10 && number <= 17 {
			operationCount++
			if operationCount > 1 {
				return ErrMalformedPlatformWire
			}
		}
		switch number {
		case 3:
			projections++
			if projections > layoutauthoringv2.MaxHistoryRelatedListProjections {
				return budget.fail(commonsemantic.LimitOperationCount, layoutauthoringv2.MaxHistoryRelatedListProjections)
			}
			columns := 0
			return visitWireBytesFields(value, func(number protowire.Number, entry []byte) error {
				if number != 2 {
					return nil
				}
				// Count encoded entries, including duplicate keys that protobuf
				// would overwrite, before allocating the decoded map.
				columns++
				if columns > historysemantic.HistoryResultColumnCount {
					return budget.fail(commonsemantic.LimitFieldCount, historysemantic.HistoryResultColumnCount)
				}
				return visitWireBytesFields(entry, func(protowire.Number, []byte) error { return nil })
			})
		case 10:
			seen := map[protowire.Number]bool{}
			return visitWireBytesFields(value, func(number protowire.Number, nested []byte) error {
				if (number == 1 || number == 2) && duplicateLayoutAuthoringSingular(seen, number) {
					return ErrMalformedPlatformWire
				}
				switch number {
				case 1:
					return preflightLayoutAuthoringDocument(nested, budget)
				case 2:
					return preflightLayoutAuthoringStringListChange(nested, layoutauthoringsemantic.MaxListFields, commonsemantic.LimitFieldCount, budget)
				default:
					return nil
				}
			})
		case 11:
			seen := map[protowire.Number]bool{}
			return visitWireBytesFields(value, func(number protowire.Number, nested []byte) error {
				if (number == 2 || number == 3) && duplicateLayoutAuthoringSingular(seen, number) {
					return ErrMalformedPlatformWire
				}
				switch number {
				case 2:
					return preflightLayoutAuthoringChanges(nested, budget)
				case 3:
					return preflightLayoutAuthoringStringListChange(nested, layoutauthoringsemantic.MaxListFields, commonsemantic.LimitFieldCount, budget)
				default:
					return nil
				}
			})
		default:
			return nil
		}
	})
}

func preflightLayoutAuthoringV2Workspace(data []byte) error {
	budget := newLayoutAuthoringResponseWireBudget()
	layouts := 0
	assignments := 0
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		switch number {
		case 3:
			layouts++
			if layouts > metadataadminsemantic.MaxLayoutsPerObject {
				return budget.fail(commonsemantic.LimitRecordCount, metadataadminsemantic.MaxLayoutsPerObject)
			}
			return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.storedLayoutSummary)
		case 4:
			assignments++
			if assignments > metadataadminsemantic.MaxAssignmentsPerObject {
				return budget.fail(commonsemantic.LimitRecordCount, metadataadminsemantic.MaxAssignmentsPerObject)
			}
			if err := budget.takeSemanticFloor(layoutAuthoringSemanticFloors.storedAssignment); err != nil {
				return err
			}
			dimensions := 0
			return visitWireBytesFields(value, func(number protowire.Number, _ []byte) error {
				if number != 4 {
					return nil
				}
				dimensions++
				if dimensions > metadataadminsemantic.MaxAssignmentDimensions {
					return budget.malformed()
				}
				return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.storedDimension)
			})
		default:
			return nil
		}
	})
}

func preflightLayoutAuthoringV2StoredLayout(data []byte) error {
	budget := newLayoutAuthoringResponseWireBudget()
	documentSeen := false
	orderedFieldsSeen := false
	requiredFieldsSeen := false
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		switch number {
		case 4:
			if documentSeen {
				return ErrMalformedPlatformWire
			}
			documentSeen = true
			return preflightLayoutAuthoringDocument(value, budget)
		case 6:
			if orderedFieldsSeen {
				return ErrMalformedPlatformWire
			}
			orderedFieldsSeen = true
			fields := 0
			return visitWireBytesFields(value, func(number protowire.Number, _ []byte) error {
				if number != 1 {
					return nil
				}
				fields++
				if fields > layoutauthoringsemantic.MaxListFields {
					return budget.fail(commonsemantic.LimitFieldCount, layoutauthoringsemantic.MaxListFields)
				}
				return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.stringValue)
			})
		case 7:
			if requiredFieldsSeen {
				return ErrMalformedPlatformWire
			}
			requiredFieldsSeen = true
			fields := 0
			return visitWireBytesFields(value, func(number protowire.Number, field []byte) error {
				if number != 1 {
					return nil
				}
				fields++
				if fields > layoutauthoringsemantic.MaxCreateRequiredFields {
					return budget.fail(commonsemantic.LimitFieldCount, layoutauthoringsemantic.MaxCreateRequiredFields)
				}
				if len(field) == 0 || len(field) > commonsemantic.MaxFieldIdentifierBytes {
					return budget.malformed()
				}
				return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.stringValue + len(field))
			})
		default:
			return nil
		}
	})
}

func preflightLayoutAuthoringSnapshot(data []byte, budget *layoutAuthoringWireBudget) error {
	listFields := 0
	documentSeen := false
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		switch number {
		case 1:
			if documentSeen {
				return ErrMalformedPlatformWire
			}
			documentSeen = true
			return preflightLayoutAuthoringDocument(value, budget)
		case 2:
			listFields++
			if listFields > layoutauthoringsemantic.MaxListFields {
				return budget.fail(commonsemantic.LimitFieldCount, layoutauthoringsemantic.MaxListFields)
			}
			return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.stringValue)
		}
		return nil
	})
}

func preflightLayoutAuthoringDocument(data []byte, budget *layoutAuthoringWireBudget) error {
	return budget.withinDocument(func() error {
		counts := map[protowire.Number]int{}
		singular := map[protowire.Number]bool{}
		maxima := map[protowire.Number]struct {
			maximum int
			kind    commonsemantic.LimitKind
		}{
			6:  {layoutauthoringsemantic.MaxCompactFields, commonsemantic.LimitFieldCount},
			7:  {layoutauthoringsemantic.MaxTabs, commonsemantic.LimitOperationCount},
			8:  {layoutauthoringsemantic.MaxSections, commonsemantic.LimitOperationCount},
			9:  {layoutauthoringsemantic.MaxRelatedLists, commonsemantic.LimitOperationCount},
			10: {layoutauthoringsemantic.MaxRecordPanels, commonsemantic.LimitOperationCount},
			13: {layoutauthoringsemantic.MaxRecordStates, commonsemantic.LimitOperationCount},
			14: {layoutauthoringsemantic.MaxPrimaryHeaderActions, commonsemantic.LimitOperationCount},
		}
		return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
			if (number == 11 || number == 12) && duplicateLayoutAuthoringSingular(singular, number) {
				return ErrMalformedPlatformWire
			}
			if limit, bounded := maxima[number]; bounded {
				counts[number]++
				if counts[number] > limit.maximum {
					return budget.fail(limit.kind, limit.maximum)
				}
			}
			switch number {
			case 6, 7, 14:
				return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.stringValue)
			case 8:
				if err := budget.takeSemanticFloor(layoutAuthoringSemanticFloors.section); err != nil {
					return err
				}
				return preflightLayoutAuthoringSection(value, budget)
			case 9:
				if err := budget.takeSemanticFloor(layoutAuthoringSemanticFloors.relatedList); err != nil {
					return err
				}
				return preflightLayoutAuthoringRelatedList(value, budget)
			case 10:
				if err := budget.takeSemanticFloor(layoutAuthoringSemanticFloors.recordPanel); err != nil {
					return err
				}
				return preflightLayoutAuthoringRecordPanel(value, budget)
			case 11, 12:
				return preflightLayoutAuthoringActionPlacement(value, budget)
			case 13:
				if err := budget.takeSemanticFloor(layoutAuthoringSemanticFloors.recordState); err != nil {
					return err
				}
				return preflightLayoutAuthoringRecordState(value, budget)
			default:
				return nil
			}
		})
	})
}

func preflightLayoutAuthoringSection(data []byte, budget *layoutAuthoringWireBudget) error {
	counts := map[protowire.Number]int{}
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		switch number {
		case 6:
			counts[number]++
			if counts[number] > layoutauthoringsemantic.MaxConfigurationEntries {
				return budget.fail(commonsemantic.LimitOperationCount, layoutauthoringsemantic.MaxConfigurationEntries)
			}
			if err := budget.takeSemanticFloor(layoutAuthoringSemanticFloors.namedValue); err != nil {
				return err
			}
			return preflightLayoutAuthoringNamedValue(value, budget)
		case 8:
			counts[number]++
			if counts[number] > layoutauthoringsemantic.MaxFieldsPerSection {
				return budget.fail(commonsemantic.LimitFieldCount, layoutauthoringsemantic.MaxFieldsPerSection)
			}
			return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.stringValue)
		case 9:
			counts[number]++
			if counts[number] > layoutauthoringsemantic.MaxFieldLabelsPerSection {
				return budget.fail(commonsemantic.LimitFieldCount, layoutauthoringsemantic.MaxFieldLabelsPerSection)
			}
			return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.fieldLabel)
		case 10:
			counts[number]++
			budget.behaviorNodes++
			if counts[number] > layoutauthoringsemantic.MaxFieldBehaviorGroupsPerSection {
				return budget.fail(commonsemantic.LimitFieldCount, layoutauthoringsemantic.MaxFieldBehaviorGroupsPerSection)
			}
			if budget.behaviorNodes > layoutauthoringsemantic.MaxFieldBehaviorNodesPerDocument {
				return budget.fail(commonsemantic.LimitFieldCount, layoutauthoringsemantic.MaxFieldBehaviorNodesPerDocument)
			}
			if err := budget.takeSemanticFloor(layoutAuthoringSemanticFloors.behaviorGroup); err != nil {
				return err
			}
			return preflightLayoutAuthoringBehaviorGroup(value, budget)
		}
		return nil
	})
}

func preflightLayoutAuthoringBehaviorGroup(data []byte, budget *layoutAuthoringWireBudget) error {
	behaviorsSeen := false
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		if number != 2 {
			return nil
		}
		if behaviorsSeen {
			return ErrMalformedPlatformWire
		}
		behaviorsSeen = true
		behaviors := 0
		return visitWireBytesFields(value, func(number protowire.Number, _ []byte) error {
			if number == 1 {
				behaviors++
				budget.behaviorNodes++
				if behaviors > layoutauthoringsemantic.MaxFieldBehaviorsPerField {
					return budget.fail(commonsemantic.LimitFieldCount, layoutauthoringsemantic.MaxFieldBehaviorsPerField)
				}
				if budget.behaviorNodes > layoutauthoringsemantic.MaxFieldBehaviorNodesPerDocument {
					return budget.fail(commonsemantic.LimitFieldCount, layoutauthoringsemantic.MaxFieldBehaviorNodesPerDocument)
				}
				return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.behavior)
			}
			return nil
		})
	})
}

func preflightLayoutAuthoringRelatedList(data []byte, budget *layoutAuthoringWireBudget) error {
	fields := 0
	mappings := 0
	return visitWireBytesFields(data, func(number protowire.Number, _ []byte) error {
		switch number {
		case 6:
			fields++
			if fields > layoutauthoringsemantic.MaxFieldsPerRelatedList {
				return budget.fail(commonsemantic.LimitFieldCount, layoutauthoringsemantic.MaxFieldsPerRelatedList)
			}
			return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.stringValue)
		case 7:
			mappings++
			if mappings > layoutauthoringsemantic.MaxPrefillMappings {
				return budget.fail(commonsemantic.LimitFieldCount, layoutauthoringsemantic.MaxPrefillMappings)
			}
			return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.prefillMapping)
		}
		return nil
	})
}

func preflightLayoutAuthoringRecordPanel(data []byte, budget *layoutAuthoringWireBudget) error {
	configuration := 0
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		if number == 8 {
			configuration++
			if configuration > layoutauthoringsemantic.MaxConfigurationEntries {
				return budget.fail(commonsemantic.LimitOperationCount, layoutauthoringsemantic.MaxConfigurationEntries)
			}
			if err := budget.takeSemanticFloor(layoutAuthoringSemanticFloors.namedValue); err != nil {
				return err
			}
			return preflightLayoutAuthoringNamedValue(value, budget)
		}
		return nil
	})
}

func preflightLayoutAuthoringActionPlacement(data []byte, budget *layoutAuthoringWireBudget) error {
	actions := 0
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		if number != 2 {
			return nil
		}
		actions++
		if actions > layoutauthoringsemantic.MaxActionsPerPlacement {
			return budget.fail(commonsemantic.LimitOperationCount, layoutauthoringsemantic.MaxActionsPerPlacement)
		}
		if err := budget.takeSemanticFloor(layoutAuthoringSemanticFloors.action); err != nil {
			return err
		}
		return preflightLayoutAuthoringAction(value, budget)
	})
}

func preflightLayoutAuthoringAction(data []byte, budget *layoutAuthoringWireBudget) error {
	counts := map[protowire.Number]int{}
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		if number != 8 && number != 9 {
			return nil
		}
		counts[number]++
		maximum := layoutauthoringsemantic.MaxConfigurationEntries
		if number == 9 {
			maximum = layoutauthoringsemantic.MaxActionExtensions
		}
		if counts[number] > maximum {
			return budget.fail(commonsemantic.LimitOperationCount, maximum)
		}
		if err := budget.takeSemanticFloor(layoutAuthoringSemanticFloors.namedValue); err != nil {
			return err
		}
		return preflightLayoutAuthoringNamedValue(value, budget)
	})
}

func preflightLayoutAuthoringRecordState(data []byte, budget *layoutAuthoringWireBudget) error {
	links := 0
	overrides := 0
	bannerSeen := false
	readOnlySeen := false
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		switch number {
		case 4:
			if bannerSeen {
				return ErrMalformedPlatformWire
			}
			bannerSeen = true
			if err := budget.takeSemanticFloor(layoutAuthoringSemanticFloors.banner); err != nil {
				return err
			}
			bannerLinks := 0
			return visitWireBytesFields(value, func(number protowire.Number, _ []byte) error {
				if number == 4 {
					bannerLinks++
					if bannerLinks > layoutauthoringsemantic.MaxRecordStateLinks {
						return budget.fail(commonsemantic.LimitOperationCount, layoutauthoringsemantic.MaxRecordStateLinks)
					}
					return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.stringValue)
				}
				return nil
			})
		case 5:
			links++
			if links > layoutauthoringsemantic.MaxRecordStateLinks {
				return budget.fail(commonsemantic.LimitOperationCount, layoutauthoringsemantic.MaxRecordStateLinks)
			}
			return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.link)
		case 6:
			overrides++
			if overrides > layoutauthoringsemantic.MaxRecordStateActionOverrides {
				return budget.fail(commonsemantic.LimitOperationCount, layoutauthoringsemantic.MaxRecordStateActionOverrides)
			}
			return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.actionOverride)
		case 7:
			if readOnlySeen {
				return ErrMalformedPlatformWire
			}
			readOnlySeen = true
			return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.readOnly)
		}
		return nil
	})
}

func preflightLayoutAuthoringNamedValue(data []byte, budget *layoutAuthoringWireBudget) error {
	return preflightLayoutAuthoringNamedValueAtDepth(data, 1, budget)
}

func preflightLayoutAuthoringNamedValueAtDepth(data []byte, depth int, budget *layoutAuthoringWireBudget) error {
	valueSeen := false
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		if number == 2 {
			if valueSeen {
				return ErrMalformedPlatformWire
			}
			valueSeen = true
			return preflightLayoutAuthoringValue(value, depth, budget)
		}
		return nil
	})
}

func preflightLayoutAuthoringValue(data []byte, depth int, budget *layoutAuthoringWireBudget) error {
	budget.valueNodes++
	if budget.valueNodes > layoutauthoringsemantic.MaxValueNodes {
		return budget.fail(commonsemantic.LimitOperationCount, layoutauthoringsemantic.MaxValueNodes)
	}
	if depth > layoutauthoringsemantic.MaxValueDepth {
		return budget.fail(commonsemantic.LimitQueryDepth, layoutauthoringsemantic.MaxValueDepth)
	}
	unionCount := 0
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		if number >= 1 && number <= 6 {
			unionCount++
			if unionCount > 1 {
				return ErrMalformedPlatformWire
			}
		}
		if number != 5 && number != 6 {
			return nil
		}
		budget.collections++
		if budget.collections > layoutauthoringsemantic.MaxValueCollections {
			return budget.fail(commonsemantic.LimitOperationCount, layoutauthoringsemantic.MaxValueCollections)
		}
		entries := 0
		return visitWireBytesFields(value, func(itemNumber protowire.Number, item []byte) error {
			if itemNumber != 1 {
				return nil
			}
			entries++
			if entries > layoutauthoringsemantic.MaxValueCollectionEntries {
				return budget.fail(commonsemantic.LimitOperationCount, layoutauthoringsemantic.MaxValueCollectionEntries)
			}
			if number == 5 {
				if err := budget.takeSemanticFloor(layoutAuthoringSemanticFloors.value); err != nil {
					return err
				}
				return preflightLayoutAuthoringValue(item, depth+1, budget)
			}
			if err := budget.takeSemanticFloor(layoutAuthoringSemanticFloors.namedValue); err != nil {
				return err
			}
			return preflightLayoutAuthoringNamedValueAtDepth(item, depth+1, budget)
		})
	})
}

func preflightLayoutAuthoringStringListChange(data []byte, maximum int, kind commonsemantic.LimitKind, budget *layoutAuthoringWireBudget) error {
	valueSeen := false
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		if number != 2 {
			return nil
		}
		if valueSeen {
			return ErrMalformedPlatformWire
		}
		valueSeen = true
		entries := 0
		return visitWireBytesFields(value, func(number protowire.Number, _ []byte) error {
			if number == 1 {
				entries++
				if entries > maximum {
					return budget.fail(kind, maximum)
				}
				return budget.takeSemanticFloor(layoutAuthoringSemanticFloors.stringValue)
			}
			return nil
		})
	})
}

func preflightLayoutAuthoringChanges(data []byte, budget *layoutAuthoringWireBudget) error {
	seen := map[protowire.Number]bool{}
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		if number >= 1 && number <= 12 && duplicateLayoutAuthoringSingular(seen, number) {
			return ErrMalformedPlatformWire
		}
		switch number {
		case 4:
			return preflightLayoutAuthoringStringListChange(value, layoutauthoringsemantic.MaxCompactFields, commonsemantic.LimitFieldCount, budget)
		case 5:
			return preflightLayoutAuthoringStringListChange(value, layoutauthoringsemantic.MaxTabs, commonsemantic.LimitOperationCount, budget)
		case 6:
			return preflightLayoutAuthoringMessageListChange(value, layoutauthoringsemantic.MaxSections, layoutAuthoringSemanticFloors.section, budget, preflightLayoutAuthoringSection)
		case 7:
			return preflightLayoutAuthoringMessageListChange(value, layoutauthoringsemantic.MaxRelatedLists, layoutAuthoringSemanticFloors.relatedList, budget, preflightLayoutAuthoringRelatedList)
		case 8:
			return preflightLayoutAuthoringMessageListChange(value, layoutauthoringsemantic.MaxRecordPanels, layoutAuthoringSemanticFloors.recordPanel, budget, preflightLayoutAuthoringRecordPanel)
		case 9, 10:
			valueSeen := false
			return visitWireBytesFields(value, func(number protowire.Number, nested []byte) error {
				if number == 2 {
					if valueSeen {
						return ErrMalformedPlatformWire
					}
					valueSeen = true
					return preflightLayoutAuthoringActionPlacement(nested, budget)
				}
				return nil
			})
		case 11:
			return preflightLayoutAuthoringMessageListChange(value, layoutauthoringsemantic.MaxRecordStates, layoutAuthoringSemanticFloors.recordState, budget, preflightLayoutAuthoringRecordState)
		case 12:
			return preflightLayoutAuthoringStringListChange(value, layoutauthoringsemantic.MaxPrimaryHeaderActions, commonsemantic.LimitOperationCount, budget)
		default:
			return nil
		}
	})
}

func preflightLayoutAuthoringMessageListChange(
	data []byte,
	maximum int,
	semanticFloor int,
	budget *layoutAuthoringWireBudget,
	visitItem func([]byte, *layoutAuthoringWireBudget) error,
) error {
	valueSeen := false
	return visitWireBytesFields(data, func(number protowire.Number, value []byte) error {
		if number != 2 {
			return nil
		}
		if valueSeen {
			return ErrMalformedPlatformWire
		}
		valueSeen = true
		entries := 0
		return visitWireBytesFields(value, func(number protowire.Number, item []byte) error {
			if number != 1 {
				return nil
			}
			entries++
			if entries > maximum {
				return budget.fail(commonsemantic.LimitOperationCount, maximum)
			}
			if err := budget.takeSemanticFloor(semanticFloor); err != nil {
				return err
			}
			return visitItem(item, budget)
		})
	})
}

func duplicateLayoutAuthoringSingular(seen map[protowire.Number]bool, number protowire.Number) bool {
	if seen[number] {
		return true
	}
	seen[number] = true
	return false
}

func preflightPlatformRequestFrame(data []byte) error {
	if len(data) > envelope.MaxRequestWireBytes {
		return platformLimitFailure(commonsemantic.LimitWireFrame, envelope.MaxRequestWireBytes)
	}
	return nil
}

func preflightPlatformResponseFrame(data []byte) error {
	if len(data) > envelope.MaxResponseWireBytes {
		return internalPlatformWire()
	}
	return nil
}

func preflightRepeatedMessageFields(
	data []byte,
	maxima map[protowire.Number]int,
	totalMaximum int,
	limitError func(int) error,
) error {
	counts := make(map[protowire.Number]int, len(maxima))
	total := 0
	return visitWireBytesFields(data, func(number protowire.Number, _ []byte) error {
		maximum, bounded := maxima[number]
		if !bounded {
			return nil
		}
		counts[number]++
		total++
		if counts[number] > maximum {
			return limitError(maximum)
		}
		if total > totalMaximum {
			return limitError(totalMaximum)
		}
		return nil
	})
}

func requestOperationCountLimit(maximum int) error {
	return platformLimitFailure(commonsemantic.LimitOperationCount, maximum)
}

func responseWireLimit(int) error {
	return internalPlatformWire()
}

func preflightAnalyticsDefinitionCounts(data []byte) error {
	components := 0
	reportEntries := 0
	return visitWireBytesFields(data, func(number protowire.Number, definition []byte) error {
		switch number {
		case 6:
			return visitWireBytesFields(definition, func(number protowire.Number, componentSet []byte) error {
				if number != 7 {
					return nil
				}
				return visitWireBytesFields(componentSet, func(number protowire.Number, _ []byte) error {
					if number != 1 {
						return nil
					}
					components++
					if components > analyticssemantic.MaxDashboardComponents {
						return requestOperationCountLimit(analyticssemantic.MaxDashboardComponents)
					}
					return nil
				})
			})
		case 8:
			return visitWireBytesFields(definition, func(number protowire.Number, collection []byte) error {
				if number != 9 && number != 10 && number != 11 {
					return nil
				}
				return visitWireBytesFields(collection, func(number protowire.Number, _ []byte) error {
					if number != 1 {
						return nil
					}
					reportEntries++
					if reportEntries > analyticssemantic.MaxReportDefinitionEntries {
						return requestOperationCountLimit(analyticssemantic.MaxReportDefinitionEntries)
					}
					return nil
				})
			})
		default:
			return nil
		}
	})
}

func visitWireBytesFields(data []byte, visit func(protowire.Number, []byte) error) error {
	for len(data) != 0 {
		number, wireType, tagBytes := protowire.ConsumeTag(data)
		if tagBytes < 0 {
			return ErrMalformedPlatformWire
		}
		data = data[tagBytes:]
		// Runtime v1 uses proto3 and declares no groups. Reject the obsolete
		// recursive grammar instead of asking a general-purpose parser to skip it
		// before transport admission runs.
		if wireType == protowire.StartGroupType || wireType == protowire.EndGroupType {
			return ErrMalformedPlatformWire
		}
		if wireType == protowire.BytesType {
			value, valueBytes := protowire.ConsumeBytes(data)
			if valueBytes < 0 {
				return ErrMalformedPlatformWire
			}
			if err := visit(number, value); err != nil {
				return err
			}
			data = data[valueBytes:]
			continue
		}
		valueBytes := protowire.ConsumeFieldValue(number, wireType, data)
		if valueBytes < 0 {
			return ErrMalformedPlatformWire
		}
		data = data[valueBytes:]
	}
	return nil
}
