class_name EntityPresentationSnapshot
extends RefCounted

## Immutable renderer input for one session-local world entity visual.
## Gameplay authority, identity allocation and asset selection remain external.

const CONTRACT_VERSION := 1
const SCRIPT_PATH := "res://src/render/entities/entity_presentation_snapshot.gd"
const ENTITY_ID_SCRIPT := preload("res://src/domain/identity/entity_id.gd")
const GODOT_WORLD_POSITION_SCRIPT := preload("res://src/domain/coordinates/godot_world_position.gd")

var is_valid: bool:
	get:
		return _failure_code.is_empty()

var failure_code: StringName:
	get:
		return _failure_code

var entity_id: RefCounted:
	get:
		return _entity_id

var world_position: RefCounted:
	get:
		return _world_position

var visual_scene_path: String:
	get:
		return _visual_scene_path

var yaw_radians: float:
	get:
		return _yaw_radians

var uniform_scale: float:
	get:
		return _uniform_scale

var is_visible: bool:
	get:
		return _is_visible

var _failure_code: StringName
var _entity_id: RefCounted
var _world_position: RefCounted
var _visual_scene_path: String
var _yaw_radians: float
var _uniform_scale: float
var _is_visible: bool


## Creates a version-1 full visual snapshot. Invalid values remain inspectable and
## are rejected without scene mutation by the facade/presenter.
static func create(
		entity_id_value: RefCounted,
		world_position_value: RefCounted,
		visual_scene_path_value: String,
		yaw_radians_value: float = 0.0,
		uniform_scale_value: float = 1.0,
		is_visible_value: bool = true
) -> RefCounted:
	return load(SCRIPT_PATH).new(
		entity_id_value,
		world_position_value,
		visual_scene_path_value,
		yaw_radians_value,
		uniform_scale_value,
		is_visible_value
	)


func _init(
		entity_id_value: RefCounted,
		world_position_value: RefCounted,
		visual_scene_path_value: String,
		yaw_radians_value: float,
		uniform_scale_value: float,
		is_visible_value: bool
) -> void:
	_entity_id = entity_id_value
	_world_position = world_position_value
	_visual_scene_path = visual_scene_path_value.strip_edges()
	_yaw_radians = yaw_radians_value
	_uniform_scale = uniform_scale_value
	_is_visible = is_visible_value
	_failure_code = _validate()


func _validate() -> StringName:
	if _entity_id == null or _entity_id.get_script() != ENTITY_ID_SCRIPT or not bool(_entity_id.call("is_valid")):
		return &"entity_presentation_invalid_entity_id"
	if _world_position == null or _world_position.get_script() != GODOT_WORLD_POSITION_SCRIPT:
		return &"entity_presentation_invalid_world_position"
	for coordinate_name in [&"x_units", &"y_units", &"z_units"]:
		if not is_finite(float(_world_position.get(coordinate_name))):
			return &"entity_presentation_position_not_finite"
	if _visual_scene_path.is_empty():
		return &"entity_presentation_visual_path_empty"
	if not is_finite(_yaw_radians):
		return &"entity_presentation_yaw_not_finite"
	if not is_finite(_uniform_scale) or _uniform_scale <= 0.0:
		return &"entity_presentation_scale_invalid"
	return &""
