extends SceneTree

# One-off capture: the hero and the Vieux-Port monsters built by Model3DFactory
# exactly as Bridge3D builds them, seen through the game camera (35 deg tilt,
# 30 deg FOV, looking toward -Z). Writes one PNG per animation state.
const ENEMIES := ["dock_rat", "loaded_dice_crab", "powder_gull", "siren_dancer", "platform_mimic",
	"eltuna", "gab_le_crab", "barnacle_brute"]
const STATES := [["idle", 0.4], ["walk", 0.3], ["attack", 0.45], ["death", 0.999]]

var out_dir := ""

func _initialize() -> void:
	out_dir = OS.get_environment("CAPTURE_DIR")
	call_deferred("_run")

func _run() -> void:
	for _frame in range(5):
		await process_frame
	if not DataCatalog.loaded_from_master:
		DataCatalog.load_master_data()
	var stage := Node3D.new()
	root.add_child(stage)
	var environment := Environment.new()
	environment.background_mode = Environment.BG_COLOR
	environment.background_color = Color("2a2f3a")
	environment.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR
	environment.ambient_light_color = Color.WHITE
	environment.ambient_light_energy = 0.7
	var world_environment := WorldEnvironment.new()
	world_environment.environment = environment
	stage.add_child(world_environment)
	var sun := DirectionalLight3D.new()
	sun.rotation_degrees = Vector3(-55.0, 25.0, 0.0)
	sun.light_energy = 1.2
	sun.shadow_enabled = true
	stage.add_child(sun)
	var ground := MeshInstance3D.new()
	var plane := PlaneMesh.new()
	plane.size = Vector2(3000.0, 1200.0)
	ground.mesh = plane
	var ground_material := StandardMaterial3D.new()
	ground_material.albedo_color = Color("3f5260")
	ground.material_override = ground_material
	stage.add_child(ground)

	var actors: Array[Node3D] = []
	var hero_config: Dictionary = DataCatalog.active_player_config().get("model_3d", {})
	var hero := Model3DFactory.build(hero_config, 132.0)
	var cursor := -760.0
	if hero != null:
		stage.add_child(hero)
		hero.position = Vector3(cursor, 0.0, 0.0)
		_label(stage, "heros", cursor)
		cursor += 150.0
	for id: String in ENEMIES:
		var config: Dictionary = DataCatalog.ENEMIES.get(id, {}).get("model_3d", {})
		var model := Model3DFactory.build(config, 92.0)
		if model == null:
			print("CAPTURE missing model for %s" % id)
			continue
		var scale_value := float(config.get("scale", 1.0))
		var half := 50.0 * maxf(0.8, scale_value)
		cursor += half
		stage.add_child(model)
		model.position = Vector3(cursor, 0.0, 0.0)
		_label(stage, id, cursor)
		actors.append(model)
		cursor += half + 40.0

	var camera := Camera3D.new()
	camera.projection = Camera3D.PROJECTION_PERSPECTIVE
	camera.fov = 30.0
	camera.far = 8000.0
	var center := (cursor - 760.0) * 0.5 - 40.0
	var tilt := deg_to_rad(35.0)
	var reach := 1650.0
	camera.position = Vector3(center, 0.0, 0.0) + Vector3(0.0, sin(tilt), cos(tilt)) * reach
	camera.rotation_degrees = Vector3(-35.0, 0.0, 0.0)
	stage.add_child(camera)
	camera.make_current()

	for pair: Array in STATES:
		var state: String = pair[0]
		var moment: float = pair[1]
		for actor: Node3D in actors:
			Model3DFactory.show_state(actor, state, "idle", "", true)
		if hero != null:
			Model3DFactory.show_state(hero, state if state != "death" else "idle", "idle", "", true)
		for _frame in range(3):
			await process_frame
		# Deterministic pose: each clip is placed at the same fraction of its length.
		for actor: Node3D in actors:
			var player := actor.get_meta("animation_player") as AnimationPlayer
			if player != null and not player.current_animation.is_empty():
				player.seek(player.current_animation_length * moment, true)
				player.pause()
		for _frame in range(3):
			await process_frame
		await RenderingServer.frame_post_draw
		var image := root.get_viewport().get_texture().get_image()
		var path := out_dir.path_join("old_port_%s.png" % state)
		image.save_png(path)
		print("CAPTURE %s" % path)
	quit(0)

func _label(stage: Node3D, text: String, x: float) -> void:
	var label := Label3D.new()
	label.text = text
	label.font_size = 96
	label.pixel_size = 0.25
	label.billboard = BaseMaterial3D.BILLBOARD_ENABLED
	label.position = Vector3(x, 4.0, 110.0)
	label.modulate = Color("f1f5f9")
	stage.add_child(label)
