package queryv1

import (
	"context"
	"encoding/json"
	"math"
	"regexp"
	"strings"
	"time"
	"unicode/utf8"
)

var (
	identifierPattern  = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*$`)
	pathPattern        = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_.]*$`)
	coefficientPattern = regexp.MustCompile(`^-?(0|[1-9][0-9]*)$`)
)

func SemanticRequestSize(request Request) (int, error) {
	data, err := json.Marshal(request)
	return len(data), err
}

func SemanticResponseSize(response Response) (int, error) {
	data, err := json.Marshal(response)
	return len(data), err
}

func SemanticHistoryRequestSize(request HistoryRequest) (int, error) {
	data, err := json.Marshal(request)
	return len(data), err
}

func SemanticHistoryResponseSize(response HistoryResponse) (int, error) {
	data, err := json.Marshal(response)
	return len(data), err
}

func ValidateRequest(ctx context.Context, request Request) error {
	if err := contextFailure(ctx); err != nil {
		return err
	}
	if _, ok := ctx.Deadline(); !ok {
		return invalid(InvalidComponentDeadline)
	}
	if !validIdentifier(request.ObjectID, MaxObjectIdentifierBytes) {
		if len(request.ObjectID) > MaxObjectIdentifierBytes {
			return exhausted(LimitObjectID, MaxObjectIdentifierBytes)
		}
		return invalid(InvalidComponentObjectID)
	}
	if len(request.Selections) == 0 {
		return invalid(InvalidComponentSelection)
	}
	if len(request.Selections) > MaxSelectedFields {
		return exhausted(LimitSelectedFields, MaxSelectedFields)
	}
	for _, selection := range request.Selections {
		if !validSelection(selection) {
			return invalid(InvalidComponentSelection)
		}
	}
	if request.Limit > MaxRows {
		return exhausted(LimitRecordCount, MaxRows)
	}
	// Aggregate execution needs one extra row to detect a full-page overflow.
	// This is an internal probe, not a larger public query page.
	if request.AggregateFetchLimit > MaxRows+1 {
		return exhausted(LimitRecordCount, MaxRows+1)
	}
	if request.Offset > MaxOffset {
		return exhausted(LimitQueryOffset, MaxOffset)
	}
	if len(request.OrderBy) > MaxOrderBy {
		return exhausted(LimitQueryOrderBy, MaxOrderBy)
	}
	if len(request.Subqueries) > MaxSubqueries {
		return exhausted(LimitQuerySubqueries, MaxSubqueries)
	}
	if request.GroupBy != "" && !validPath(request.GroupBy) {
		return invalid(InvalidComponentQueryPlan)
	}
	for _, order := range request.OrderBy {
		if !validPath(order.Field) || !validDirection(order.Direction) {
			return invalid(InvalidComponentQueryPlan)
		}
	}
	nodes := 0
	if err := validatePredicate(request.Filter, 1, &nodes); err != nil {
		return err
	}
	if err := validatePredicate(request.Having, 1, &nodes); err != nil {
		return err
	}
	for _, sub := range request.Subqueries {
		if !validIdentifier(sub.RelationshipName, MaxFieldIdentifierBytes) || len(sub.SelectedFields) == 0 || len(sub.SelectedFields) > MaxSelectedFields || sub.Limit > MaxRows || len(sub.OrderBy) > MaxOrderBy {
			return invalid(InvalidComponentQueryPlan)
		}
		for _, field := range sub.SelectedFields {
			if !validPath(field) {
				return invalid(InvalidComponentSelection)
			}
		}
		for _, order := range sub.OrderBy {
			if !validPath(order.Field) || !validDirection(order.Direction) {
				return invalid(InvalidComponentQueryPlan)
			}
		}
		if err := validatePredicate(sub.Filter, 2, &nodes); err != nil {
			return err
		}
	}
	if nodes > MaxPredicateNodes {
		return exhausted(LimitQueryPredicate, MaxPredicateNodes)
	}
	size, err := SemanticRequestSize(request)
	if err != nil {
		return invalid(InvalidComponentQueryPlan)
	}
	if !withinSemanticEnvelope(size, decimalExpansionInRequest(request), MaxSemanticRequestBytes) {
		return exhausted(LimitSemanticRequest, MaxSemanticRequestBytes)
	}
	return nil
}

func ValidateResponse(response Response) error {
	if !ValidReceipts(response.Receipts) {
		return incompatible()
	}
	maximumRows := MaxRows
	if response.Aggregate {
		maximumRows++ // Preserve the overflow sentinel for the caller.
	}
	if len(response.Records) > maximumRows {
		return exhausted(LimitRecordCount, uint64(maximumRows))
	}
	for i := range response.Records {
		if err := validateRecord(response.Records[i], 1); err != nil {
			return err
		}
	}
	size, err := SemanticResponseSize(response)
	if err != nil {
		return internal()
	}
	if !withinSemanticEnvelope(size, decimalExpansionInResponse(response), MaxSemanticResponseBytes) {
		return exhausted(LimitSemanticResponse, MaxSemanticResponseBytes)
	}
	return nil
}

// ValidateRecord validates the canonical neutral record carrier independently
// of the query response envelope. Other Runtime capabilities reuse this exact
// carrier instead of defining subtly different typed-value grammars.
func ValidateRecord(record Record) error {
	return validateRecord(record, 1)
}

// SemanticRecordExpansionBytes returns the additional rendered-byte budget
// required by exact decimals in the canonical record carrier. Capabilities
// that embed Record in another envelope use this owner instead of rebuilding
// the recursive decimal accounting.
func SemanticRecordExpansionBytes(record Record) uint64 {
	return decimalExpansionInRecord(record)
}

func ValidateHistoryRequest(ctx context.Context, request HistoryRequest) error {
	if err := contextFailure(ctx); err != nil {
		return err
	}
	if _, ok := ctx.Deadline(); !ok {
		return invalid(InvalidComponentDeadline)
	}
	if !validIdentifier(request.ParentObjectID, MaxObjectIdentifierBytes) {
		if len(request.ParentObjectID) > MaxObjectIdentifierBytes {
			return exhausted(LimitObjectID, MaxObjectIdentifierBytes)
		}
		return invalid(InvalidComponentObjectID)
	}
	if len(request.SelectedFields) == 0 {
		return invalid(InvalidComponentSelection)
	}
	if len(request.SelectedFields) > MaxSelectedFields {
		return exhausted(LimitSelectedFields, MaxSelectedFields)
	}
	for _, field := range request.SelectedFields {
		if !validPath(field) {
			return invalid(InvalidComponentSelection)
		}
	}
	if request.ParentRecordID != "" && (!utf8.ValidString(request.ParentRecordID) || len(request.ParentRecordID) > MaxRecordIdentifierBytes || strings.TrimSpace(request.ParentRecordID) != request.ParentRecordID) {
		if len(request.ParentRecordID) > MaxRecordIdentifierBytes {
			return exhausted(LimitRecordID, MaxRecordIdentifierBytes)
		}
		return invalid(InvalidComponentQueryPlan)
	}
	if request.Limit > MaxHistoryRows || request.PageSize > MaxHistoryRows {
		return exhausted(LimitRecordCount, MaxHistoryRows)
	}
	if request.Offset > MaxOffset || request.CursorOffset > MaxOffset {
		return exhausted(LimitQueryOffset, MaxOffset)
	}
	nodes := 0
	if err := validatePredicate(request.Filter, 1, &nodes); err != nil {
		return err
	}
	size, err := SemanticHistoryRequestSize(request)
	if err != nil {
		return invalid(InvalidComponentQueryPlan)
	}
	if !withinSemanticEnvelope(size, decimalExpansionInPredicate(request.Filter), MaxSemanticRequestBytes) {
		return exhausted(LimitSemanticRequest, MaxSemanticRequestBytes)
	}
	return nil
}

func ValidateHistoryResponse(response HistoryResponse) error {
	if !ValidReceipts(response.Receipts) {
		return incompatible()
	}
	if len(response.Rows) > MaxHistoryRows {
		return exhausted(LimitRecordCount, MaxHistoryRows)
	}
	for _, row := range response.Rows {
		if !validHistoryText(row.ID) || !validHistoryText(row.ParentID) || !validHistoryText(row.Field) ||
			!validHistoryText(row.DataType) || !validHistoryText(row.CreatedDate) || !validHistoryText(row.CreatedByID) ||
			(row.OldValue != nil && !utf8.ValidString(*row.OldValue)) || (row.NewValue != nil && !utf8.ValidString(*row.NewValue)) {
			return internal()
		}
	}
	size, err := SemanticHistoryResponseSize(response)
	if err != nil {
		return internal()
	}
	if size > MaxSemanticResponseBytes {
		return exhausted(LimitSemanticResponse, MaxSemanticResponseBytes)
	}
	return nil
}

func validHistoryText(value string) bool {
	return value != "" && utf8.ValidString(value) && !strings.ContainsAny(value, "\x00\r\n")
}

func ValidReceipts(receipts Receipts) bool {
	return receipts.ProtocolVersion == "1.0" && receipts.CapabilityVersion == CapabilityName
}

func validatePredicate(predicate Predicate, depth int, nodes *int) error {
	if predicate.Kind == PredicateNone {
		if !predicatePayloadEmpty(predicate) {
			return invalid(InvalidComponentPredicate)
		}
		return nil
	}
	(*nodes)++
	if depth > MaxNestingDepth {
		return exhausted(LimitQueryDepth, MaxNestingDepth)
	}
	if *nodes > MaxPredicateNodes {
		return exhausted(LimitQueryPredicate, MaxPredicateNodes)
	}
	switch predicate.Kind {
	case PredicateAnd, PredicateOr:
		if !predicateOnlyChildren(predicate) || len(predicate.Children) < 2 {
			return invalid(InvalidComponentPredicate)
		}
		for _, child := range predicate.Children {
			if err := validatePredicate(child, depth+1, nodes); err != nil {
				return err
			}
		}
	case PredicateNot:
		if !predicateOnlyChildren(predicate) || len(predicate.Children) != 1 {
			return invalid(InvalidComponentPredicate)
		}
		return validatePredicate(predicate.Children[0], depth+1, nodes)
	case PredicateExpression:
		if !predicateOnlyOperand(predicate) {
			return invalid(InvalidComponentPredicate)
		}
		return validateOperand(predicate.Operand, depth+1, nodes)
	case PredicateComparison:
		if !predicateOnlyComparison(predicate) || !predicate.Operator.Valid() {
			return invalid(InvalidComponentPredicate)
		}
		if err := validateOperand(predicate.Left, depth+1, nodes); err != nil {
			return err
		}
		return validateOperand(predicate.Right, depth+1, nodes)
	case PredicateFieldComparison:
		if !predicateOnlyFieldComparison(predicate) || !validPath(predicate.Field) || !predicate.Operator.Valid() || predicate.Value == nil || !validScalar(*predicate.Value) {
			return invalid(InvalidComponentPredicate)
		}
	case PredicateCorrelatedMembership:
		m := predicate.CorrelatedMembership
		if !predicateOnlyCorrelatedMembership(predicate) || m == nil ||
			(m.ID != "" && !validIdentifier(m.ID, MaxFieldIdentifierBytes)) ||
			!validPath(m.OuterField) || !validIdentifier(m.InnerObjectID, MaxObjectIdentifierBytes) ||
			!validPath(m.InnerSelectField) || m.InnerLimit > MaxRows {
			return invalid(InvalidComponentPredicate)
		}
		return validatePredicate(m.InnerFilter, depth+1, nodes)
	default:
		return invalid(InvalidComponentPredicate)
	}
	return nil
}

func validateOperand(operand Operand, depth int, nodes *int) error {
	(*nodes)++
	if depth > MaxNestingDepth {
		return exhausted(LimitQueryDepth, MaxNestingDepth)
	}
	if *nodes > MaxPredicateNodes {
		return exhausted(LimitQueryPredicate, MaxPredicateNodes)
	}
	switch operand.Kind {
	case OperandField:
		if !operandOnlyField(operand) || !validPath(operand.Field) {
			return invalid(InvalidComponentPredicate)
		}
	case OperandLiteral:
		if !operandOnlyLiteral(operand) || operand.Literal == nil || !validScalar(*operand.Literal) {
			return invalid(InvalidComponentPredicate)
		}
	case OperandList:
		if !operandOnlyElements(operand) || len(operand.Elements) == 0 {
			return invalid(InvalidComponentPredicate)
		}
		for _, element := range operand.Elements {
			if err := validateOperand(element, depth+1, nodes); err != nil {
				return err
			}
		}
	case OperandTrustedContext:
		if !operandOnlyTrustedContext(operand) || !operand.TrustedContext.Valid() {
			return invalid(InvalidComponentPredicate)
		}
	case OperandFunction:
		if !operandOnlyFunction(operand) || !operand.Function.Valid() {
			return invalid(InvalidComponentPredicate)
		}
		switch operand.Function {
		case FunctionTemporalPart:
			if !operand.TemporalBasis.Valid() || !operand.TemporalPart.Valid() || operand.DistanceUnit != "" || len(operand.Args) != 1 ||
				(operand.TemporalBasis == TemporalBasisBusiness && operand.TemporalPart != TemporalPartMonth && operand.TemporalPart != TemporalPartQuarter && operand.TemporalPart != TemporalPartYear) {
				return invalid(InvalidComponentPredicate)
			}
		case FunctionGeoDistance:
			if operand.TemporalBasis != "" || operand.TemporalPart != "" || !operand.DistanceUnit.Valid() || len(operand.Args) != 2 {
				return invalid(InvalidComponentPredicate)
			}
		case FunctionGeoPoint:
			if operand.TemporalBasis != "" || operand.TemporalPart != "" || operand.DistanceUnit != "" || len(operand.Args) != 2 {
				return invalid(InvalidComponentPredicate)
			}
		default:
			if operand.TemporalBasis != "" || operand.TemporalPart != "" || operand.DistanceUnit != "" {
				return invalid(InvalidComponentPredicate)
			}
		}
		for _, arg := range operand.Args {
			if err := validateOperand(arg, depth+1, nodes); err != nil {
				return err
			}
		}
	default:
		return invalid(InvalidComponentPredicate)
	}
	return nil
}

func predicatePayloadEmpty(predicate Predicate) bool {
	return predicate.Field == "" && predicate.Operator == "" && predicate.Value == nil &&
		operandEmpty(predicate.Left) && operandEmpty(predicate.Right) && operandEmpty(predicate.Operand) &&
		len(predicate.Children) == 0 && predicate.CorrelatedMembership == nil
}

func predicateOnlyChildren(predicate Predicate) bool {
	return predicate.Field == "" && predicate.Operator == "" && predicate.Value == nil &&
		operandEmpty(predicate.Left) && operandEmpty(predicate.Right) && operandEmpty(predicate.Operand) &&
		predicate.CorrelatedMembership == nil
}

func predicateOnlyOperand(predicate Predicate) bool {
	return predicate.Field == "" && predicate.Operator == "" && predicate.Value == nil &&
		operandEmpty(predicate.Left) && operandEmpty(predicate.Right) && len(predicate.Children) == 0 &&
		predicate.CorrelatedMembership == nil
}

func predicateOnlyComparison(predicate Predicate) bool {
	return predicate.Field == "" && predicate.Value == nil && operandEmpty(predicate.Operand) &&
		len(predicate.Children) == 0 && predicate.CorrelatedMembership == nil
}

func predicateOnlyFieldComparison(predicate Predicate) bool {
	return operandEmpty(predicate.Left) && operandEmpty(predicate.Right) && operandEmpty(predicate.Operand) &&
		len(predicate.Children) == 0 && predicate.CorrelatedMembership == nil
}

func predicateOnlyCorrelatedMembership(predicate Predicate) bool {
	return predicate.Field == "" && predicate.Operator == "" && predicate.Value == nil &&
		operandEmpty(predicate.Left) && operandEmpty(predicate.Right) && operandEmpty(predicate.Operand) &&
		len(predicate.Children) == 0
}

func operandEmpty(operand Operand) bool {
	return operand.Kind == OperandNone && operand.Field == "" && operand.Literal == nil &&
		operand.TrustedContext == "" && operand.Function == "" && operand.TemporalBasis == "" && operand.TemporalPart == "" && operand.DistanceUnit == "" &&
		len(operand.Args) == 0 && len(operand.Elements) == 0
}

func operandOnlyField(operand Operand) bool {
	return operand.Literal == nil && operand.TrustedContext == "" && operand.Function == "" && operand.TemporalBasis == "" && operand.TemporalPart == "" && operand.DistanceUnit == "" && len(operand.Args) == 0 && len(operand.Elements) == 0
}

func operandOnlyLiteral(operand Operand) bool {
	return operand.Field == "" && operand.TrustedContext == "" && operand.Function == "" && operand.TemporalBasis == "" && operand.TemporalPart == "" && operand.DistanceUnit == "" && len(operand.Args) == 0 && len(operand.Elements) == 0
}

func operandOnlyElements(operand Operand) bool {
	return operand.Field == "" && operand.Literal == nil && operand.TrustedContext == "" && operand.Function == "" && operand.TemporalBasis == "" && operand.TemporalPart == "" && operand.DistanceUnit == "" && len(operand.Args) == 0
}

func operandOnlyFunction(operand Operand) bool {
	return operand.Field == "" && operand.Literal == nil && operand.TrustedContext == "" && len(operand.Elements) == 0
}

func operandOnlyTrustedContext(operand Operand) bool {
	return operand.Field == "" && operand.Literal == nil && operand.Function == "" &&
		operand.TemporalBasis == "" && operand.TemporalPart == "" && operand.DistanceUnit == "" &&
		len(operand.Args) == 0 && len(operand.Elements) == 0
}

func validateRecord(record Record, depth int) error {
	if depth > MaxNestingDepth {
		return exhausted(LimitQueryDepth, MaxNestingDepth)
	}
	namedRecord := record.ObjectID != ""
	if namedRecord {
		if !validIdentifier(record.ObjectID, MaxObjectIdentifierBytes) {
			return internal()
		}
		if len(record.Fields) > MaxSelectedFields {
			return exhausted(LimitSelectedFields, MaxSelectedFields)
		}
	}
	for index, field := range record.Fields {
		if !utf8.ValidString(field.Name) || (namedRecord && !validIdentifier(field.Name, MaxFieldIdentifierBytes)) {
			return internal()
		}
		if index > 0 && record.Fields[index-1].Name >= field.Name {
			return internal()
		}
		if err := validateValue(field.Value, depth); err != nil {
			return err
		}
	}
	return nil
}

func validateValue(value Value, depth int) error {
	if depth > MaxNestingDepth {
		return exhausted(LimitQueryDepth, MaxNestingDepth)
	}
	arms := 0
	for _, present := range []bool{value.String != nil, value.Boolean != nil, value.Integer != nil, value.Unsigned != nil, value.Double != nil, value.Decimal != nil, value.Date != nil, value.DateTime != nil, value.Reference != nil, value.Object != nil, value.List != nil} {
		if present {
			arms++
		}
	}
	if !value.Kind.Valid() {
		return internal()
	}
	if value.Null {
		if arms != 0 {
			return internal()
		}
		return nil
	}
	if arms != 1 {
		return internal()
	}
	switch value.Kind {
	case ValueString:
		if value.String == nil || !utf8.ValidString(*value.String) {
			return internal()
		}
	case ValueBoolean:
		if value.Boolean == nil {
			return internal()
		}
	case ValueInteger:
		if value.Integer == nil {
			return internal()
		}
	case ValueUnsigned:
		if value.Unsigned == nil {
			return internal()
		}
	case ValueDouble:
		if value.Double == nil || math.IsNaN(*value.Double) || math.IsInf(*value.Double, 0) {
			return internal()
		}
	case ValueDecimal:
		if value.Decimal == nil || !validDecimal(*value.Decimal) {
			return internal()
		}
	case ValueDate:
		if value.Date == nil {
			return internal()
		}
		parsed, err := time.Parse("2006-01-02", *value.Date)
		if err != nil || parsed.Format("2006-01-02") != *value.Date {
			return internal()
		}
	case ValueDateTime:
		if value.DateTime == nil {
			return internal()
		}
		parsed, err := time.Parse(time.RFC3339Nano, *value.DateTime)
		if err != nil || !strings.HasSuffix(*value.DateTime, "Z") || parsed.Format(time.RFC3339Nano) != *value.DateTime {
			return internal()
		}
	case ValueReference:
		if value.Reference == nil || !utf8.ValidString(*value.Reference) {
			return internal()
		}
	case ValueObject:
		if value.Object == nil {
			return internal()
		}
		return validateRecord(*value.Object, depth+1)
	case ValueList:
		if value.List == nil {
			return internal()
		}
		for _, item := range *value.List {
			if err := validateValue(item, depth+1); err != nil {
				return err
			}
		}
	default:
		return internal()
	}
	return nil
}

func validScalar(value Scalar) bool {
	arms := 0
	for _, present := range []bool{value.String != nil, value.Boolean != nil, value.Integer != nil, value.Unsigned != nil, value.Double != nil, value.Decimal != nil, value.Date != nil, value.DateTime != nil} {
		if present {
			arms++
		}
	}
	if value.Null {
		return arms == 0
	}
	if arms != 1 {
		return false
	}
	if value.Double != nil && (math.IsNaN(*value.Double) || math.IsInf(*value.Double, 0)) {
		return false
	}
	if value.String != nil && !utf8.ValidString(*value.String) {
		return false
	}
	if value.Decimal != nil && !validDecimal(*value.Decimal) {
		return false
	}
	if value.Date != nil {
		parsed, err := time.Parse("2006-01-02", *value.Date)
		if err != nil || parsed.Format("2006-01-02") != *value.Date {
			return false
		}
	}
	if value.DateTime != nil {
		parsed, err := time.Parse(time.RFC3339Nano, *value.DateTime)
		if err != nil || !strings.HasSuffix(*value.DateTime, "Z") || parsed.Format(time.RFC3339Nano) != *value.DateTime {
			return false
		}
	}
	return true
}

func validDecimal(value Decimal) bool {
	return coefficientPattern.MatchString(value.Coefficient)
}

func validIdentifier(value string, maximum int) bool {
	return value != "" && len(value) <= maximum && identifierPattern.MatchString(value)
}
func validPath(value string) bool {
	if value == "" || len(value) > MaxFieldPathBytes || !pathPattern.MatchString(value) {
		return false
	}
	segments := strings.Split(value, ".")
	if len(segments) > MaxFieldPathSegments {
		return false
	}
	for _, segment := range segments {
		if !validIdentifier(segment, MaxFieldIdentifierBytes) {
			return false
		}
	}
	return true
}
func validDirection(value SortDirection) bool {
	return value == SortAscending || value == SortDescending
}

func validSelection(selection Selection) bool {
	switch selection.Kind {
	case SelectionField:
		return validPath(selection.Field) && selection.Aggregate == "" && selection.Alias == ""
	case SelectionAggregate:
		if !selection.Aggregate.Valid() || (selection.Aggregate != AggregateCount && selection.Field == "") {
			return false
		}
		if selection.Field != "" && !validPath(selection.Field) {
			return false
		}
		return selection.Alias == "" || validIdentifier(selection.Alias, MaxFieldIdentifierBytes)
	default:
		return false
	}
}

func withinSemanticEnvelope(jsonBytes int, decimalExpansion uint64, maximum int) bool {
	if jsonBytes < 0 || jsonBytes > maximum || decimalExpansion > uint64(maximum) {
		return false
	}
	return decimalExpansion <= uint64(maximum-jsonBytes)
}

func decimalExpansionInRequest(request Request) uint64 {
	total := decimalExpansionInPredicate(request.Filter) + decimalExpansionInPredicate(request.Having)
	for _, subquery := range request.Subqueries {
		total += decimalExpansionInPredicate(subquery.Filter)
	}
	return total
}

func decimalExpansionInPredicate(predicate Predicate) uint64 {
	var total uint64
	if predicate.Value != nil {
		total += decimalExpansionInScalar(*predicate.Value)
	}
	total += decimalExpansionInOperand(predicate.Left)
	total += decimalExpansionInOperand(predicate.Right)
	total += decimalExpansionInOperand(predicate.Operand)
	for _, child := range predicate.Children {
		total += decimalExpansionInPredicate(child)
	}
	if predicate.CorrelatedMembership != nil {
		total += decimalExpansionInPredicate(predicate.CorrelatedMembership.InnerFilter)
	}
	return total
}

func decimalExpansionInOperand(operand Operand) uint64 {
	var total uint64
	if operand.Literal != nil {
		total += decimalExpansionInScalar(*operand.Literal)
	}
	for _, arg := range operand.Args {
		total += decimalExpansionInOperand(arg)
	}
	for _, element := range operand.Elements {
		total += decimalExpansionInOperand(element)
	}
	return total
}

func decimalExpansionInScalar(value Scalar) uint64 {
	if value.Decimal == nil {
		return 0
	}
	return decimalRenderedBytes(*value.Decimal)
}

func decimalExpansionInResponse(response Response) uint64 {
	var total uint64
	for _, record := range response.Records {
		total += decimalExpansionInRecord(record)
	}
	return total
}

func decimalExpansionInRecord(record Record) uint64 {
	var total uint64
	for _, field := range record.Fields {
		total += decimalExpansionInValue(field.Value)
	}
	return total
}

func decimalExpansionInValue(value Value) uint64 {
	var total uint64
	if value.Decimal != nil {
		total += decimalRenderedBytes(*value.Decimal)
	}
	if value.Object != nil {
		total += decimalExpansionInRecord(*value.Object)
	}
	if value.List != nil {
		for _, item := range *value.List {
			total += decimalExpansionInValue(item)
		}
	}
	return total
}

func decimalRenderedBytes(value Decimal) uint64 {
	coefficientBytes := uint64(len(value.Coefficient))
	negative := strings.HasPrefix(value.Coefficient, "-")
	digitBytes := coefficientBytes
	if negative {
		digitBytes--
	}
	if value.Scale == 0 {
		return coefficientBytes
	}
	scale := uint64(value.Scale)
	if digitBytes > scale {
		return coefficientBytes + 1
	}
	result := scale + 2
	if negative {
		result++
	}
	return result
}

func contextFailure(ctx context.Context) error {
	if err := ctx.Err(); err != nil {
		if err == context.DeadlineExceeded {
			return &Failure{Category: FailureDeadlineExceeded}
		}
		return &Failure{Category: FailureCanceled}
	}
	return nil
}
func invalid(component InvalidComponent) *Failure {
	return &Failure{Category: FailureInvalidRequest, InvalidComponent: component}
}
func exhausted(kind LimitKind, maximum uint64) *Failure {
	return &Failure{Category: FailureResourceExhausted, LimitKind: kind, Maximum: maximum}
}
func incompatible() *Failure {
	return &Failure{Category: FailureIncompatible, RequiredCapability: CapabilityName, SupportedMajor: ProtocolMajor, SupportedMinorMin: ProtocolMinor, SupportedMinorMax: ProtocolMinor}
}
func internal() *Failure { return &Failure{Category: FailureInternal} }
