class_name StreamingTargetPolicy
extends RefCounted

## Immutable runtime tile-radius and boundary-prefetch policy consumed by
## [StreamingTargetPlanner]. Values preserve scene configuration exactly;
## effective radii and thresholds apply the existing renderer clamps.

const CHUNKS_PER_ADT_TILE := 16

var lod2_radius_chunks: int:
	get:
		return _lod2_radius_chunks

var lod2_tile_radius: int:
	get:
		return _lod2_tile_radius

var warm_tile_margin: int:
	get:
		return _warm_tile_margin

var prewarm_tile_margin: int:
	get:
		return _prewarm_tile_margin

var retain_tile_margin: int:
	get:
		return _retain_tile_margin

var boundary_prefetch_threshold: float:
	get:
		return _boundary_prefetch_threshold

var _lod2_radius_chunks: int
var _lod2_tile_radius: int
var _warm_tile_margin: int
var _prewarm_tile_margin: int
var _retain_tile_margin: int
var _boundary_prefetch_threshold: float


## Captures one renderer configuration snapshot for a deterministic plan.
func _init(
		lod2_radius_chunks_value: int,
		lod2_tile_radius_value: int,
		warm_tile_margin_value: int,
		prewarm_tile_margin_value: int,
		retain_tile_margin_value: int,
		boundary_prefetch_threshold_value: float
) -> void:
	_lod2_radius_chunks = lod2_radius_chunks_value
	_lod2_tile_radius = lod2_tile_radius_value
	_warm_tile_margin = warm_tile_margin_value
	_prewarm_tile_margin = prewarm_tile_margin_value
	_retain_tile_margin = retain_tile_margin_value
	_boundary_prefetch_threshold = boundary_prefetch_threshold_value


## Returns the current visible ADT radius derived from chunk and tile settings.
func visible_tile_radius() -> int:
	return calculate_visible_tile_radius(_lod2_radius_chunks, _lod2_tile_radius, _warm_tile_margin)


## Returns the visible radius plus the non-negative prewarm margin.
func load_tile_radius() -> int:
	return calculate_load_tile_radius(
		_lod2_radius_chunks,
		_lod2_tile_radius,
		_warm_tile_margin,
		_prewarm_tile_margin
	)


## Returns the load radius plus the non-negative hysteresis margin.
func retained_tile_radius() -> int:
	return load_tile_radius() + maxi(0, _retain_tile_margin)


## Returns the edge fraction accepted by the existing prefetch policy.
func clamped_boundary_prefetch_threshold() -> float:
	return clampf(_boundary_prefetch_threshold, 0.0, 0.49)


## Calculates the visible radius without allocating a policy. The streamer uses
## this hot-path form while finalizing tiles between planning refreshes.
static func calculate_visible_tile_radius(
		lod2_radius_chunks_value: int,
		lod2_tile_radius_value: int,
		warm_tile_margin_value: int
) -> int:
	var chunk_tile_radius := int(ceil(
		float(lod2_radius_chunks_value) / float(CHUNKS_PER_ADT_TILE)
	)) + warm_tile_margin_value
	return maxi(chunk_tile_radius, lod2_tile_radius_value)


## Calculates the load radius without allocating a policy.
static func calculate_load_tile_radius(
		lod2_radius_chunks_value: int,
		lod2_tile_radius_value: int,
		warm_tile_margin_value: int,
		prewarm_tile_margin_value: int
) -> int:
	return calculate_visible_tile_radius(
		lod2_radius_chunks_value,
		lod2_tile_radius_value,
		warm_tile_margin_value
	) + maxi(0, prewarm_tile_margin_value)
