extends SceneTree
## Ragdoll throw visual test — triggers ragdoll on the matador and captures a
## frame strip so you can inspect the throw arc and settling.
##
## Run (needs a display for real screenshots):
##   godot --script tests/ragdoll_throw_test.gd
##
## Outputs: tests/output/ragdoll_throw/frame_00..09.png
## Each frame is 0.2 s apart → strip covers 2 s of flight and tumble.

const OUTPUT_DIR := "res://tests/output/ragdoll_throw"
const BULL_SPEED  := 22.0   # simulate a solid charge

const TRACKED_BONES: Array[StringName] = [&"chest", &"head", &"COG"]


func _init() -> void:
	_run.call_deferred()


func _run() -> void:
	DirAccess.make_dir_recursive_absolute(OUTPUT_DIR)

	var scene_res := load("res://scene.tscn")
	if not scene_res:
		push_error("ragdoll_throw_test: failed to load scene.tscn")
		quit(1)
		return

	var scene: Node = scene_res.instantiate()
	root.add_child(scene)

	# Let physics and AI settle
	await create_timer(0.8).timeout

	var matadors := get_nodes_in_group(&"matador")
	if matadors.is_empty():
		push_error("ragdoll_throw_test: no matadors in scene")
		quit(1)
		return

	var mat := matadors[0] as Node3D
	var spawn := mat.global_position
	print("matador spawn: %s" % spawn)

	# Throw toward +Z with a realistic charge speed
	mat.call(&"_enter_ragdoll", Vector3(0.0, 0.0, 1.0), BULL_SPEED)
	print("ragdoll triggered  bull_speed=%.1f" % BULL_SPEED)

	# Strip: 10 frames every 0.2 s
	for i: int in range(10):
		await create_timer(0.2).timeout
		var t := (i + 1) * 0.2

		var img: Image = root.get_viewport().get_texture().get_image()
		if img:
			img.save_png(OUTPUT_DIR + "/frame_%02d.png" % i)

		var sim: Node = _find_class_recursive(mat, "PhysicalBoneSimulator3D")
		var bone_info := ""
		if sim:
			for bone_name: StringName in TRACKED_BONES:
				for child: Node in sim.get_children():
					if child is PhysicalBone3D and \
							(child as PhysicalBone3D).bone_name == bone_name:
						var bp: Vector3 = (child as PhysicalBone3D).global_position
						var dist: float = bp.distance_to(spawn)
						bone_info += "  %s y=%.2f dist=%.2f" % [bone_name, bp.y, dist]

		print("t=%.1fs frame %02d%s" % [t, i, bone_info])

	print("\nStrip saved → %s" % OUTPUT_DIR)
	quit(0)


func _find_class_recursive(node: Node, class_name_str: String) -> Node:
	if node.get_class() == class_name_str:
		return node
	for child: Node in node.get_children():
		var r := _find_class_recursive(child, class_name_str)
		if r:
			return r
	return null
