package placement

import (
	

	
	
)

// optimizerCandidateMovement reuses the candidate search's existing rollback
// snapshot as its stable movement set. Scoring only changes geometry, so every
// trial visits the same descendants in the same order. Its caller must restore
// positions if the search fails or panics, including an error midway through a
// move; it must not retain this movement set across topology changes.
type optimizerCandidateMovement struct {
	positions      []nodePositionSnapshot
	descendantWork uint64
}

func captureOptimizerCandidateMovement( *layoutgraph.Node,  *limits.OptimizationWorkGuard) (optimizerCandidateMovement, error) {
	 := .Used()
	,  := captureOptimizerNodePositions([]*layoutgraph.Node{}, )
	if  != nil {
		return optimizerCandidateMovement{}, 
	}
	// Single-root capture charges one Step for each retained position in addition
	// to the descendant walk. Retain the latter's charge so every trial preserves
	// the original work boundary and cancellation polling sequence.
	return optimizerCandidateMovement{
		positions:      ,
		descendantWork: .Used() -  - uint64(len()),
	}, nil
}

func ( optimizerCandidateMovement) (,  float64,  *limits.OptimizationWorkGuard) error {
	 := .positions[0].node
	if .TopLeft == nil {
		return fmt.Errorf("TALA %s cannot move an unpositioned node", .Location())
	}
	if .TopLeft.X ==  && .TopLeft.Y ==  {
		return .Step()
	}
	// Replay the original walk's Step calls instead of batching them: custom
	// contexts and resource failures keep the same observation boundaries.
	for range .descendantWork {
		if  := .Step();  != nil {
			return 
		}
	}
	 := .positions[1:]
	for ,  := range  {
		if  := .Step();  != nil {
			return 
		}
		if .node.TopLeft == nil {
			return fmt.Errorf("TALA %s cannot move an unpositioned descendant", .Location())
		}
	}
	,  := -.TopLeft.X, -.TopLeft.Y
	.Translate(, )
	for ,  := range  {
		if  := .Step();  != nil {
			return 
		}
		.node.Translate(, )
	}
	return nil
}