package plan

import (
	"bytes"
	"encoding/json"
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/core/domain"
)

// ArtifactExpressionOp is a runtime expression instruction. The wire values
// are deliberately independent from the authoring syntax: a runtime never has
// to parse operators, function names, parentheses, or array literals again.
type ArtifactExpressionOp string

// ArtifactTypeNull is the expression-only type of a null constant. Null is
// not a declarable contract ValueType, but it is valid in equality operands.
const ArtifactTypeNull ValueType = "null"

const (
	ArtifactOpConst      ArtifactExpressionOp = "const"
	ArtifactOpLoad       ArtifactExpressionOp = "load"
	ArtifactOpArray      ArtifactExpressionOp = "array"
	ArtifactOpNot        ArtifactExpressionOp = "not"
	ArtifactOpAnd        ArtifactExpressionOp = "and"
	ArtifactOpOr         ArtifactExpressionOp = "or"
	ArtifactOpEqual      ArtifactExpressionOp = "eq"
	ArtifactOpNotEqual   ArtifactExpressionOp = "ne"
	ArtifactOpLess       ArtifactExpressionOp = "lt"
	ArtifactOpLessEqual  ArtifactExpressionOp = "le"
	ArtifactOpGreater    ArtifactExpressionOp = "gt"
	ArtifactOpGreaterEq  ArtifactExpressionOp = "ge"
	ArtifactOpIn         ArtifactExpressionOp = "in"
	ArtifactOpContains   ArtifactExpressionOp = "contains"
	ArtifactOpStartsWith ArtifactExpressionOp = "starts_with"
	ArtifactOpEndsWith   ArtifactExpressionOp = "ends_with"
	ArtifactOpLength     ArtifactExpressionOp = "length"
)

// ArtifactLoadSpace names one statically resolved runtime value space.
// ScopeOwnerID and Branch carry correlation metadata separately so neither
// the source reference nor a compiler-specific, dotted synthetic key survives
// into the artifact.
type ArtifactLoadSpace string

const (
	ArtifactLoadPlanInput        ArtifactLoadSpace = "plan_input"
	ArtifactLoadActivationInput  ArtifactLoadSpace = "activation_input"
	ArtifactLoadActivationOutput ArtifactLoadSpace = "activation_output"
	ArtifactLoadRunState         ArtifactLoadSpace = "run_state"
	ArtifactLoadLoopState        ArtifactLoadSpace = "loop_state"
	ArtifactLoadLoopIteration    ArtifactLoadSpace = "loop_iteration"
	ArtifactLoadLoopIsLast       ArtifactLoadSpace = "loop_is_last"
	ArtifactLoadJoinBranch       ArtifactLoadSpace = "join_branch"
	ArtifactLoadJoinWinnerBranch ArtifactLoadSpace = "join_winner_branch"
	ArtifactLoadJoinWinnerValue  ArtifactLoadSpace = "join_winner_value"
	ArtifactLoadFanOutItem       ArtifactLoadSpace = "fan_out_item"
	ArtifactLoadJoinItems        ArtifactLoadSpace = "join_items"
)

// ArtifactExpression is a typed, normalized expression AST. Exactly one of
// Value or Load is present for const/load respectively; Args contains operands
// in evaluation order for every other opcode. ResultType is the value type
// produced by the instruction, not the type expected by its eventual target.
type ArtifactExpression struct {
	Op         ArtifactExpressionOp `json:"op"`
	ResultType ValueType            `json:"resultType"`
	Value      ArtifactLiteral      `json:"value,omitempty"`
	Load       *ArtifactLoad        `json:"load,omitempty"`
	Args       []ArtifactExpression `json:"args,omitempty"`
}

type ArtifactLoad struct {
	Space        ArtifactLoadSpace `json:"space"`
	ScopeOwnerID string            `json:"scopeOwnerId,omitempty"`
	Branch       string            `json:"branch,omitempty"`
	Path         []string          `json:"path"`
	// Optional records that the statically resolved field may be absent. It is
	// part of the executable artifact contract.
	Optional bool `json:"optional,omitempty"`
}

// MayBeAbsent reports whether a load can produce no value. Only direct loads
// carry absence; operators such as equality always produce a present result.
func (expression ArtifactExpression) MayBeAbsent() bool {
	return expression.Op == ArtifactOpLoad && expression.Load != nil && expression.Load.MayBeAbsent()
}

// MayBeAbsent reports the compiler-declared load presence.
func (load ArtifactLoad) MayBeAbsent() bool { return load.Optional }

// ArtifactLiteral contains one already-deterministic JSON value. It marshals as
// that value rather than as a base64 byte slice, which lets the same type be
// used by const instructions and normalized contract defaults.
type ArtifactLiteral []byte

func (literal ArtifactLiteral) MarshalJSON() ([]byte, error) {
	if len(literal) == 0 {
		return nil, fmt.Errorf("artifact literal is empty")
	}
	if !json.Valid(literal) {
		return nil, fmt.Errorf("artifact literal is not valid JSON")
	}
	return append([]byte(nil), literal...), nil
}

func (literal *ArtifactLiteral) UnmarshalJSON(payload []byte) error {
	if literal == nil {
		return fmt.Errorf("artifact literal target is nil")
	}
	decoder := json.NewDecoder(bytes.NewReader(payload))
	decoder.UseNumber()
	var value any
	if err := decoder.Decode(&value); err != nil {
		return fmt.Errorf("decode artifact literal: %w", err)
	}
	normalized, err := compileArtifactLiteral(value, nil)
	if err != nil {
		return err
	}
	*literal = normalized
	return nil
}

type ArtifactTemplate struct {
	Segments []ArtifactTemplateSegment `json:"segments"`
}

type ArtifactTemplateSegmentKind string

const (
	ArtifactTemplateSegmentText ArtifactTemplateSegmentKind = "text"
	ArtifactTemplateSegmentExpr ArtifactTemplateSegmentKind = "expr"
)

// ArtifactTemplateSegment is either literal text or one compiled expression.
// Kind is explicit so runtimes do not have to infer a union case from an empty
// string or a missing pointer.
type ArtifactTemplateSegment struct {
	Kind       ArtifactTemplateSegmentKind `json:"kind"`
	Text       string                      `json:"text,omitempty"`
	Expression *ArtifactExpression         `json:"expression,omitempty"`
}

// compileArtifactValueExpr lowers a validated ref/value/expr union. expected
// is used only to preserve a literal's nominal target type and to normalize a
// duration literal to nanoseconds; it never coerces a load or computed value.
func compileArtifactValueExpr(v *validator, value ValueExpr, node *Node, references referenceContext, expected *Schema) (ArtifactExpression, error) {
	hasRef := strings.TrimSpace(value.Ref) != ""
	hasValue := value.Value != nil
	hasExpr := strings.TrimSpace(value.Expr) != ""
	present := 0
	for _, candidate := range []bool{hasRef, hasValue, hasExpr} {
		if candidate {
			present++
		}
	}
	if present != 1 {
		return ArtifactExpression{}, fmt.Errorf("artifact expression requires exactly one of ref, value, or expr")
	}

	if hasRef {
		return compileArtifactLoad(v, strings.TrimSpace(value.Ref), node, references)
	}
	if hasValue {
		literal, err := compileArtifactLiteral(*value.Value, expected)
		if err != nil {
			return ArtifactExpression{}, err
		}
		resultType, err := artifactLiteralResultType(*value.Value, expected)
		if err != nil {
			return ArtifactExpression{}, err
		}
		return ArtifactExpression{Op: ArtifactOpConst, ResultType: resultType, Value: literal}, nil
	}

	expression, err := compileArtifactExpression(v, strings.TrimSpace(value.Expr), node, references)
	if err != nil {
		return ArtifactExpression{}, err
	}
	return normalizeArtifactConstForExpected(expression, expected)
}

func compileArtifactPredicate(v *validator, predicate Predicate, node *Node, references referenceContext) (ArtifactExpression, error) {
	expression, err := compileArtifactExpression(v, strings.TrimSpace(string(predicate)), node, references)
	if err != nil {
		return ArtifactExpression{}, err
	}
	if expression.ResultType != TypeBoolean {
		return ArtifactExpression{}, fmt.Errorf("predicate result type must be boolean, got %q", expression.ResultType)
	}
	return expression, nil
}

func compileArtifactTemplate(v *validator, source string, node *Node, references referenceContext) (ArtifactTemplate, error) {
	template := ArtifactTemplate{Segments: make([]ArtifactTemplateSegment, 0)}
	stripped := templatePattern.ReplaceAllString(source, "")
	if strings.Contains(stripped, "{{") || strings.Contains(stripped, "}}") {
		return ArtifactTemplate{}, fmt.Errorf("template contains an unmatched delimiter")
	}

	position := 0
	for _, match := range templatePattern.FindAllStringSubmatchIndex(source, -1) {
		if len(match) != 4 || match[0] < position || match[2] < 0 {
			return ArtifactTemplate{}, fmt.Errorf("template contains an invalid expression segment")
		}
		appendArtifactTemplateText(&template, source[position:match[0]])
		expressionSource := strings.TrimSpace(source[match[2]:match[3]])
		if expressionSource == "" {
			return ArtifactTemplate{}, fmt.Errorf("template expression is empty")
		}
		expression, err := compileArtifactExpression(v, expressionSource, node, references)
		if err != nil {
			return ArtifactTemplate{}, fmt.Errorf("compile template expression: %w", err)
		}
		template.Segments = append(template.Segments, ArtifactTemplateSegment{
			Kind:       ArtifactTemplateSegmentExpr,
			Expression: &expression,
		})
		position = match[1]
	}
	appendArtifactTemplateText(&template, source[position:])
	return template, nil
}

func appendArtifactTemplateText(template *ArtifactTemplate, value string) {
	if template == nil || value == "" {
		return
	}
	last := len(template.Segments) - 1
	if last >= 0 && template.Segments[last].Kind == ArtifactTemplateSegmentText {
		template.Segments[last].Text += value
		return
	}
	template.Segments = append(template.Segments, ArtifactTemplateSegment{
		Kind: ArtifactTemplateSegmentText,
		Text: value,
	})
}

func compileArtifactExpression(v *validator, source string, node *Node, references referenceContext) (ArtifactExpression, error) {
	if v == nil {
		return ArtifactExpression{}, fmt.Errorf("expression validator is nil")
	}
	if source == "" {
		return ArtifactExpression{}, fmt.Errorf("expression is empty")
	}
	tokens, ok := tokenizeTypedExpression(source)
	if !ok {
		return ArtifactExpression{}, fmt.Errorf("expression tokenization failed")
	}
	parser := artifactExpressionParser{
		tokens:     tokens,
		validator:  v,
		node:       node,
		references: references,
	}
	expression, err := parser.parseOr()
	if err != nil {
		return ArtifactExpression{}, err
	}
	if parser.peek().kind != planTokenEOF {
		return ArtifactExpression{}, fmt.Errorf("expression contains trailing token %q", parser.peek().text)
	}
	return expression, nil
}

type artifactExpressionParser struct {
	tokens     []planExpressionToken
	position   int
	validator  *validator
	node       *Node
	references referenceContext
}

func (parser *artifactExpressionParser) peek() planExpressionToken {
	if parser.position >= len(parser.tokens) {
		return planExpressionToken{kind: planTokenEOF}
	}
	return parser.tokens[parser.position]
}

func (parser *artifactExpressionParser) advance() planExpressionToken {
	token := parser.peek()
	parser.position++
	return token
}

func (parser *artifactExpressionParser) parseOr() (ArtifactExpression, error) {
	left, err := parser.parseAnd()
	if err != nil {
		return ArtifactExpression{}, err
	}
	for parser.peek().kind == planTokenOr {
		parser.advance()
		right, parseErr := parser.parseAnd()
		if parseErr != nil {
			return ArtifactExpression{}, parseErr
		}
		opcode, ok := compilerAuthoringCapabilities.expressionOperator("||")
		if !ok {
			return ArtifactExpression{}, fmt.Errorf("compiler authoring catalog is missing operator ||")
		}
		left = artifactOperation(opcode, TypeBoolean, left, right)
	}
	return left, nil
}

func (parser *artifactExpressionParser) parseAnd() (ArtifactExpression, error) {
	left, err := parser.parseNot()
	if err != nil {
		return ArtifactExpression{}, err
	}
	for parser.peek().kind == planTokenAnd {
		parser.advance()
		right, parseErr := parser.parseNot()
		if parseErr != nil {
			return ArtifactExpression{}, parseErr
		}
		opcode, ok := compilerAuthoringCapabilities.expressionOperator("&&")
		if !ok {
			return ArtifactExpression{}, fmt.Errorf("compiler authoring catalog is missing operator &&")
		}
		left = artifactOperation(opcode, TypeBoolean, left, right)
	}
	return left, nil
}

func (parser *artifactExpressionParser) parseNot() (ArtifactExpression, error) {
	if parser.peek().kind == planTokenNot {
		parser.advance()
		value, err := parser.parseNot()
		if err != nil {
			return ArtifactExpression{}, err
		}
		opcode, ok := compilerAuthoringCapabilities.expressionOperator("!")
		if !ok {
			return ArtifactExpression{}, fmt.Errorf("compiler authoring catalog is missing operator !")
		}
		return artifactOperation(opcode, TypeBoolean, value), nil
	}
	return parser.parseComparison()
}

func (parser *artifactExpressionParser) parseComparison() (ArtifactExpression, error) {
	left, err := parser.parsePrimary()
	if err != nil {
		return ArtifactExpression{}, err
	}
	if parser.peek().kind == planTokenIdent && parser.peek().text == "in" {
		parser.advance()
		right, parseErr := parser.parsePrimary()
		if parseErr != nil {
			return ArtifactExpression{}, parseErr
		}
		opcode, ok := compilerAuthoringCapabilities.expressionOperator("in")
		if !ok {
			return ArtifactExpression{}, fmt.Errorf("compiler authoring catalog is missing operator in")
		}
		return artifactOperation(opcode, TypeBoolean, left, right), nil
	}
	if parser.peek().kind != planTokenOperator {
		return left, nil
	}
	operator := parser.advance().text
	right, parseErr := parser.parsePrimary()
	if parseErr != nil {
		return ArtifactExpression{}, parseErr
	}
	opcode, ok := mapArtifactComparisonOpcode(operator)
	if !ok {
		return ArtifactExpression{}, fmt.Errorf("unsupported comparison operator %q", operator)
	}
	return artifactOperation(opcode, TypeBoolean, left, right), nil
}

func mapArtifactComparisonOpcode(operator string) (ArtifactExpressionOp, bool) {
	return compilerAuthoringCapabilities.expressionOperator(operator)
}

func (parser *artifactExpressionParser) parsePrimary() (ArtifactExpression, error) {
	token := parser.peek()
	switch token.kind {
	case planTokenLeftParen:
		parser.advance()
		expression, err := parser.parseOr()
		if err != nil {
			return ArtifactExpression{}, err
		}
		if parser.peek().kind != planTokenRightParen {
			return ArtifactExpression{}, fmt.Errorf("expression is missing a closing parenthesis")
		}
		parser.advance()
		return expression, nil
	case planTokenLeftBracket:
		return parser.parseArray()
	case planTokenString:
		if !compilerAuthoringCapabilities.supportsExpressionLiteral(expressionLiteralString) {
			return ArtifactExpression{}, fmt.Errorf("compiler authoring catalog is missing string literals")
		}
		parser.advance()
		return artifactConst(token.text, TypeString, nil)
	case planTokenNumber:
		if !compilerAuthoringCapabilities.supportsExpressionLiteral(expressionLiteralNumber) {
			return ArtifactExpression{}, fmt.Errorf("compiler authoring catalog is missing number literals")
		}
		parser.advance()
		// The validation evaluator's number value is float64. Parse here as well
		// (rather than retaining the token as json.Number) so accepted spellings
		// such as "1." and precision rounding have exactly the same semantics.
		number, err := strconv.ParseFloat(token.text, 64)
		if err != nil {
			return ArtifactExpression{}, fmt.Errorf("invalid number literal %q: %w", token.text, err)
		}
		return artifactConst(number, TypeNumber, nil)
	case planTokenIdent:
		parser.advance()
		switch token.text {
		case "true":
			if !compilerAuthoringCapabilities.supportsExpressionLiteral(expressionLiteralTrue) {
				return ArtifactExpression{}, fmt.Errorf("compiler authoring catalog is missing true literals")
			}
			return artifactConst(true, TypeBoolean, nil)
		case "false":
			if !compilerAuthoringCapabilities.supportsExpressionLiteral(expressionLiteralFalse) {
				return ArtifactExpression{}, fmt.Errorf("compiler authoring catalog is missing false literals")
			}
			return artifactConst(false, TypeBoolean, nil)
		case "null":
			if !compilerAuthoringCapabilities.supportsExpressionLiteral(expressionLiteralNull) {
				return ArtifactExpression{}, fmt.Errorf("compiler authoring catalog is missing null literals")
			}
			return artifactConst(nil, ArtifactTypeNull, nil)
		}
		if parser.peek().kind == planTokenLeftParen {
			return parser.parseFunction(token.text)
		}
		return compileArtifactLoad(parser.validator, token.text, parser.node, parser.references)
	default:
		return ArtifactExpression{}, fmt.Errorf("unexpected expression token %q", token.text)
	}
}

func (parser *artifactExpressionParser) parseArray() (ArtifactExpression, error) {
	if !compilerAuthoringCapabilities.supportsExpressionLiteral(expressionLiteralArray) {
		return ArtifactExpression{}, fmt.Errorf("compiler authoring catalog is missing array literals")
	}
	parser.advance()
	elements := make([]ArtifactExpression, 0)
	if parser.peek().kind == planTokenRightBracket {
		parser.advance()
		return artifactConst([]any{}, TypeArray, nil)
	}
	for {
		element, err := parser.parseOr()
		if err != nil {
			return ArtifactExpression{}, err
		}
		elements = append(elements, element)
		switch parser.peek().kind {
		case planTokenComma:
			parser.advance()
			if parser.peek().kind == planTokenRightBracket {
				return ArtifactExpression{}, fmt.Errorf("array literal has a trailing comma")
			}
		case planTokenRightBracket:
			parser.advance()
			return foldArtifactArray(elements)
		default:
			return ArtifactExpression{}, fmt.Errorf("array literal requires a comma or closing bracket")
		}
	}
}

func (parser *artifactExpressionParser) parseFunction(name string) (ArtifactExpression, error) {
	parser.advance()
	arguments := make([]ArtifactExpression, 0)
	if parser.peek().kind != planTokenRightParen {
		for {
			argument, err := parser.parseOr()
			if err != nil {
				return ArtifactExpression{}, err
			}
			arguments = append(arguments, argument)
			if parser.peek().kind == planTokenComma {
				parser.advance()
				continue
			}
			break
		}
	}
	if parser.peek().kind != planTokenRightParen {
		return ArtifactExpression{}, fmt.Errorf("function %q is missing a closing parenthesis", name)
	}
	parser.advance()

	function, ok := compilerAuthoringCapabilities.expressionFunction(name)
	if !ok {
		return ArtifactExpression{}, fmt.Errorf("unsupported expression function %q", name)
	}
	if len(arguments) != function.Arity {
		return ArtifactExpression{}, fmt.Errorf("function %q requires %d arguments, got %d", name, function.Arity, len(arguments))
	}
	return ArtifactExpression{Op: function.Opcode, ResultType: function.ResultType, Args: arguments}, nil
}

func artifactOperation(opcode ArtifactExpressionOp, resultType ValueType, arguments ...ArtifactExpression) ArtifactExpression {
	return ArtifactExpression{Op: opcode, ResultType: resultType, Args: arguments}
}

func artifactConst(value any, resultType ValueType, expected *Schema) (ArtifactExpression, error) {
	literal, err := compileArtifactLiteral(value, expected)
	if err != nil {
		return ArtifactExpression{}, err
	}
	return ArtifactExpression{Op: ArtifactOpConst, ResultType: resultType, Value: literal}, nil
}

func foldArtifactArray(elements []ArtifactExpression) (ArtifactExpression, error) {
	values := make([]any, len(elements))
	for index := range elements {
		if elements[index].Op != ArtifactOpConst {
			if compilerAuthoringCapabilities.ArrayExpressionOp == "" {
				return ArtifactExpression{}, fmt.Errorf("compiler authoring catalog is missing array expression support")
			}
			return ArtifactExpression{
				Op:         compilerAuthoringCapabilities.ArrayExpressionOp,
				ResultType: TypeArray,
				Args:       elements,
			}, nil
		}
		value, err := decodeArtifactLiteral(elements[index].Value)
		if err != nil {
			return ArtifactExpression{}, err
		}
		values[index] = value
	}
	return artifactConst(values, TypeArray, nil)
}

func compileArtifactLoad(v *validator, reference string, node *Node, references referenceContext) (ArtifactExpression, error) {
	if v == nil {
		return ArtifactExpression{}, fmt.Errorf("expression validator is nil")
	}
	segments := strings.Split(reference, ".")
	if len(segments) == 0 || segments[0] == "" {
		return ArtifactExpression{}, fmt.Errorf("reference is empty")
	}
	switch segments[0] {
	case "input", "output":
		if node == nil {
			return ArtifactExpression{}, fmt.Errorf("reference %q requires an activation node", reference)
		}
	case "state", "plan":
		if v.document == nil {
			return ArtifactExpression{}, fmt.Errorf("reference %q requires a Plan document", reference)
		}
	case "loop":
		if node == nil || node.Type != NodeLoop || node.Loop == nil || references.loop == nil {
			return ArtifactExpression{}, fmt.Errorf("reference %q requires its loop scope owner", reference)
		}
	case "branches", "winner":
		if node == nil || node.Type != NodeJoin || node.Join == nil {
			return ArtifactExpression{}, fmt.Errorf("reference %q requires its join scope", reference)
		}
	case "item":
		if node == nil || node.Type != NodeFanOut || node.FanOut == nil || references.sourcePort != "item" {
			return ArtifactExpression{}, fmt.Errorf("reference %q requires a fan_out item edge", reference)
		}
	case "items":
		if node == nil || node.Type != NodeJoin || node.Join == nil || node.Join.FanOutID == "" || !references.joinMerge {
			return ArtifactExpression{}, fmt.Errorf("reference %q requires a fan_out join merge", reference)
		}
	}
	schema, ok := v.referenceSchema(reference, node, references)
	if !ok || schema.Type == "" {
		return ArtifactExpression{}, fmt.Errorf("reference %q is not declared in this context", reference)
	}
	load := &ArtifactLoad{Path: make([]string, 0)}
	switch segments[0] {
	case "plan":
		if len(segments) != 3 || segments[1] != "input" {
			return ArtifactExpression{}, fmt.Errorf("invalid Plan input reference %q", reference)
		}
		if err := setArtifactLoadSpace(load, referencePlanInput); err != nil {
			return ArtifactExpression{}, err
		}
		load.Path = append(load.Path, segments[2])
	case "input":
		if len(segments) != 2 {
			return ArtifactExpression{}, fmt.Errorf("invalid activation input reference %q", reference)
		}
		if err := setArtifactLoadSpace(load, referenceActivationInput); err != nil {
			return ArtifactExpression{}, err
		}
		load.Path = append(load.Path, segments[1])
	case "output":
		if len(segments) != 2 {
			return ArtifactExpression{}, fmt.Errorf("invalid activation output reference %q", reference)
		}
		if err := setArtifactLoadSpace(load, referenceActivationOutput); err != nil {
			return ArtifactExpression{}, err
		}
		load.Path = append(load.Path, segments[1])
	case "state":
		if len(segments) != 2 {
			return ArtifactExpression{}, fmt.Errorf("invalid Run state reference %q", reference)
		}
		if err := setArtifactLoadSpace(load, referenceRunState); err != nil {
			return ArtifactExpression{}, err
		}
		load.Path = append(load.Path, segments[1])
	case "loop":
		if node == nil || len(segments) != 2 && len(segments) != 3 {
			return ArtifactExpression{}, fmt.Errorf("invalid loop reference %q", reference)
		}
		load.ScopeOwnerID = node.ID
		if len(segments) == 2 {
			switch segments[1] {
			case "iteration":
				if err := setArtifactLoadSpace(load, referenceLoopIteration); err != nil {
					return ArtifactExpression{}, err
				}
			case "isLast":
				if err := setArtifactLoadSpace(load, referenceLoopIsLast); err != nil {
					return ArtifactExpression{}, err
				}
			default:
				return ArtifactExpression{}, fmt.Errorf("invalid loop reference %q", reference)
			}
			break
		}
		load.Path = append(load.Path, segments[2])
		switch segments[1] {
		case "state":
			if err := setArtifactLoadSpace(load, referenceLoopState); err != nil {
				return ArtifactExpression{}, err
			}
		default:
			return ArtifactExpression{}, fmt.Errorf("invalid loop reference %q", reference)
		}
	case "branches":
		if node == nil || node.Join == nil || len(segments) > 3 {
			return ArtifactExpression{}, fmt.Errorf("invalid join branch reference %q", reference)
		}
		if err := setArtifactLoadSpace(load, referenceJoinBranch); err != nil {
			return ArtifactExpression{}, err
		}
		load.ScopeOwnerID = node.Join.ForkID
		if len(segments) >= 2 {
			load.Branch = segments[1]
		}
		if len(segments) == 3 {
			load.Path = append(load.Path, segments[2])
		}
	case "winner":
		if node == nil || node.Join == nil || len(segments) < 2 {
			return ArtifactExpression{}, fmt.Errorf("invalid join winner reference %q", reference)
		}
		load.ScopeOwnerID = node.Join.ForkID
		switch segments[1] {
		case "branch":
			if len(segments) != 2 {
				return ArtifactExpression{}, fmt.Errorf("invalid join winner branch reference %q", reference)
			}
			if err := setArtifactLoadSpace(load, referenceJoinWinnerBranch); err != nil {
				return ArtifactExpression{}, err
			}
		case "value":
			if len(segments) > 3 {
				return ArtifactExpression{}, fmt.Errorf("invalid join winner value reference %q", reference)
			}
			if err := setArtifactLoadSpace(load, referenceJoinWinnerValue); err != nil {
				return ArtifactExpression{}, err
			}
			if len(segments) == 3 {
				load.Path = append(load.Path, segments[2])
			}
		default:
			return ArtifactExpression{}, fmt.Errorf("invalid join winner reference %q", reference)
		}
	case "item":
		if node == nil || len(segments) != 2 {
			return ArtifactExpression{}, fmt.Errorf("invalid fan_out item reference %q", reference)
		}
		if err := setArtifactLoadSpace(load, referenceFanOutItem); err != nil {
			return ArtifactExpression{}, err
		}
		load.ScopeOwnerID = node.ID
		load.Path = append(load.Path, segments[1])
	case "items":
		if node == nil || node.Join == nil || len(segments) != 1 {
			return ArtifactExpression{}, fmt.Errorf("invalid fan_out join items reference %q", reference)
		}
		if err := setArtifactLoadSpace(load, referenceJoinItems); err != nil {
			return ArtifactExpression{}, err
		}
		load.ScopeOwnerID = node.Join.FanOutID
	default:
		return ArtifactExpression{}, fmt.Errorf("unsupported reference space in %q", reference)
	}
	load.Optional = !schemaGuaranteed(schema)
	return ArtifactExpression{Op: ArtifactOpLoad, ResultType: schema.Type, Load: load}, nil
}

func setArtifactLoadSpace(load *ArtifactLoad, reference referenceSpace) error {
	if load == nil {
		return fmt.Errorf("artifact load is nil")
	}
	space, ok := compilerAuthoringCapabilities.referenceLoadSpace(reference)
	if !ok {
		return fmt.Errorf("compiler authoring catalog is missing reference space %q", reference)
	}
	load.Space = space
	return nil
}

// compileArtifactLiteral emits one deterministic JSON scalar/array/object.
// Duration literals lower to integer nanoseconds, while datetime literals
// lower to an RFC3339Nano UTC instant. Schema-aware normalization recurses
// through array items so equivalent temporal spellings remain byte-identical.
func compileArtifactLiteral(value any, expected *Schema) (ArtifactLiteral, error) {
	normalized, err := normalizeArtifactLiteralForSchema(value, expected)
	if err != nil {
		return nil, err
	}
	payload, err := json.Marshal(normalized)
	if err != nil {
		return nil, fmt.Errorf("marshal artifact literal: %w", err)
	}
	return ArtifactLiteral(payload), nil
}

func normalizeArtifactLiteralForSchema(value any, expected *Schema) (any, error) {
	if expected != nil {
		switch expected.Type {
		case TypeDuration:
			text, ok := value.(string)
			if !ok {
				return nil, fmt.Errorf("duration literal must be a string")
			}
			duration, err := parsePlanDuration(text)
			if err != nil || duration <= 0 {
				return nil, fmt.Errorf("invalid duration literal %q", text)
			}
			return artifactNormalizedNumber(strconv.FormatInt(int64(duration), 10)), nil
		case TypeDatetime:
			text, ok := value.(string)
			if !ok {
				return nil, fmt.Errorf("datetime literal must be a string")
			}
			instant, err := time.Parse(time.RFC3339, text)
			if err != nil {
				return nil, fmt.Errorf("invalid datetime literal %q", text)
			}
			return normalizeArtifactLiteral(instant.UTC().Format(time.RFC3339Nano))
		case TypeScope:
			scope, err := domain.NormalizeMessageScopeValue(value)
			if err != nil {
				return nil, fmt.Errorf("invalid message scope literal: %w", err)
			}
			return map[string]any{
				"kind":    string(scope.Kind),
				"scopeId": scope.ScopeID,
			}, nil
		case TypeArray:
			if values, ok := value.([]any); ok && expected.Items != nil {
				normalized := make([]any, len(values))
				for index, item := range values {
					compiled, err := normalizeArtifactLiteralForSchema(item, expected.Items)
					if err != nil {
						return nil, fmt.Errorf("normalize array item %d: %w", index, err)
					}
					normalized[index] = compiled
				}
				return normalized, nil
			}
		}
	}
	return normalizeArtifactLiteral(value)
}

func normalizeArtifactConstForExpected(expression ArtifactExpression, expected *Schema) (ArtifactExpression, error) {
	if expected == nil || expression.Op != ArtifactOpConst {
		return expression, nil
	}
	value, err := decodeArtifactLiteral(expression.Value)
	if err != nil {
		return ArtifactExpression{}, err
	}
	if !valueMatchesSchema(value, *expected) {
		return expression, nil
	}
	literal, err := compileArtifactLiteral(value, expected)
	if err != nil {
		return ArtifactExpression{}, err
	}
	expression.Value = literal
	expression.ResultType = expected.Type
	return expression, nil
}

func artifactLiteralResultType(value any, expected *Schema) (ValueType, error) {
	if expected != nil && valueMatchesSchema(value, *expected) {
		return expected.Type, nil
	}
	schema := inferredSchema(value)
	if schema.Type != "" {
		if schema.Type == TypeEnum {
			return TypeString, nil
		}
		return schema.Type, nil
	}
	if value == nil {
		return ArtifactTypeNull, nil
	}
	return "", fmt.Errorf("literal has unsupported type %T", value)
}

func normalizeArtifactLiteral(value any) (any, error) {
	switch typed := value.(type) {
	case nil, bool, string:
		return typed, nil
	case int:
		return normalizedArtifactNumber(strconv.FormatInt(int64(typed), 10))
	case int8:
		return normalizedArtifactNumber(strconv.FormatInt(int64(typed), 10))
	case int16:
		return normalizedArtifactNumber(strconv.FormatInt(int64(typed), 10))
	case int32:
		return normalizedArtifactNumber(strconv.FormatInt(int64(typed), 10))
	case int64:
		return normalizedArtifactNumber(strconv.FormatInt(typed, 10))
	case uint:
		return normalizedArtifactNumber(strconv.FormatUint(uint64(typed), 10))
	case uint8:
		return normalizedArtifactNumber(strconv.FormatUint(uint64(typed), 10))
	case uint16:
		return normalizedArtifactNumber(strconv.FormatUint(uint64(typed), 10))
	case uint32:
		return normalizedArtifactNumber(strconv.FormatUint(uint64(typed), 10))
	case uint64:
		return normalizedArtifactNumber(strconv.FormatUint(typed, 10))
	case float32:
		if math.IsNaN(float64(typed)) || math.IsInf(float64(typed), 0) {
			return nil, fmt.Errorf("literal contains a non-finite number")
		}
		return normalizedArtifactNumber(strconv.FormatFloat(float64(typed), 'g', -1, 32))
	case float64:
		if math.IsNaN(typed) || math.IsInf(typed, 0) {
			return nil, fmt.Errorf("literal contains a non-finite number")
		}
		return normalizedArtifactNumber(strconv.FormatFloat(typed, 'g', -1, 64))
	case json.Number:
		return normalizedArtifactNumber(string(typed))
	case map[string]any:
		normalized := make(map[string]any, len(typed))
		for key, item := range typed {
			value, err := normalizeArtifactLiteral(item)
			if err != nil {
				return nil, fmt.Errorf("normalize object field %q: %w", key, err)
			}
			normalized[key] = value
		}
		return normalized, nil
	case []any:
		normalized := make([]any, len(typed))
		for index, item := range typed {
			value, err := normalizeArtifactLiteral(item)
			if err != nil {
				return nil, fmt.Errorf("normalize array item %d: %w", index, err)
			}
			normalized[index] = value
		}
		return normalized, nil
	default:
		return nil, fmt.Errorf("literal contains unsupported value type %T", value)
	}
}

type artifactNormalizedNumber string

func (number artifactNormalizedNumber) MarshalJSON() ([]byte, error) {
	payload := []byte(number)
	if !json.Valid(payload) {
		return nil, fmt.Errorf("invalid canonical JSON number %q", number)
	}
	var decoded any
	decoder := json.NewDecoder(bytes.NewReader(payload))
	decoder.UseNumber()
	if err := decoder.Decode(&decoded); err != nil {
		return nil, err
	}
	if _, ok := decoded.(json.Number); !ok {
		return nil, fmt.Errorf("canonical value %q is not a JSON number", number)
	}
	return payload, nil
}

// normalizedArtifactNumber first resolves the number to the finite float64
// domain used by Plan expressions/runtime, then removes exponent notation,
// insignificant zeroes, and negative zero. This makes authoring spellings and
// precision rounding share exactly one runtime value and digest.
func normalizedArtifactNumber(source string) (artifactNormalizedNumber, error) {
	decoder := json.NewDecoder(strings.NewReader(source))
	decoder.UseNumber()
	var decoded any
	if err := decoder.Decode(&decoded); err != nil {
		return "", fmt.Errorf("invalid JSON number %q: %w", source, err)
	}
	if _, ok := decoded.(json.Number); !ok {
		return "", fmt.Errorf("invalid JSON number %q", source)
	}
	number, err := strconv.ParseFloat(source, 64)
	if err != nil || math.IsNaN(number) || math.IsInf(number, 0) {
		return "", fmt.Errorf("JSON number %q is outside the finite runtime number domain", source)
	}
	source = strconv.FormatFloat(number, 'g', -1, 64)

	negative := strings.HasPrefix(source, "-")
	unsigned := strings.TrimPrefix(source, "-")
	mantissa, exponentText := unsigned, ""
	if index := strings.IndexAny(unsigned, "eE"); index >= 0 {
		mantissa, exponentText = unsigned[:index], unsigned[index+1:]
	}
	exponent := 0
	if exponentText != "" {
		parsed, err := strconv.ParseInt(exponentText, 10, 32)
		if err != nil {
			return "", fmt.Errorf("JSON number exponent is out of range in %q", source)
		}
		exponent = int(parsed)
	}
	integer, fraction := mantissa, ""
	if index := strings.IndexByte(mantissa, '.'); index >= 0 {
		integer, fraction = mantissa[:index], mantissa[index+1:]
	}
	digits := integer + fraction
	decimalPosition := len(integer) + exponent
	for len(digits) > 0 && digits[0] == '0' {
		digits = digits[1:]
		decimalPosition--
	}
	if digits == "" {
		return artifactNormalizedNumber("0"), nil
	}
	for len(digits) > 1 && digits[len(digits)-1] == '0' {
		digits = digits[:len(digits)-1]
	}
	// Finite float64 formatting bounds decimalPosition to a few hundred, but
	// retain a defensive allocation guard for decoded/untrusted artifacts.
	if decimalPosition > 1024 || decimalPosition < -1024 {
		return "", fmt.Errorf("JSON number exponent is too large in %q", source)
	}

	var result string
	switch {
	case decimalPosition <= 0:
		result = "0." + strings.Repeat("0", -decimalPosition) + digits
	case decimalPosition >= len(digits):
		result = digits + strings.Repeat("0", decimalPosition-len(digits))
	default:
		result = digits[:decimalPosition] + "." + digits[decimalPosition:]
	}
	if negative {
		result = "-" + result
	}
	return artifactNormalizedNumber(result), nil
}

func decodeArtifactLiteral(literal ArtifactLiteral) (any, error) {
	if len(literal) == 0 {
		return nil, fmt.Errorf("artifact literal is empty")
	}
	decoder := json.NewDecoder(bytes.NewReader(literal))
	decoder.UseNumber()
	var value any
	if err := decoder.Decode(&value); err != nil {
		return nil, fmt.Errorf("decode artifact literal: %w", err)
	}
	return value, nil
}
