extends SceneTree

## Verifies that the pinned AzerothCore spawn is routed through the coordinate
## contract into an executable renderer checkpoint. GUI capture is performed by
## capture_render_checkpoints.gd with the validated dedicated manifest.

const COORDINATE_MAPPER_SCRIPT := preload("res://src/domain/coordinates/coordinate_mapper.gd")
const SERVER_WORLD_POSITION_SCRIPT := preload("res://src/domain/coordinates/server_world_position.gd")

const MANIFEST_PATH := "res://src/tools/server_spawn_render_manifest.json"
const EXPECTED_FIXTURE_PATH := "res://src/tests/fixtures/coordinate_golden_points.json"
const EXPECTED_SPAWN_NAME := "azerothcore_human_warrior_start"
const EXPECTED_PROFILE := "Blizzlike335"
const POSITION_TOLERANCE_YARDS := 0.002


func _initialize() -> void:
	var failures: Array[String] = []
	var manifest := _load_json_object(MANIFEST_PATH, failures)
	var fixture_path := String(manifest.get("source_fixture", ""))
	_expect_equal(fixture_path, EXPECTED_FIXTURE_PATH, "source fixture path", failures)
	var fixture := _load_json_object(fixture_path, failures) if not fixture_path.is_empty() else {}
	if manifest.is_empty() or fixture.is_empty():
		_report_and_quit(failures)
		return

	_expect_equal(int(manifest.get("schema_version", -1)), 1, "manifest schema version", failures)
	_expect_equal(String(manifest.get("profile", "")), EXPECTED_PROFILE, "renderer profile", failures)
	_expect_equal(String(manifest.get("map", "")), "Azeroth", "renderer map", failures)
	_expect_true(ResourceLoader.exists(String(manifest.get("scene", ""))), "renderer scene exists", failures)
	_expect_equal(String(manifest.get("source_spawn_name", "")), EXPECTED_SPAWN_NAME, "source spawn name", failures)

	var spawn := _find_named_dictionary(fixture.get("server_spawns", []), EXPECTED_SPAWN_NAME)
	_expect_true(not spawn.is_empty(), "pinned server spawn exists", failures)
	var checkpoints: Array = manifest.get("checkpoints", [])
	_expect_equal(checkpoints.size(), 1, "renderer checkpoint count", failures)
	if spawn.is_empty() or checkpoints.size() != 1 or not (checkpoints[0] is Dictionary):
		_report_and_quit(failures)
		return

	var checkpoint: Dictionary = checkpoints[0]
	var server_values := _three_floats(spawn.get("server_position", null), "server position", failures)
	if server_values.is_empty():
		_report_and_quit(failures)
		return
	var server_position = SERVER_WORLD_POSITION_SCRIPT.new(server_values[0], server_values[1], server_values[2])
	var canonical_position = COORDINATE_MAPPER_SCRIPT.server_to_canonical(server_position)
	var godot_position = COORDINATE_MAPPER_SCRIPT.canonical_to_godot(canonical_position)
	var tile_coordinate = COORDINATE_MAPPER_SCRIPT.canonical_to_adt_tile(canonical_position)
	var tile_local_position = COORDINATE_MAPPER_SCRIPT.canonical_to_adt_tile_local(canonical_position)
	var chunk_coordinate = COORDINATE_MAPPER_SCRIPT.adt_tile_local_to_chunk(tile_coordinate, tile_local_position)
	var mapped_position := [godot_position.x_units, godot_position.y_units, godot_position.z_units]

	_expect_equal(String(checkpoint.get("name", "")), EXPECTED_SPAWN_NAME, "checkpoint name", failures)
	_expect_true("server_spawn" in checkpoint.get("coverage", []), "server-spawn coverage", failures)
	_expect_true(bool(checkpoint.get("diagnostic_spawn_marker", false)), "diagnostic spawn marker enabled", failures)
	_expect_three_near(checkpoint.get("target", null), mapped_position, "checkpoint target", failures)
	_expect_three_near(checkpoint.get("player", null), mapped_position, "checkpoint player", failures)
	_expect_pair(checkpoint.get("expected_adt_tile", null), [tile_coordinate.tile_x, tile_coordinate.tile_y], "ADT tile", failures)
	_expect_pair(checkpoint.get("expected_adt_chunk", null), [chunk_coordinate.chunk_x, chunk_coordinate.chunk_y], "ADT chunk", failures)
	_expect_three_near(spawn.get("expected_godot_position", null), mapped_position, "fixture Godot position", failures)
	var camera_values := _three_floats(checkpoint.get("camera", null), "checkpoint camera", failures)
	if not camera_values.is_empty():
		_expect_true(camera_values[1] > godot_position.y_units, "checkpoint camera is above spawn", failures)
		_expect_true(Vector3(camera_values[0], camera_values[1], camera_values[2]).distance_to(Vector3(mapped_position[0], mapped_position[1], mapped_position[2])) > 1.0, "checkpoint camera is distinct from spawn", failures)

	if not failures.is_empty():
		_report_and_quit(failures)
		return
	print("SERVER_SPAWN_RENDERER PASS spawn=1 checkpoint=1 tile=%d_%d chunk=%d_%d profile=%s" % [
		tile_coordinate.tile_x,
		tile_coordinate.tile_y,
		chunk_coordinate.chunk_x,
		chunk_coordinate.chunk_y,
		EXPECTED_PROFILE,
	])
	quit(0)


func _find_named_dictionary(entries: Array, expected_name: String) -> Dictionary:
	for entry_variant in entries:
		if entry_variant is Dictionary and String(entry_variant.get("name", "")) == expected_name:
			return entry_variant
	return {}


func _load_json_object(path: String, failures: Array[String]) -> Dictionary:
	var file := FileAccess.open(path, FileAccess.READ)
	if file == null:
		failures.append("cannot open JSON: %s" % path)
		return {}
	var parsed = JSON.parse_string(file.get_as_text())
	if not (parsed is Dictionary):
		failures.append("JSON is not an object: %s" % path)
		return {}
	return parsed


func _three_floats(value_variant, label: String, failures: Array[String]) -> Array[float]:
	if not (value_variant is Array) or value_variant.size() != 3:
		failures.append("%s must contain three numbers" % label)
		return []
	return [float(value_variant[0]), float(value_variant[1]), float(value_variant[2])]


func _expect_three_near(actual_variant, expected_values: Array, label: String, failures: Array[String]) -> void:
	var actual_values := _three_floats(actual_variant, label, failures)
	if actual_values.is_empty() or expected_values.size() != 3:
		return
	for component_index in range(3):
		if absf(actual_values[component_index] - float(expected_values[component_index])) > POSITION_TOLERANCE_YARDS:
			failures.append("%s[%d] expected %.9f, got %.9f" % [label, component_index, expected_values[component_index], actual_values[component_index]])


func _expect_pair(actual_variant, expected_values: Array, label: String, failures: Array[String]) -> void:
	if not (actual_variant is Array) or actual_variant.size() != 2:
		failures.append("%s must contain two integers" % label)
		return
	for component_index in range(2):
		_expect_equal(int(actual_variant[component_index]), int(expected_values[component_index]), "%s[%d]" % [label, component_index], failures)


func _expect_equal(actual_value, expected_value, label: String, failures: Array[String]) -> void:
	if actual_value != expected_value:
		failures.append("%s expected %s, got %s" % [label, expected_value, actual_value])


func _expect_true(actual_value: bool, label: String, failures: Array[String]) -> void:
	if not actual_value:
		failures.append("%s expected true" % label)


func _report_and_quit(failures: Array[String]) -> void:
	if failures.is_empty():
		failures.append("verification stopped without a diagnostic")
	for failure in failures:
		push_error("SERVER_SPAWN_RENDERER: %s" % failure)
	quit(1)
