@tool
class_name SpineDialogicPortrait
extends DialogicPortrait

#region EXPORTS

@export_group("Main")
## Path to the .tres SpineSkeletonDataResource file.
@export_file var spine_skeleton_data_file := ""

func _ready() -> void:
	$SpineSprite.animation_completed.connect(_on_animation_completed)

# Just a signal connection example
func _on_animation_completed(spine_sprite: Object, animation_state: SpineAnimationState, track_entry: SpineTrackEntry) -> void:
	print(track_entry)
	pass
	
#region DIALOGIC PORTRAIT OVERRIDES

## If the next portrait uses the same scene, reuse this instance rather than
## creating a new one (allows smooth animation transitions).
func _should_do_portrait_update(_character: DialogicCharacter, _portrait: String) -> bool:
	return true


## Called by Dialogic when the portrait is first shown or changed.
## [param passed_character] — the DialogicCharacter resource.
## [param passed_portrait] — the portrait name (e.g. "Idle", "Walk").
##
## Export overrides (like spine_skeleton_data_file) are applied by Dialogic
## *before* this method is called.
func _update_portrait(passed_character: DialogicCharacter, passed_portrait: String) -> void:
	apply_character_and_portrait(passed_character, passed_portrait)

	# Load the skeleton data file (export override from character portrait config).
	if not spine_skeleton_data_file.is_empty() and ResourceLoader.exists(spine_skeleton_data_file):
		var skel_res := load(spine_skeleton_data_file)
		if skel_res:
			$SpineSprite.skeleton_data_res = skel_res

	# Anchor the SpineSprite at the root origin. Dialogic treats the portrait
	# root's (0,0) as the bottom-center pivot. Scale is applied by the portrait
	# container, so we reset the SpineSprite's own scale to 1.
	$SpineSprite.position = Vector2.ZERO
	$SpineSprite.scale = Vector2.ONE

	# Play the animation matching the portrait name (loop on track 0).
	var anim_name := passed_portrait
	var loop := anim_name == "walk"
	$SpineSprite.get_animation_state().set_animation(anim_name, loop, 0)


## Returns the bounding rectangle of this portrait relative to the root node.
## The root node's origin (0,0) is the spine skeleton's root bone.
## Dialogic uses this rect to compute the scale/offset for the portrait.
func _get_covered_rect() -> Rect2:
	if not is_instance_valid($SpineSprite):
		return Rect2()

	# Use the skeleton's own bounds — the rect is in the skeleton's local
	# space, relative to the root bone at (0,0).
	return $SpineSprite.get_skeleton().get_bounds()


## Called by Dialogic when the character should be mirrored (e.g. facing left
## on a right-side position).
func _set_mirror(mirror: bool) -> void:
	if not is_instance_valid($SpineSprite):
		return
	# Mirror by flipping the skeleton horizontally.
	$SpineSprite.get_skeleton().set_scale_x(-1.0 if mirror else 1.0)


## Called when this character becomes the active speaker.
func _highlight() -> void:
	if not is_instance_valid($SpineSprite):
		return
	# Visual feedback: brighten slightly when speaking.
	$SpineSprite.modulate = Color(1.2, 1.2, 1.2, 1.0)


## Called when this character stops being the active speaker.
func _unhighlight() -> void:
	if not is_instance_valid($SpineSprite):
		return
	$SpineSprite.modulate = Color(1.0, 1.0, 1.0, 1.0)
