package routing

import (
	
	
	
	
	
	

	

	
	
)

const (
	// OVG construction derives a visibility graph whose size can be much larger
	// than the input graph. These limits bound the memory and CPU cost of one
	// routing attempt independently of the adapter's input limits.
	maxOVGIntersectionCandidates uint64 = 1_000_000
	maxOVGNodes                  uint64 = 200_000
	maxOVGEdges                  uint64 = 500_000
	// maxOVGWorkUnits bounds actual OVG construction and query work, including
	// index construction. Comparisons eliminated by an index or a hoisted
	// lookup do not consume CPU and must not be charged. The independent
	// candidate, node, and edge limits above still bound derived graph growth.
	maxOVGWorkUnits uint64 = 250_000_000
)

var errOVGResourceLimit = errors.New("TALA OVG resource limit exceeded")

type ovgBuildLimits struct {
	intersectionCandidates uint64
	nodes                  uint64
	edges                  uint64
	work                   uint64
}

func defaultOVGBuildLimits() ovgBuildLimits {
	return ovgBuildLimits{
		intersectionCandidates: maxOVGIntersectionCandidates,
		nodes:                  maxOVGNodes,
		edges:                  maxOVGEdges,
		work:                   maxOVGWorkUnits,
	}
}

type ovgBuildGuard struct {
	ctx  context.Context
	done <-chan struct{}
	// aggregate is shared by all OVGs and route-search flavors in one public
	// routing operation. EdgeRoutingStage also reuses this entire guard across
	// subgraphs, making its resource counters stage-wide rather than per graph.
	aggregate workBudget

	limits     ovgBuildLimits
	candidates uint64
	nodes      uint64
	edges      uint64
	work       uint64
}

func newOVGBuildGuard( context.Context,  ovgBuildLimits) (*ovgBuildGuard, error) {
	if  == nil {
		 = context.Background()
	}
	 := &ovgBuildGuard{ctx: , done: .Done(), aggregate: routeAggregateWorkFromContext(), limits: }
	if  := .check();  != nil {
		return nil, 
	}
	return , nil
}

func ( *ovgBuildGuard) () error {
	if  := cachedContextErr(.ctx, .done);  != nil {
		return fmt.Errorf("EdgeRouting: %w", )
	}
	return nil
}

func ovgResourceOverflow( string) error {
	return fmt.Errorf("%w: %s arithmetic overflow", errOVGResourceLimit, )
}

func ovgResourceExceeded( string, ,  uint64) error {
	return fmt.Errorf("%w: %s %d exceeds limit %d", errOVGResourceLimit, , , )
}

func ( *ovgBuildGuard) ( string,  *uint64, ,  uint64) error {
	if  := .check();  != nil {
		return 
	}
	,  := limits.CheckedAddUint64(*, )
	if ! {
		return ovgResourceOverflow()
	}
	if  >  {
		return ovgResourceExceeded(, , )
	}
	* = 
	return nil
}

func ( *ovgBuildGuard) ( uint64) error {
	return .reserve("intersection candidate count", &.candidates, , .limits.intersectionCandidates)
}

func ( *ovgBuildGuard) ( uint64) error {
	return .reserve("node count", &.nodes, , .limits.nodes)
}

func ( *ovgBuildGuard) ( uint64) error {
	return .reserve("edge count", &.edges, , .limits.edges)
}

func ( *ovgBuildGuard) ( uint64) error {
	,  := limits.CheckedAddUint64(.work, )
	if ! {
		if  := .check();  != nil {
			return 
		}
		return ovgResourceOverflow("work units")
	}
	if  > .limits.work {
		if  := .check();  != nil {
			return 
		}
		return ovgResourceExceeded("work units", , .limits.work)
	}
	// Synthetic contexts without Done retain per-operation Err polling. Standard
	// contexts poll at a bounded stride, avoiding a channel select in every inner
	// OVG scan while still checking before any resource-limit result.
	if .done == nil ||  == 0 ||
		.work/routeStageContextCheckStride != /routeStageContextCheckStride {
		if  := .check();  != nil {
			return 
		}
	}
	.work = 
	if .aggregate != nil {
		return .aggregate.add()
	}
	return nil
}

func ( *ovgBuildGuard) () error {
	return .reserveWork(1)
}

func ( *ovgBuildGuard) ( int) error {
	if  < 2 {
		return .check()
	}
	 := uint64(0)
	for  := uint64( - 1);  > 0;  >>= 1 {
		++
	}
	,  := limits.CheckedMulUint64(uint64(), )
	if ! {
		return ovgResourceOverflow("sort work units")
	}
	return .reserveWork()
}

func checkedOVGIntersectionCount(,  int) (uint64, error) {
	,  := limits.CheckedMulUint64(uint64(), uint64())
	if ! {
		return 0, ovgResourceOverflow("intersection candidate count")
	}
	return , nil
}

func checkedUint64ToInt(,  uint64) (int, error) {
	if  >  {
		return 0, ovgResourceExceeded("allocation capacity", , )
	}
	return int(), nil
}

func checkedOVGSliceCapacity( ...int) (int, error) {
	 := uint64(0)
	for ,  := range  {
		,  := limits.CheckedAddUint64(, uint64())
		if ! {
			return 0, ovgResourceOverflow("allocation capacity")
		}
		 = 
	}
	return checkedUint64ToInt(, maxIntAsUint64())
}

func maxIntAsUint64() uint64 {
	return uint64(^uint(0) >> 1)
}

// checkedOVGEdgeCapacity computes the exact sweep upper bound used for slice
// preallocation. Every eligible node appears in one horizontal and one vertical
// line, so the sweeps can add at most (n-h)+(n-v) edges. This avoids the old
// dense-grid h*v estimate, which could overflow and badly overallocate sparse
// visibility graphs.
func checkedOVGEdgeCapacity(, , ,  uint64, ,  uint64) (int, error) {
	if  >  {
		return 0, ovgResourceExceeded("edge count", , )
	}

	,  := limits.CheckedMulUint64(, 2)
	if ! {
		return 0, ovgResourceOverflow("edge capacity")
	}
	,  := limits.CheckedAddUint64(, )
	if ! ||  <  {
		return 0, ovgResourceOverflow("edge capacity")
	}
	 :=  - 
	,  := limits.CheckedAddUint64(, )
	if ! {
		return 0, ovgResourceOverflow("edge capacity")
	}
	if  >  {
		 = 
	}
	return checkedUint64ToInt(, )
}

func ( *ovgBuildGuard) ( *OVG,  *OVGNode) (*OVGNode, error) {
	if  := .step();  != nil {
		return nil, 
	}
	if ,  := .OccupiedPoints[*.Point];  {
		return , nil
	}
	if  := .reserveNodes(1);  != nil {
		return nil, 
	}
	.AddNodeUnchecked()
	return , nil
}

func ( *ovgBuildGuard) ( *OVG,  *geo.Point) (*OVGNode, error) {
	if  := .step();  != nil {
		return nil, 
	}
	if ,  := .OccupiedPoints[*];  {
		return , nil
	}
	if  := .reserveNodes(1);  != nil {
		return nil, 
	}
	 := NewOVGNode()
	.AddNodeUnchecked()
	return , nil
}

// newDerivedNode accounts for a temporary OVG node before allocating it. The
// node may later also consume a slot in one or more OVGs; those memberships are
// deliberately counted separately by addNode.
func ( *ovgBuildGuard) ( *geo.Point) (*OVGNode, error) {
	if  := .step();  != nil {
		return nil, 
	}
	if  := .reserveNodes(1);  != nil {
		return nil, 
	}
	return NewOVGNode(), nil
}

func ( *ovgBuildGuard) ( *geo.Point) (*OVGNode, error) {
	if  := .step();  != nil {
		return nil, 
	}
	return NewOVGNode(), nil
}

func ( *ovgBuildGuard) ( *OVG,  *OVGNode) error {
	if  := .step();  != nil {
		return 
	}
	if  := .reserveNodes(1);  != nil {
		return 
	}
	.AddNodeUnchecked()
	return nil
}

func ( *ovgBuildGuard) ( *OVG, ,  *OVGNode) (*OVGEdge, error) {
	if  := .step();  != nil {
		return nil, 
	}
	if .IsNodeCenter && !.isPort() || .IsNodeCenter && !.isPort() {
		return nil, nil
	}
	if  := .reserveEdges(1);  != nil {
		return nil, 
	}
	return .Connect(, ), nil
}

func ( *ovgBuildGuard) ( *layoutgraph.Graph,  *geo.Point) (bool, error) {
	for ,  := range .Nodes {
		if  := .step();  != nil {
			return false, 
		}
		// It is valid for visibility nodes to lie on container boundaries.
		if .IsContainer() {
			continue
		}
		if .IsPointNear() {
			return true, nil
		}
	}
	return false, nil
}

// ovgPointProximityIndex is a build-local broad phase for the Cartesian
// intersection grid. Candidate X coordinates are known in advance, so each
// coordinate keeps graph nodes whose expanded box can contain a candidate.
// Nodes stay in graph order and the exact isPointNear predicate remains the
// final test.
type ovgPointProximityIndex struct {
	byX map[float64][]*layoutgraph.Node
}

func newOVGPointProximityIndex( *layoutgraph.Graph,  []float64,  *ovgBuildGuard) (*ovgPointProximityIndex, error) {
	 := &ovgPointProximityIndex{
		byX: make(map[float64][]*layoutgraph.Node, len()),
	}
	for ,  := range  {
		if  := .step();  != nil {
			return nil, 
		}
		for ,  := range .Nodes {
			if  := .step();  != nil {
				return nil, 
			}
			if .IsContainer() {
				continue
			}
			if .TopLeft.X-layoutgraph.MinRouteNodeClearance <=  &&
				.TopLeft.X+.Width+layoutgraph.MinRouteNodeClearance >=  {
				.byX[] = append(.byX[], )
			}
		}
	}
	return , .check()
}

func ( *ovgPointProximityIndex) (,  float64,  *ovgBuildGuard) (bool, error) {
	if  := .step();  != nil {
		return false, 
	}
	 := geo.Point{X: , Y: }
	for ,  := range .byX[] {
		if  := .step();  != nil {
			return false, 
		}
		if .IsPointNear(&) {
			return true, nil
		}
	}
	return false, nil
}

func ( *ovgBuildGuard) ( layoutgraph.Nodes) (*geo.Point, *geo.Point, error) {
	if len() == 0 {
		return geo.NewPoint(math.Inf(-1), math.Inf(-1)), geo.NewPoint(math.Inf(1), math.Inf(1)), .check()
	}
	if [0].TopLeft == nil {
		return nil, nil, .check()
	}

	 := [0].TopLeft.X
	 := [0].TopLeft.Y
	 := [0].TopLeft.X + [0].Width
	 := [0].TopLeft.Y + [0].Height
	for ,  := range  {
		if  := .step();  != nil {
			return nil, nil, 
		}
		if .TopLeft == nil {
			return nil, nil, nil
		}
		 = math.Min(, .TopLeft.X)
		 = math.Min(, .TopLeft.Y)
		 = math.Max(, .TopLeft.X+.Width)
		 = math.Max(, .TopLeft.Y+.Height)
	}
	return geo.NewPoint(, ), geo.NewPoint(, ), .check()
}

func ( *ovgBuildGuard) ( *OVG) (*geo.Point, *geo.Point, error) {
	if len(.Nodes) == 0 {
		return geo.NewPoint(math.Inf(-1), math.Inf(-1)), geo.NewPoint(math.Inf(1), math.Inf(1)), .check()
	}
	 := .Nodes[0].X
	 := .Nodes[0].Y
	 := .Nodes[0].X
	 := .Nodes[0].Y
	for ,  := range .Nodes {
		if  := .step();  != nil {
			return nil, nil, 
		}
		 = math.Min(, .X)
		 = math.Min(, .Y)
		 = math.Max(, .X)
		 = math.Max(, .Y)
	}
	return geo.NewPoint(, ), geo.NewPoint(, ), .check()
}

func ( *ovgBuildGuard) ( *OVG,  *layoutgraph.Node,  geo.Orientation) ([]*OVGNode, error) {
	 := make([]*OVGNode, 0, len(.Ports[]))
	 := make(map[*OVGNode]struct{}, len(.Ports[]))
	for ,  := range .Ports[] {
		if  := .step();  != nil {
			return nil, 
		}
		if ,  := [];  {
			continue
		}
		[] = struct{}{}
		if .hasPortDirection(, ) {
			 = append(, )
		}
	}
	return , .check()
}

func ( *ovgBuildGuard) ( *layoutgraph.Node, ,  *geo.Point,  geo.Orientation,  []*OVGNode) (bool, error) {
	if len() == 0 {
		return .PassesThrough(, ), .check()
	}
	// A port can exempt a segment only when it points outwards in the supplied
	// direction. Most visibility nodes have no port owner (NONE), so do this
	// invariant direction check before scanning a shape's complete port list.
	 := false
	switch  {
	case geo.Top:
		 = .X == .X && .Y > .Y
	case geo.Bottom:
		 = .X == .X && .Y < .Y
	case geo.Left:
		 = .Y == .Y && .X > .X
	case geo.Right:
		 = .Y == .Y && .X < .X
	}
	if  {
		for ,  := range  {
			if  := .step();  != nil {
				return false, 
			}
			if nonNilEquals(.Point, ) || nonNilEquals(.Point, ) {
				return false, nil
			}
		}
	}
	return .PassesThrough(, ), .check()
}

func ( *ovgBuildGuard) (,  *layoutgraph.Node) (bool, error) {
	for  := ; ; {
		if  := .step();  != nil {
			return false, 
		}
		if  ==  {
			return true, nil
		}
		if  == nil {
			return false, nil
		}
		switch {
		case .Container != nil:
			 = .Container
		case .Cluster != nil:
			 = .Cluster.Vessel
		case .Sequence != nil:
			 = .Sequence.Vessel
		default:
			return  == nil, nil
		}
	}
}

func ( *ovgBuildGuard) ( *layoutgraph.Node) (bool, error) {
	for  := ;  != nil;  = .OwningContainer() {
		if  := .step();  != nil {
			return false, 
		}
		if .FixedTopLeft != nil {
			return true, nil
		}
	}
	return false, nil
}

func ( *ovgBuildGuard) (,  layoutgraph.Nodes) (bool, error) {
	if len() != len() {
		return false, .check()
	}
	for  := range  {
		if  := .step();  != nil {
			return false, 
		}
		if [] != [] {
			return false, nil
		}
	}
	return true, .check()
}

func ( *ovgBuildGuard) ( *OVGNode) (bool, error) {
	 := .portOwners()
	if len() == 0 {
		return false, .check()
	}
	for ,  := range  {
		if  := .step();  != nil {
			return false, 
		}
		if .Sequence == nil {
			return false, nil
		}
		if .directions.any(func( geo.Orientation) bool {
			switch  {
			case geo.Left:
				return .Sequence.First() == 
			case geo.Right:
				return .Sequence.Last() == 
			default:
				return true
			}
		}) {
			return false, nil
		}
	}
	return true, .check()
}

func ( *ovgBuildGuard) ( *layoutgraph.Graph,  *layoutgraph.Node) ([]*layoutgraph.Node, error) {
	var  []*layoutgraph.Node
	if  != nil && !.IsContainer() {
		return , .check()
	}
	 := .Containers[]
	for ,  := range slices.Backward() {
		if  := .step();  != nil {
			return nil, 
		}

		if .IsContainer() {
			,  := .(, )
			if  != nil {
				return nil, 
			}
			 = append(, ...)
			 = append(, )
			continue
		}
		if .IsClusterVessel() {
			 := .Clusters[]
			for ,  := range slices.Backward(.Nodes) {
				if  := .step();  != nil {
					return nil, 
				}

				if !.IsContainer() {
					continue
				}
				,  := .(, )
				if  != nil {
					return nil, 
				}
				 = append(, ...)
				 = append(, )
			}
		}
	}
	return , .check()
}

// reserveHierarchyTransform accounts for a complete, non-interruptible
// coordinate transform before it mutates graph or OVG state. Preflighting the
// whole transform lets the existing inverse defers remain infallible.
func ( *ovgBuildGuard) ( *OVG,  int) error {
	if  := .reserveWork(uint64());  != nil {
		return 
	}
	for ,  := range .Nodes {
		if  := .step();  != nil { // preflight scan
			return 
		}
		if  := .reserveWork(2);  != nil { // point transform and reindex
			return 
		}
		for range .portOwners() {
			if  := .step();  != nil { // preflight scan
				return 
			}
			if  := .reserveWork(1);  != nil { // direction transform
				return 
			}
		}
	}
	return .check()
}

func ( *OVG) ( *layoutgraph.Graph,  layoutgraph.Nodes,  *ovgBuildGuard) (map[*layoutgraph.Node]struct{}, error) {
	.fixedOverlapsMu.Lock()
	defer .fixedOverlapsMu.Unlock()

	for ,  := range .fixedOverlapsCache {
		if  := .step();  != nil {
			return nil, 
		}
		,  := .sameNodes(.nodes, )
		if  != nil {
			return nil, 
		}
		if .graph ==  &&  {
			return .overlaps, nil
		}
	}

	 := make([]*layoutgraph.Node, 0, len()/4)
	for ,  := range  {
		if  := .step();  != nil {
			return nil, 
		}
		,  := .hasFixedAncestor()
		if  != nil {
			return nil, 
		}
		if  {
			 = append(, )
		}
	}

	 := make(map[*layoutgraph.Node]struct{})
	for ,  := range  {
		if ,  := [];  {
			continue
		}
		for ,  := range  {
			if  := .step();  != nil {
				return nil, 
			}
			,  := .isDescendantOf(, )
			if  != nil {
				return nil, 
			}
			,  := .isDescendantOf(, )
			if  != nil {
				return nil, 
			}
			if  ==  ||  ||  {
				continue
			}
			if .Overlaps(.Box) {
				[] = struct{}{}
				,  := .hasFixedAncestor()
				if  != nil {
					return nil, 
				}
				if  {
					[] = struct{}{}
				}
				break
			}
		}
	}

	.fixedOverlapsCache = append(.fixedOverlapsCache, fixedOverlapsCacheEntry{
		graph:    ,
		nodes:    append(layoutgraph.Nodes(nil), ...),
		overlaps: ,
	})
	return , nil
}

type ovgPortIndex struct {
	xByY               map[float64][]float64
	yByX               map[float64][]float64
	owners             []*layoutgraph.Node
	ownersByX          map[float64][]int
	ownersByY          map[float64][]int
	verticalBlockers   map[float64][]*layoutgraph.Node
	horizontalBlockers map[float64][]*layoutgraph.Node
}

func newOVGPortIndex( map[*layoutgraph.Node][]*OVGNode,  *layoutgraph.Graph,  map[*layoutgraph.Node]struct{},  *ovgBuildGuard) (*ovgPortIndex, error) {
	 := &ovgPortIndex{
		xByY:               make(map[float64][]float64),
		yByX:               make(map[float64][]float64),
		owners:             make([]*layoutgraph.Node, 0, len()),
		ownersByX:          make(map[float64][]int),
		ownersByY:          make(map[float64][]int),
		verticalBlockers:   make(map[float64][]*layoutgraph.Node),
		horizontalBlockers: make(map[float64][]*layoutgraph.Node),
	}
	for ,  := range  {
		if  := .step();  != nil {
			return nil, 
		}
		 := len(.owners)
		.owners = append(.owners, )
		for ,  := range  {
			if  := .step();  != nil {
				return nil, 
			}
			.xByY[.Y] = append(.xByY[.Y], .X)
			.yByX[.X] = append(.yByX[.X], .Y)
			.ownersByX[.X] = append(.ownersByX[.X], )
			.ownersByY[.Y] = append(.ownersByY[.Y], )
		}
	}
	for ,  := range .xByY {
		if  := .reserveSortWork(len());  != nil {
			return nil, 
		}
		sort.Float64s()
	}
	for ,  := range .yByX {
		if  := .reserveSortWork(len());  != nil {
			return nil, 
		}
		sort.Float64s()
	}

	// A port-to-candidate segment is axis aligned. Precompute the graph-order
	// blockers that can intersect each port axis, then retain passesThrough as
	// the exact segment predicate at query time.
	if  != nil {
		for  := range .ownersByX {
			if  := .step();  != nil {
				return nil, 
			}
			for ,  := range .Nodes {
				if  := .step();  != nil {
					return nil, 
				}
				if  == nil || .TopLeft == nil || .IsContainer() {
					continue
				}
				if ,  := [];  {
					continue
				}
				 := math.Min(.TopLeft.X, .TopLeft.X+.Width)
				 := math.Max(.TopLeft.X, .TopLeft.X+.Width)
				if  <=  &&  <=  {
					.verticalBlockers[] = append(.verticalBlockers[], )
				}
			}
		}
		for  := range .ownersByY {
			if  := .step();  != nil {
				return nil, 
			}
			for ,  := range .Nodes {
				if  := .step();  != nil {
					return nil, 
				}
				if  == nil || .TopLeft == nil || .IsContainer() {
					continue
				}
				if ,  := [];  {
					continue
				}
				 := math.Min(.TopLeft.Y, .TopLeft.Y+.Height)
				 := math.Max(.TopLeft.Y, .TopLeft.Y+.Height)
				if  <=  &&  <=  {
					.horizontalBlockers[] = append(.horizontalBlockers[], )
				}
			}
		}
	}
	return , nil
}

// Owner indexes are appended in ascending order during index construction.
// Merge the two axis lists so a query visits only aligned owners, once each,
// in the same order as a full owners scan. Duplicate ports and owners aligned
// on both axes do not count as distinct unobstructed graph nodes.
func ( *ovgPortIndex) (,  float64) ovgAlignedOwners {
	return ovgAlignedOwners{byX: .ownersByX[], byY: .ownersByY[]}
}

type ovgAlignedOwners struct {
	byX, byY []int
}

func ( *ovgAlignedOwners) ( *ovgBuildGuard) (int, bool, error) {
	if  := .step();  != nil {
		return 0, false, 
	}
	if len(.byX) == 0 && len(.byY) == 0 {
		return 0, false, nil
	}
	var  int
	if len(.byY) == 0 || len(.byX) > 0 && .byX[0] < .byY[0] {
		 = .byX[0]
	} else {
		 = .byY[0]
	}
	for len(.byX) > 0 && .byX[0] ==  {
		if  := .step();  != nil {
			return 0, false, 
		}
		.byX = .byX[1:]
	}
	for len(.byY) > 0 && .byY[0] ==  {
		if  := .step();  != nil {
			return 0, false, 
		}
		.byY = .byY[1:]
	}
	return , true, nil
}

func ( *ovgBuildGuard) ( []float64, ,  float64) (bool, error) {
	,  := 0, len()
	 :=  - 
	for  <  {
		if  := .step();  != nil {
			return false, 
		}
		 := int(uint(+) >> 1)
		if [] <  {
			 =  + 1
		} else {
			 = 
		}
	}
	return  < len() && [] <= +, .check()
}

func ( *ovgPortIndex) (, ,  float64,  *ovgBuildGuard) (bool, error) {
	,  := .hasCoordinateWithin(.xByY[], , )
	if  != nil ||  {
		return , 
	}
	return .hasCoordinateWithin(.yByX[], , )
}