package d2ir

import (
	

	
)

// DefaultMaxEdgeExpansion is the maximum number of distinct edge-segment and
// endpoint combinations that edge globs may consider during one compilation.
// Explicit edges do not consume this budget because their work is proportional
// to the input size. The limit is calibrated so a sparse star at the boundary
// remains bounded in the built-in Dagre and ELK layouts, while larger wildcard
// fanout stops before layout.
const DefaultMaxEdgeExpansion int64 = 1_024

// DefaultMaxEdgeExpansionWork is the maximum number of endpoint-pair
// examinations edge globs may perform, including repeated lazy replays.
const DefaultMaxEdgeExpansionWork int64 = 65_536

type edgeExpansionPair struct {
	glob     *globContext
	segment  *d2ast.Edge
	src      *Field
	dst      *Field
	selector bool
}

type edgeExpansionBudget struct {
	limit int64
	used  int64
}

type edgeExpansionLimitError struct {
	limit int64
}

type edgeExpansionWorkBudget struct {
	limit int64
	used  int64
}

type edgeExpansionWorkLimitError struct {
	limit int64
}

func ( *edgeExpansionWorkLimitError) () string {
	return fmt.Sprintf("edge glob expansion exceeds work limit of %d endpoint-pair examinations", .limit)
}

func ( *edgeExpansionLimitError) () string {
	return fmt.Sprintf("edge glob expansion exceeds limit of %d endpoint pairs", .limit)
}

func newEdgeExpansionBudget( int64) (*edgeExpansionBudget, error) {
	if  < 0 {
		return nil, fmt.Errorf("MaxEdgeExpansion must not be negative")
	}
	if  == 0 {
		 = DefaultMaxEdgeExpansion
	}
	return &edgeExpansionBudget{limit: }, nil
}

func newEdgeExpansionWorkBudget( int64) (*edgeExpansionWorkBudget, error) {
	if  < 0 {
		return nil, fmt.Errorf("MaxEdgeExpansionWork must not be negative")
	}
	if  == 0 {
		 = DefaultMaxEdgeExpansionWork
	}
	return &edgeExpansionWorkBudget{limit: }, nil
}

func ( *edgeExpansionBudget) () error {
	if  == nil || .used >= .limit {
		 := int64(0)
		if  != nil {
			 = .limit
		}
		return &edgeExpansionLimitError{limit: }
	}
	.used++
	return nil
}

func ( *edgeExpansionWorkBudget) () error {
	if  == nil || .used >= .limit {
		 := int64(0)
		if  != nil {
			 = .limit
		}
		return &edgeExpansionWorkLimitError{limit: }
	}
	.used++
	return nil
}

func ( *compiler) ( *d2ast.Edge,  *globContext, ,  *Field,  bool) bool {
	if .stopped() {
		return false
	}
	if  := .edgeExpansionWork.reserve();  != nil {
		return .rejectEdgeExpansion(, )
	}
	 := edgeExpansionPair{glob: , segment: , src: , dst: , selector: }
	if ,  := .edgeExpansionPairs[];  {
		return true
	}
	if  := .edgeExpansion.reserve();  != nil {
		return .rejectEdgeExpansion(, )
	}
	if .edgeExpansionPairs == nil {
		.edgeExpansionPairs = make(map[edgeExpansionPair]struct{})
	}
	.edgeExpansionPairs[] = struct{}{}
	return true
}

func ( *compiler) ( d2ast.Node,  error) bool {
	.expansionErr = 
	if  != nil {
		.errorf(, "%v", )
	}
	.halted = true
	return false
}