package sfcrmappservice

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"regexp"
	"strconv"
	"strings"
	"time"

	querycodec "github.com/pingcap-inc/nexuscrm-app-packs/sfcrm/querycodec"
	semantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/queryv1"
)

type RuntimeQueryFunc func(context.Context, string, semantic.Request) (semantic.Response, error)
type RuntimeHistoryQueryFunc func(context.Context, string, semantic.HistoryRequest) (semantic.HistoryResponse, error)

var queryAggregateSelectionPattern = regexp.MustCompile(`(?i)^(COUNT|SUM|AVG|MIN|MAX)\(\s*([A-Za-z_][A-Za-z0-9_.]*)?\s*\)(?:\s+(?:AS\s+)?([A-Za-z_][A-Za-z0-9_]*))?$`)
var queryExactNumberPattern = regexp.MustCompile(`^([+-]?)([0-9]+)(?:\.([0-9]*))?(?:[eE]([+-]?[0-9]+))?$`)

type queryBearerContextKey struct{}
type queryAuthorityContextKey struct{}

type runtimeQueryAuthority struct {
	receipts semantic.Receipts
	set      bool
	mixed    bool
}

func withQueryBearer(ctx context.Context, bearer string) context.Context {
	return context.WithValue(ctx, queryBearerContextKey{}, bearer)
}

func withQueryAuthority(ctx context.Context, authority *runtimeQueryAuthority) context.Context {
	return context.WithValue(ctx, queryAuthorityContextKey{}, authority)
}

func observeQueryAuthority(ctx context.Context, receipts semantic.Receipts) {
	authority, _ := ctx.Value(queryAuthorityContextKey{}).(*runtimeQueryAuthority)
	if authority == nil {
		return
	}
	if !authority.set {
		authority.receipts, authority.set = receipts, true
		return
	}
	if authority.receipts.CatalogRevision != receipts.CatalogRevision ||
		authority.receipts.SchemaGeneration != receipts.SchemaGeneration ||
		authority.receipts.EngineGeneration != receipts.EngineGeneration ||
		authority.receipts.SecurityEpoch != receipts.SecurityEpoch {
		authority.mixed = true
	}
}

func (authority *runtimeQueryAuthority) matches(receipts semantic.Receipts) bool {
	return authority != nil && authority.set && !authority.mixed &&
		authority.receipts.CatalogRevision == receipts.CatalogRevision &&
		authority.receipts.SchemaGeneration == receipts.SchemaGeneration &&
		authority.receipts.EngineGeneration == receipts.EngineGeneration &&
		authority.receipts.SecurityEpoch == receipts.SecurityEpoch
}

// RuntimeQueryAdapter is the L1 lowering boundary between the single-owner CRM
// query codec and the coarse neutral Runtime family. It has no database or
// legacy-backend path. Search remains a separate capability family.
type RuntimeQueryAdapter struct {
	query   RuntimeQueryFunc
	history RuntimeHistoryQueryFunc
	dates   *runtimeQueryDates
}

func NewRuntimeQueryHandler(query RuntimeQueryFunc, history RuntimeHistoryQueryFunc, dates ...*runtimeQueryDates) (*querycodec.Handler, error) {
	if query == nil || history == nil {
		return nil, errors.New("sfcrm AppService: Runtime query and history clients are required")
	}
	adapter := &RuntimeQueryAdapter{query: query, history: history}
	executor := querycodec.Executor{Query: adapter.queryRecords, History: adapter.queryHistory}
	if len(dates) > 0 && dates[0] != nil {
		adapter.dates = dates[0]
		executor.Dates = dates[0].resolve
	}
	return querycodec.NewHandler(executor)
}

func (c *RuntimeQueryAdapter) queryRecords(ctx context.Context, request querycodec.QueryRequest, aggregateFetchLimit int) (querycodec.Result, error) {
	bearer, ok := ctx.Value(queryBearerContextKey{}).(string)
	if !ok || bearer == "" || c == nil || c.query == nil {
		return querycodec.Result{}, runtimeQueryFailure(&semantic.Failure{Category: semantic.FailureUnavailable}, false)
	}
	semanticRequest, err := queryRequestToSemantic(request, aggregateFetchLimit)
	if err != nil {
		return querycodec.Result{}, err
	}
	if view, ok := c.dateMetadata(ctx); ok {
		semanticRequest.MinCatalogRevision = pointerTo(view.Receipts.CatalogRevision)
	}
	if err := semantic.ValidateRequest(ctx, semanticRequest); err != nil {
		return querycodec.Result{}, runtimeQueryFailure(err, false)
	}
	response, err := c.query(ctx, bearer, semanticRequest)
	if err != nil {
		return querycodec.Result{}, runtimeQueryFailure(err, false)
	}
	if err := semantic.ValidateResponse(response); err != nil {
		return querycodec.Result{}, runtimeQueryFailure(err, false)
	}
	if view, ok := c.dateMetadata(ctx); ok {
		if err := validateSearchMetadataAuthority(ctx, c.dates.reconcile, view, response.Receipts); err != nil {
			return querycodec.Result{}, runtimeQueryFailure(err, false)
		}
	}
	observeQueryAuthority(ctx, response.Receipts)
	result := querycodec.Result{TotalSize: int(response.TotalSize), TotalSizeUnknown: response.TotalSizeUnknown, Done: response.Done, Aggregate: response.Aggregate}
	for _, record := range response.Records {
		mapped, err := queryRecordFromSemantic(record)
		if err != nil {
			return querycodec.Result{}, runtimeQueryFailure(err, false)
		}
		result.Records = append(result.Records, mapped)
	}
	return result, nil
}

func (c *RuntimeQueryAdapter) queryHistory(ctx context.Context, request querycodec.HistoryRequest) (querycodec.HistoryResult, error) {
	bearer, ok := ctx.Value(queryBearerContextKey{}).(string)
	if !ok || bearer == "" || c == nil || c.history == nil {
		return querycodec.HistoryResult{}, runtimeQueryFailure(&semantic.Failure{Category: semantic.FailureUnavailable}, true)
	}
	if request.Limit < 0 || request.Limit > semantic.MaxHistoryRows ||
		request.Offset < 0 || uint64(request.Offset) > semantic.MaxOffset ||
		request.PageSize < 0 || request.PageSize > semantic.MaxHistoryRows ||
		request.CursorOffset < 0 || uint64(request.CursorOffset) > semantic.MaxOffset {
		return querycodec.HistoryResult{}, invalidQuery()
	}
	filter, err := queryPredicateToSemantic(request.Filter)
	if err != nil {
		return querycodec.HistoryResult{}, err
	}
	semanticRequest := semantic.HistoryRequest{
		ParentObjectID: request.ParentObjectAPIName, SelectedFields: append([]string(nil), request.SelectFields...),
		ParentRecordID: request.ParentID, Filter: filter, Limit: uint32(request.Limit), Offset: uint64(request.Offset),
		SortDescending: request.SortDescending, IncludeDeleted: request.IncludeDeleted, PageSize: uint32(request.PageSize), CursorOffset: uint64(request.CursorOffset),
	}
	if view, ok := c.dateMetadata(ctx); ok {
		semanticRequest.MinCatalogRevision = pointerTo(view.Receipts.CatalogRevision)
	}
	if err := semantic.ValidateHistoryRequest(ctx, semanticRequest); err != nil {
		return querycodec.HistoryResult{}, runtimeQueryFailure(err, true)
	}
	response, err := c.history(ctx, bearer, semanticRequest)
	if err != nil {
		return querycodec.HistoryResult{}, runtimeQueryFailure(err, true)
	}
	if err := semantic.ValidateHistoryResponse(response); err != nil {
		return querycodec.HistoryResult{}, runtimeQueryFailure(err, true)
	}
	if view, ok := c.dateMetadata(ctx); ok {
		if err := validateSearchMetadataAuthority(ctx, c.dates.reconcile, view, response.Receipts); err != nil {
			return querycodec.HistoryResult{}, runtimeQueryFailure(err, true)
		}
	}
	result := querycodec.HistoryResult{TotalSize: int(response.TotalSize), Done: response.Done}
	for _, row := range response.Rows {
		result.Rows = append(result.Rows, querycodec.HistoryRecord{ID: row.ID, ParentID: row.ParentID, Field: row.Field, OldValue: row.OldValue, NewValue: row.NewValue, DataType: row.DataType, CreatedDate: row.CreatedDate, CreatedByID: row.CreatedByID})
	}
	return result, nil
}

func queryRequestToSemantic(request querycodec.QueryRequest, aggregateFetchLimit int) (semantic.Request, error) {
	if request.Limit < 0 || request.Limit > semantic.MaxRows || request.Offset < 0 || uint64(request.Offset) > semantic.MaxOffset {
		return semantic.Request{}, invalidQuery()
	}
	filter, err := queryPredicateToSemantic(request.Filter)
	if err != nil {
		return semantic.Request{}, err
	}
	having, err := queryPredicateToSemantic(request.HavingPredicate)
	if err != nil {
		return semantic.Request{}, err
	}
	selections, err := querySelectionsToSemantic(request.SelectFields)
	if err != nil {
		return semantic.Request{}, err
	}
	result := semantic.Request{ObjectID: request.ObjectAPIName, Selections: selections, Filter: filter, Limit: uint32(request.Limit), Offset: uint64(request.Offset), SkipTotalSize: request.SkipTotalSize, IncludeDeleted: request.ScanAll, GroupBy: request.GroupBy, Having: having}
	for _, order := range request.OrderBy {
		direction, err := querySortDirectionToSemantic(order.Direction)
		if err != nil {
			return semantic.Request{}, err
		}
		result.OrderBy = append(result.OrderBy, semantic.Sort{Field: order.Field, Direction: direction})
	}
	for _, sub := range request.SubQueries {
		if sub.Limit < 0 || sub.Limit > semantic.MaxRows {
			return semantic.Request{}, invalidQuery()
		}
		predicate, err := queryPredicateToSemantic(sub.Filter)
		if err != nil {
			return semantic.Request{}, err
		}
		mapped := semantic.Subquery{RelationshipName: sub.RelationshipName, SelectedFields: append([]string(nil), sub.SelectFields...), Filter: predicate, Limit: uint32(sub.Limit)}
		for _, order := range sub.OrderBy {
			direction, err := querySortDirectionToSemantic(order.Direction)
			if err != nil {
				return semantic.Request{}, err
			}
			mapped.OrderBy = append(mapped.OrderBy, semantic.Sort{Field: order.Field, Direction: direction})
		}
		result.Subqueries = append(result.Subqueries, mapped)
	}
	if aggregateFetchLimit > 0 {
		// The existing grouped-query path fetches one sentinel row beyond
		// the public batch to detect overflow before formatting the result.
		if aggregateFetchLimit > semantic.MaxRows+1 {
			return semantic.Request{}, invalidQuery()
		}
		result.AggregateFetchLimit = uint32(aggregateFetchLimit)
	}
	return result, nil
}

func querySelectionsToSemantic(fields []string) ([]semantic.Selection, error) {
	result := make([]semantic.Selection, 0, len(fields))
	for _, field := range fields {
		matches := queryAggregateSelectionPattern.FindStringSubmatch(strings.TrimSpace(field))
		if len(matches) == 4 {
			aggregate, err := queryAggregateToSemantic(matches[1])
			if err != nil {
				return nil, err
			}
			result = append(result, semantic.Selection{Kind: semantic.SelectionAggregate, Aggregate: aggregate, Field: strings.TrimSpace(matches[2]), Alias: strings.TrimSpace(matches[3])})
			continue
		}
		if strings.ContainsAny(field, " ()\t\r\n") {
			return nil, invalidQuery()
		}
		result = append(result, semantic.Selection{Kind: semantic.SelectionField, Field: field})
	}
	return result, nil
}

func queryAggregateToSemantic(value string) (semantic.AggregateFunction, error) {
	switch strings.ToUpper(strings.TrimSpace(value)) {
	case "COUNT":
		return semantic.AggregateCount, nil
	case "SUM":
		return semantic.AggregateSum, nil
	case "AVG":
		return semantic.AggregateAverage, nil
	case "MIN":
		return semantic.AggregateMinimum, nil
	case "MAX":
		return semantic.AggregateMaximum, nil
	default:
		return "", invalidQuery()
	}
}

func querySortDirectionToSemantic(value string) (semantic.SortDirection, error) {
	switch strings.ToUpper(strings.TrimSpace(value)) {
	case "ASC":
		return semantic.SortAscending, nil
	case "DESC":
		return semantic.SortDescending, nil
	default:
		return "", invalidQuery()
	}
}

func queryComparisonOperatorToSemantic(value string) (semantic.ComparisonOperator, error) {
	switch strings.ToLower(strings.Join(strings.Fields(value), " ")) {
	case "=", "==":
		return semantic.ComparisonEqual, nil
	case "!=", "<>":
		return semantic.ComparisonNotEqual, nil
	case ">":
		return semantic.ComparisonGreaterThan, nil
	case ">=":
		return semantic.ComparisonGreaterOrEqual, nil
	case "<":
		return semantic.ComparisonLessThan, nil
	case "<=":
		return semantic.ComparisonLessOrEqual, nil
	case "in":
		return semantic.ComparisonIn, nil
	case "not in":
		return semantic.ComparisonNotIn, nil
	case "contains":
		return semantic.ComparisonContains, nil
	case "startswith":
		return semantic.ComparisonStartsWith, nil
	case "endswith":
		return semantic.ComparisonEndsWith, nil
	case "like":
		return semantic.ComparisonLike, nil
	case "not like":
		return semantic.ComparisonNotLike, nil
	default:
		return "", invalidQuery()
	}
}

type semanticFunction struct {
	function      semantic.Function
	temporalBasis semantic.TemporalBasis
	temporalPart  semantic.TemporalPart
}

func queryFunctionToSemantic(value string) (semanticFunction, error) {
	functions := map[string]semanticFunction{
		"COUNT": {function: semantic.FunctionCount}, "COUNT_DISTINCT": {function: semantic.FunctionCountDistinct},
		"SUM": {function: semantic.FunctionSum}, "AVG": {function: semantic.FunctionAverage}, "MIN": {function: semantic.FunctionMinimum}, "MAX": {function: semantic.FunctionMaximum},
		"TOSTRING": {function: semantic.FunctionString}, "FORMAT": {function: semantic.FunctionFormat}, "TOLABEL": {function: semantic.FunctionDisplayValue},
		"CONVERTCURRENCY": {function: semantic.FunctionNormalizeCurrency}, "GROUPING": {function: semantic.FunctionGrouping},
		"CALENDAR_MONTH": {function: semantic.FunctionTemporalPart, temporalBasis: semantic.TemporalBasisCivil, temporalPart: semantic.TemporalPartMonth}, "CALENDAR_YEAR": {function: semantic.FunctionTemporalPart, temporalBasis: semantic.TemporalBasisCivil, temporalPart: semantic.TemporalPartYear}, "CALENDAR_QUARTER": {function: semantic.FunctionTemporalPart, temporalBasis: semantic.TemporalBasisCivil, temporalPart: semantic.TemporalPartQuarter},
		"DAY_IN_MONTH": {function: semantic.FunctionTemporalPart, temporalBasis: semantic.TemporalBasisCivil, temporalPart: semantic.TemporalPartDayOfMonth}, "DAY_IN_WEEK": {function: semantic.FunctionTemporalPart, temporalBasis: semantic.TemporalBasisCivil, temporalPart: semantic.TemporalPartDayOfWeek}, "DAY_IN_YEAR": {function: semantic.FunctionTemporalPart, temporalBasis: semantic.TemporalBasisCivil, temporalPart: semantic.TemporalPartDayOfYear},
		"DAY_ONLY": {function: semantic.FunctionTemporalPart, temporalBasis: semantic.TemporalBasisCivil, temporalPart: semantic.TemporalPartDate}, "HOUR_IN_DAY": {function: semantic.FunctionTemporalPart, temporalBasis: semantic.TemporalBasisCivil, temporalPart: semantic.TemporalPartHour},
		"FISCAL_MONTH": {function: semantic.FunctionTemporalPart, temporalBasis: semantic.TemporalBasisBusiness, temporalPart: semantic.TemporalPartMonth}, "FISCAL_QUARTER": {function: semantic.FunctionTemporalPart, temporalBasis: semantic.TemporalBasisBusiness, temporalPart: semantic.TemporalPartQuarter}, "FISCAL_YEAR": {function: semantic.FunctionTemporalPart, temporalBasis: semantic.TemporalBasisBusiness, temporalPart: semantic.TemporalPartYear},
		"WEEK_IN_MONTH": {function: semantic.FunctionTemporalPart, temporalBasis: semantic.TemporalBasisCivil, temporalPart: semantic.TemporalPartWeekOfMonth}, "WEEK_IN_YEAR": {function: semantic.FunctionTemporalPart, temporalBasis: semantic.TemporalBasisCivil, temporalPart: semantic.TemporalPartWeekOfYear},
		"DISTANCE": {function: semantic.FunctionGeoDistance}, "GEOLOCATION": {function: semantic.FunctionGeoPoint},
	}
	function, ok := functions[strings.ToUpper(strings.TrimSpace(value))]
	if !ok {
		return semanticFunction{}, invalidQuery()
	}
	return function, nil
}

func queryRawScalarToSemantic(raw string) (semantic.Scalar, error) {
	if strings.EqualFold(strings.TrimSpace(raw), "null") || strings.EqualFold(strings.TrimSpace(raw), "nil") {
		return semantic.Scalar{Null: true}, nil
	}
	decimal, ok := exactQueryDecimal(strings.TrimSpace(raw))
	if !ok {
		return semantic.Scalar{}, invalidQuery()
	}
	return semantic.Scalar{Decimal: &decimal}, nil
}

func exactQueryDecimal(value string) (semantic.Decimal, bool) {
	matches := queryExactNumberPattern.FindStringSubmatch(value)
	if len(matches) != 5 {
		return semantic.Decimal{}, false
	}
	exponent := int64(0)
	if matches[4] != "" {
		parsed, err := strconv.ParseInt(matches[4], 10, 32)
		if err != nil {
			return semantic.Decimal{}, false
		}
		exponent = parsed
	}
	coefficient := strings.TrimLeft(matches[2]+matches[3], "0")
	if coefficient == "" {
		coefficient = "0"
	}
	scale := int64(len(matches[3])) - exponent
	if scale < 0 {
		zeroes := -scale
		if zeroes > semantic.MaxSemanticRequestBytes || int64(len(coefficient))+zeroes > semantic.MaxSemanticRequestBytes {
			return semantic.Decimal{}, false
		}
		coefficient += strings.Repeat("0", int(zeroes))
		scale = 0
	}
	if scale > semantic.MaxSemanticRequestBytes {
		return semantic.Decimal{}, false
	}
	if matches[1] == "-" && coefficient != "0" {
		coefficient = "-" + coefficient
	}
	return semantic.Decimal{Coefficient: coefficient, Scale: uint32(scale)}, true
}

func invalidQuery() *querycodec.Failure {
	return &querycodec.Failure{Category: querycodec.FailureInvalid, Message: "Invalid query"}
}

func queryPredicateToSemantic(value querycodec.Predicate) (semantic.Predicate, error) {
	result := semantic.Predicate{Field: value.Field}
	switch value.Kind {
	case querycodec.PredicateNone:
		result.Kind = semantic.PredicateNone
	case querycodec.PredicateAnd:
		result.Kind = semantic.PredicateAnd
	case querycodec.PredicateOr:
		result.Kind = semantic.PredicateOr
	case querycodec.PredicateNot:
		result.Kind = semantic.PredicateNot
	case querycodec.PredicateExpression:
		result.Kind = semantic.PredicateExpression
	case querycodec.PredicateComparison:
		result.Kind = semantic.PredicateComparison
	case querycodec.PredicateFieldComparison:
		result.Kind = semantic.PredicateFieldComparison
	case querycodec.PredicateCorrelatedMembership:
		result.Kind = semantic.PredicateCorrelatedMembership
	default:
		return semantic.Predicate{}, invalidQuery()
	}
	var err error
	if value.Kind == querycodec.PredicateComparison || value.Kind == querycodec.PredicateFieldComparison {
		result.Operator, err = queryComparisonOperatorToSemantic(value.Op)
		if err != nil {
			return semantic.Predicate{}, err
		}
	}
	if value.Kind == querycodec.PredicateFieldComparison {
		scalar, scalarErr := queryScalarToSemantic(value.Value)
		if scalarErr != nil {
			return semantic.Predicate{}, scalarErr
		}
		result.Value = &scalar
	}
	result.Left, err = queryOperandToSemantic(value.Left)
	if err != nil {
		return semantic.Predicate{}, err
	}
	result.Right, err = queryOperandToSemantic(value.Right)
	if err != nil {
		return semantic.Predicate{}, err
	}
	result.Operand, err = queryOperandToSemantic(value.Operand)
	if err != nil {
		return semantic.Predicate{}, err
	}
	for _, child := range value.Children {
		mapped, err := queryPredicateToSemantic(child)
		if err != nil {
			return semantic.Predicate{}, err
		}
		result.Children = append(result.Children, mapped)
	}
	if value.CorrelatedMembership != nil {
		inner, err := queryPredicateToSemantic(value.CorrelatedMembership.InnerFilter)
		if err != nil {
			return semantic.Predicate{}, err
		}
		m := value.CorrelatedMembership
		if m.InnerLimit < 0 || m.InnerLimit > semantic.MaxRows {
			return semantic.Predicate{}, invalidQuery()
		}
		result.CorrelatedMembership = &semantic.CorrelatedMembership{ID: m.ID, OuterField: m.OuterField, Negate: m.Negate, InnerObjectID: m.InnerObjectAPIName, InnerSelectField: m.InnerSelectField, InnerFilter: inner, InnerLimit: uint32(m.InnerLimit), InnerIncludeDeleted: m.InnerScanAll}
	}
	return result, nil
}

func queryOperandToSemantic(value querycodec.Operand) (semantic.Operand, error) {
	result := semantic.Operand{Field: value.Field}
	switch value.Kind {
	case querycodec.OperandNone:
		result.Kind = semantic.OperandNone
		return result, nil
	case querycodec.OperandField:
		result.Kind = semantic.OperandField
	case querycodec.OperandLiteral:
		result.Kind = semantic.OperandLiteral
		scalar, err := queryScalarToSemantic(value.Value)
		if err != nil {
			return semantic.Operand{}, err
		}
		result.Literal = &scalar
	case querycodec.OperandRaw:
		result.Kind = semantic.OperandLiteral
		scalar, err := queryRawScalarToSemantic(value.Raw)
		if err != nil {
			return semantic.Operand{}, err
		}
		result.Literal = &scalar
	case querycodec.OperandList:
		result.Kind = semantic.OperandList
	case querycodec.OperandFunction:
		result.Kind = semantic.OperandFunction
		function, err := queryFunctionToSemantic(value.Function)
		if err != nil {
			return semantic.Operand{}, err
		}
		result.Function = function.function
		result.TemporalBasis = function.temporalBasis
		result.TemporalPart = function.temporalPart
	default:
		return semantic.Operand{}, invalidQuery()
	}
	for _, item := range value.Elements {
		mapped, err := queryOperandToSemantic(item)
		if err != nil {
			return semantic.Operand{}, err
		}
		result.Elements = append(result.Elements, mapped)
	}
	for _, item := range value.Args {
		mapped, err := queryOperandToSemantic(item)
		if err != nil {
			return semantic.Operand{}, err
		}
		result.Args = append(result.Args, mapped)
	}
	if result.Function == semantic.FunctionGeoDistance {
		if len(result.Args) != 3 || result.Args[2].Kind != semantic.OperandLiteral || result.Args[2].Literal == nil || result.Args[2].Literal.String == nil {
			return semantic.Operand{}, invalidQuery()
		}
		switch strings.ToLower(strings.TrimSpace(*result.Args[2].Literal.String)) {
		case "mi":
			result.DistanceUnit = semantic.DistanceUnitMiles
		case "km":
			result.DistanceUnit = semantic.DistanceUnitKilometers
		default:
			return semantic.Operand{}, invalidQuery()
		}
		result.Args = result.Args[:2]
	}
	return result, nil
}

func queryScalarToSemantic(value any) (semantic.Scalar, error) {
	switch typed := value.(type) {
	case nil:
		return semantic.Scalar{Null: true}, nil
	case querycodec.DateLiteralValue:
		text := string(typed)
		return semantic.Scalar{Date: &text}, nil
	case querycodec.DateTimeLiteralValue:
		text := string(typed)
		return semantic.Scalar{DateTime: &text}, nil
	case string:
		return semantic.Scalar{String: &typed}, nil
	case bool:
		return semantic.Scalar{Boolean: &typed}, nil
	case int:
		mapped := int64(typed)
		return semantic.Scalar{Integer: &mapped}, nil
	case int8:
		mapped := int64(typed)
		return semantic.Scalar{Integer: &mapped}, nil
	case int16:
		mapped := int64(typed)
		return semantic.Scalar{Integer: &mapped}, nil
	case int32:
		mapped := int64(typed)
		return semantic.Scalar{Integer: &mapped}, nil
	case int64:
		return semantic.Scalar{Integer: &typed}, nil
	case uint:
		mapped := uint64(typed)
		return semantic.Scalar{Unsigned: &mapped}, nil
	case uint8:
		mapped := uint64(typed)
		return semantic.Scalar{Unsigned: &mapped}, nil
	case uint16:
		mapped := uint64(typed)
		return semantic.Scalar{Unsigned: &mapped}, nil
	case uint32:
		mapped := uint64(typed)
		return semantic.Scalar{Unsigned: &mapped}, nil
	case uint64:
		return semantic.Scalar{Unsigned: &typed}, nil
	case float32:
		mapped := float64(typed)
		return semantic.Scalar{Double: &mapped}, nil
	case float64:
		if math.IsNaN(typed) || math.IsInf(typed, 0) {
			break
		}
		return semantic.Scalar{Double: &typed}, nil
	case json.Number:
		if decimal, ok := exactQueryDecimal(string(typed)); ok {
			return semantic.Scalar{Decimal: &decimal}, nil
		}
	case time.Time:
		text := typed.UTC().Format(time.RFC3339Nano)
		return semantic.Scalar{DateTime: &text}, nil
	}
	return semantic.Scalar{}, invalidQuery()
}

func queryRecordFromSemantic(record semantic.Record) (querycodec.Record, error) {
	result := querycodec.Record{ObjectType: record.ObjectID, Fields: make(map[string]any, len(record.Fields))}
	for _, field := range record.Fields {
		value, err := queryValueFromSemantic(field.Value)
		if err != nil {
			return querycodec.Record{}, err
		}
		result.Fields[field.Name] = value
	}
	return result, nil
}

func queryValueFromSemantic(value semantic.Value) (any, error) {
	if value.Null {
		return nil, nil
	}
	switch value.Kind {
	case semantic.ValueString:
		return dereference(value.String)
	case semantic.ValueBoolean:
		return dereference(value.Boolean)
	case semantic.ValueInteger:
		return dereference(value.Integer)
	case semantic.ValueUnsigned:
		return dereference(value.Unsigned)
	case semantic.ValueDouble:
		return dereference(value.Double)
	case semantic.ValueDecimal:
		if value.Decimal == nil {
			break
		}
		return exactJSONDecimal(decimalText(value.Decimal.Coefficient, value.Decimal.Scale)), nil
	case semantic.ValueDate:
		return dereference(value.Date)
	case semantic.ValueDateTime:
		return dereference(value.DateTime)
	case semantic.ValueReference:
		return dereference(value.Reference)
	case semantic.ValueObject:
		if value.Object != nil {
			mapped, err := queryRecordFromSemantic(*value.Object)
			if err != nil {
				return nil, err
			}
			if value.Object.ObjectID == "" {
				return mapped.Fields, nil
			}
			return mapped, nil
		}
	case semantic.ValueList:
		if value.List != nil {
			result := make([]any, 0, len(*value.List))
			for _, item := range *value.List {
				mapped, err := queryValueFromSemantic(item)
				if err != nil {
					return nil, err
				}
				result = append(result, mapped)
			}
			return result, nil
		}
	}
	return nil, &semantic.Failure{Category: semantic.FailureInternal}
}

func dereference[T any](value *T) (T, error) {
	if value == nil {
		var zero T
		return zero, &semantic.Failure{Category: semantic.FailureInternal}
	}
	return *value, nil
}

type exactJSONDecimal string

func (value exactJSONDecimal) MarshalJSON() ([]byte, error) {
	text := string(value)
	if text == "" || strings.ContainsAny(text, "eE+") {
		return nil, errors.New("invalid exact decimal")
	}
	return []byte(text), nil
}

func decimalText(coefficient string, scale uint32) string {
	negative := strings.HasPrefix(coefficient, "-")
	digits := strings.TrimPrefix(coefficient, "-")
	if scale > 0 {
		for len(digits) <= int(scale) {
			digits = "0" + digits
		}
		pivot := len(digits) - int(scale)
		digits = digits[:pivot] + "." + digits[pivot:]
	}
	if negative {
		return "-" + digits
	}
	return digits
}

func runtimeQueryFailure(err error, history bool) error {
	var failure *semantic.Failure
	if !errors.As(err, &failure) {
		return &querycodec.Failure{Category: querycodec.FailureInternal}
	}
	switch failure.Category {
	case semantic.FailureInvalidRequest:
		if failure.InvalidComponent == semantic.InvalidComponentSelection {
			return &querycodec.Failure{Category: querycodec.FailureInvalidField, Message: "Invalid field in query selection"}
		}
		category := querycodec.FailureInvalid
		if history {
			category = querycodec.FailureMalformed
		}
		return &querycodec.Failure{Category: category, Message: "Invalid query"}
	case semantic.FailureUnauthenticated:
		return &querycodec.Failure{Category: querycodec.FailureUnauthenticated, Message: "Session expired or invalid"}
	case semantic.FailureForbidden:
		return &querycodec.Failure{Category: querycodec.FailureForbidden, Message: "Insufficient access"}
	case semantic.FailureMissing:
		return &querycodec.Failure{Category: querycodec.FailureMissing, Message: "Resource not found"}
	case semantic.FailureResourceExhausted:
		category := querycodec.FailureExhausted
		if failure.LimitKind == semantic.LimitSemanticResponse {
			category = querycodec.FailureResponseTooLarge
		}
		return &querycodec.Failure{Category: category, Message: queryLimitMessage(failure, history)}
	case semantic.FailureCanceled:
		return &querycodec.Failure{Category: querycodec.FailureCanceled}
	case semantic.FailureDeadlineExceeded:
		return &querycodec.Failure{Category: querycodec.FailureDeadline}
	case semantic.FailureIncompatible, semantic.FailureStaleState, semantic.FailureUnavailable:
		return &querycodec.Failure{Category: querycodec.FailureUnavailable}
	default:
		return &querycodec.Failure{Category: querycodec.FailureInternal}
	}
}

// Project only the closed limit kind and the serving peer's approved maximum.
// Error text, query contents and runtime topology never cross this boundary.
func queryLimitMessage(failure *semantic.Failure, history bool) string {
	if failure.LimitKind == semantic.LimitAdmission {
		return "Query service is at its concurrent request limit. Retry later."
	}
	if failure.Maximum == 0 {
		return "Request exceeds a supported limit"
	}
	switch failure.LimitKind {
	case semantic.LimitSemanticResponse:
		advice := "Select fewer fields or reduce the batch size using Sforce-Query-Options."
		if history {
			advice = "Select fewer fields or use a smaller SOQL LIMIT."
		}
		return fmt.Sprintf("Query response exceeds the encoded size limit of %d bytes. %s", failure.Maximum, advice)
	case semantic.LimitSemanticRequest:
		return fmt.Sprintf("Query request exceeds the encoded size limit of %d bytes. Simplify the query or use fewer filter values.", failure.Maximum)
	case semantic.LimitRecordCount:
		return fmt.Sprintf("Query exceeds the per-request limit of %d records. Request fewer records.", failure.Maximum)
	case semantic.LimitSelectedFields:
		return fmt.Sprintf("Query exceeds the limit of %d selected fields. Select fewer fields.", failure.Maximum)
	case semantic.LimitQueryPredicate:
		return fmt.Sprintf("Query exceeds the limit of %d predicate nodes. Simplify the filter.", failure.Maximum)
	case semantic.LimitQueryDepth:
		return fmt.Sprintf("Query exceeds the nesting depth limit of %d. Reduce nesting.", failure.Maximum)
	case semantic.LimitQueryOrderBy:
		return fmt.Sprintf("Query exceeds the limit of %d sort fields. Use fewer sort fields.", failure.Maximum)
	case semantic.LimitQuerySubqueries:
		return fmt.Sprintf("Query exceeds the limit of %d subqueries. Use fewer subqueries.", failure.Maximum)
	case semantic.LimitQueryOffset:
		return fmt.Sprintf("Query offset exceeds the limit of %d. Use a smaller offset.", failure.Maximum)
	default:
		return "Request exceeds a supported limit"
	}
}
