# Animation operations module
# Handles: create_animation, add_animation_track, set_animation_keyframe, get_animation_info, list_animations
# Corresponds to: test_animation.py
class_name AnimationOps


## Create a new animation resource in a scene
## @param ctx: SceneTree - The main script context (provides debug_mode, utility functions)
## @param params: Dictionary - Parameters from Python:
##   - scene_path: String - Path to the scene file
##   - animation_name: String - Name of the animation
##   - duration: float - Duration in seconds
##   - loop: bool - Whether to loop
static func create_animation(ctx: SceneTree, params: Dictionary) -> void:
	ctx.log_info("Creating animation: " + params.animation_name)

	# Normalize scene path
	var full_scene_path: String = params.scene_path
	if not full_scene_path.begins_with("res://"):
		full_scene_path = "res://" + full_scene_path

	if ctx.debug_mode:
		print("[DEBUG] Scene path: " + full_scene_path)

	# Check if scene exists
	if not FileAccess.file_exists(full_scene_path):
		ctx.log_error("Scene file does not exist: " + full_scene_path)
		ctx.quit(1)

	# Load scene
	var scene: PackedScene = load(full_scene_path)
	if not scene:
		ctx.log_error("Failed to load scene: " + full_scene_path)
		ctx.quit(1)

	var scene_root: Node = scene.instantiate()
	if ctx.debug_mode:
		print("[DEBUG] Scene loaded successfully")

	# Create Animation resource
	var animation: Animation = Animation.new()
	animation.length = params.get("duration", 1.0)
	animation.loop_mode = Animation.LOOP_LINEAR if params.get("loop", false) else Animation.LOOP_NONE

	if ctx.debug_mode:
		print("[DEBUG] Animation created with duration: " + str(animation.length))

	# Find or create AnimationPlayer
	var anim_player: AnimationPlayer = scene_root.get_node_or_null("AnimationPlayer")
	if not anim_player:
		anim_player = AnimationPlayer.new()
		anim_player.name = "AnimationPlayer"
		scene_root.add_child(anim_player)
		anim_player.owner = scene_root
		if ctx.debug_mode:
			print("[DEBUG] Created new AnimationPlayer")

	# Get or create AnimationLibrary (Godot 4.x)
	var lib: AnimationLibrary = null
	if anim_player.has_animation_library(""):
		lib = anim_player.get_animation_library("")
	else:
		lib = AnimationLibrary.new()
		anim_player.add_animation_library("", lib)
		if ctx.debug_mode:
			print("[DEBUG] Created new AnimationLibrary")

	# Add animation to library
	if lib.has_animation(params.animation_name):
		ctx.log_error("Animation already exists: " + params.animation_name)
		ctx.quit(1)

	lib.add_animation(params.animation_name, animation)
	if ctx.debug_mode:
		print("[DEBUG] Animation added to library")

	# Save scene
	var packed_scene: PackedScene = PackedScene.new()
	var result: int = packed_scene.pack(scene_root)

	if result == OK:
		var save_error: int = ResourceSaver.save(packed_scene, full_scene_path)
		if save_error == OK:
			print("Animation '" + params.animation_name + "' created successfully")
		else:
			ctx.log_error("Failed to save scene: " + str(save_error))
			ctx.quit(1)
	else:
		ctx.log_error("Failed to pack scene: " + str(result))
		ctx.quit(1)


## Add a track to an existing animation
static func add_animation_track(ctx: SceneTree, params: Dictionary) -> void:
	ctx.log_info("Adding track to animation: " + params.animation_name)

	var full_scene_path: String = params.scene_path
	if not full_scene_path.begins_with("res://"):
		full_scene_path = "res://" + full_scene_path

	if not FileAccess.file_exists(full_scene_path):
		ctx.log_error("Scene file does not exist: " + full_scene_path)
		ctx.quit(1)

	var scene: PackedScene = load(full_scene_path)
	if not scene:
		ctx.log_error("Failed to load scene: " + full_scene_path)
		ctx.quit(1)

	var scene_root: Node = scene.instantiate()

	# Find AnimationPlayer
	var anim_player: AnimationPlayer = scene_root.get_node_or_null("AnimationPlayer")
	if not anim_player:
		ctx.log_error("AnimationPlayer not found in scene")
		ctx.quit(1)

	# Get animation
	var lib: AnimationLibrary = anim_player.get_animation_library("")
	if not lib or not lib.has_animation(params.animation_name):
		ctx.log_error("Animation not found: " + params.animation_name)
		ctx.quit(1)

	var animation: Animation = lib.get_animation(params.animation_name)

	# Map track type string to enum
	var track_type_value: int
	match params.track_type:
		"value":
			track_type_value = Animation.TYPE_VALUE
		"method":
			track_type_value = Animation.TYPE_METHOD
		"bezier":
			track_type_value = Animation.TYPE_BEZIER
		"audio":
			track_type_value = Animation.TYPE_AUDIO
		"animation":
			track_type_value = Animation.TYPE_ANIMATION
		_:
			ctx.log_error("Invalid track type: " + params.track_type)
			ctx.quit(1)

	# Add track
	var track_idx: int = animation.add_track(track_type_value)
	animation.track_set_path(track_idx, NodePath(params.track_path))

	if ctx.debug_mode:
		print("[DEBUG] Track added at index: " + str(track_idx))

	# Save scene
	var packed_scene: PackedScene = PackedScene.new()
	var result: int = packed_scene.pack(scene_root)

	if result == OK:
		var save_error: int = ResourceSaver.save(packed_scene, full_scene_path)
		if save_error == OK:
			print("Track '" + params.track_path + "' added to animation '" + params.animation_name + "'")
		else:
			ctx.log_error("Failed to save scene: " + str(save_error))
			ctx.quit(1)
	else:
		ctx.log_error("Failed to pack scene: " + str(result))
		ctx.quit(1)


## Set a keyframe in an animation track
static func set_animation_keyframe(ctx: SceneTree, params: Dictionary) -> void:
	ctx.log_info("Setting keyframe in animation: " + params.animation_name)

	var full_scene_path: String = params.scene_path
	if not full_scene_path.begins_with("res://"):
		full_scene_path = "res://" + full_scene_path

	if not FileAccess.file_exists(full_scene_path):
		ctx.log_error("Scene file does not exist: " + full_scene_path)
		ctx.quit(1)

	var scene: PackedScene = load(full_scene_path)
	if not scene:
		ctx.log_error("Failed to load scene: " + full_scene_path)
		ctx.quit(1)

	var scene_root: Node = scene.instantiate()

	# Find AnimationPlayer
	var anim_player: AnimationPlayer = scene_root.get_node_or_null("AnimationPlayer")
	if not anim_player:
		ctx.log_error("AnimationPlayer not found in scene")
		ctx.quit(1)

	# Get animation
	var lib: AnimationLibrary = anim_player.get_animation_library("")
	if not lib or not lib.has_animation(params.animation_name):
		ctx.log_error("Animation not found: " + params.animation_name)
		ctx.quit(1)

	var animation: Animation = lib.get_animation(params.animation_name)

	var track_idx: int = params.track_index
	if track_idx < 0 or track_idx >= animation.get_track_count():
		ctx.log_error("Invalid track index: " + str(track_idx))
		ctx.quit(1)

	# Parse value (support simple types for now)
	var value: Variant = params.value
	var time: float = params.time

	# Insert keyframe
	var key_idx: int = animation.track_insert_key(track_idx, time, value)

	if ctx.debug_mode:
		print("[DEBUG] Keyframe inserted at index: " + str(key_idx))

	# Save scene
	var packed_scene: PackedScene = PackedScene.new()
	var result: int = packed_scene.pack(scene_root)

	if result == OK:
		var save_error: int = ResourceSaver.save(packed_scene, full_scene_path)
		if save_error == OK:
			print("Keyframe set at time " + str(time) + "s in track " + str(track_idx))
		else:
			ctx.log_error("Failed to save scene: " + str(save_error))
			ctx.quit(1)
	else:
		ctx.log_error("Failed to pack scene: " + str(result))
		ctx.quit(1)


## Get information about an animation
static func get_animation_info(ctx: SceneTree, params: Dictionary) -> void:
	var full_scene_path: String = params.scene_path
	if not full_scene_path.begins_with("res://"):
		full_scene_path = "res://" + full_scene_path

	if not FileAccess.file_exists(full_scene_path):
		ctx.log_error("Scene file does not exist: " + full_scene_path)
		ctx.quit(1)

	var scene: PackedScene = load(full_scene_path)
	if not scene:
		ctx.log_error("Failed to load scene: " + full_scene_path)
		ctx.quit(1)

	var scene_root: Node = scene.instantiate()

	# Find AnimationPlayer
	var anim_player: AnimationPlayer = scene_root.get_node_or_null("AnimationPlayer")
	if not anim_player:
		ctx.log_error("AnimationPlayer not found in scene")
		ctx.quit(1)

	# Get animation
	var lib: AnimationLibrary = anim_player.get_animation_library("")
	if not lib or not lib.has_animation(params.animation_name):
		ctx.log_error("Animation not found: " + params.animation_name)
		ctx.quit(1)

	var animation: Animation = lib.get_animation(params.animation_name)

	# Build info dictionary
	var info: Dictionary = {
		"name": params.animation_name,
		"length": animation.length,
		"loop_mode": _loop_mode_to_string(animation.loop_mode),
		"track_count": animation.get_track_count(),
		"tracks": []
	}

	# Get track information
	for i in range(animation.get_track_count()):
		var track_info: Dictionary = {
			"index": i,
			"type": _track_type_to_string(animation.track_get_type(i)),
			"path": str(animation.track_get_path(i)),
			"key_count": animation.track_get_key_count(i)
		}
		info.tracks.append(track_info)

	# Output as JSON
	print(JSON.stringify(info, "\t"))


## List all animations in a scene
static func list_animations(ctx: SceneTree, params: Dictionary) -> void:
	var full_scene_path: String = params.scene_path
	if not full_scene_path.begins_with("res://"):
		full_scene_path = "res://" + full_scene_path

	if not FileAccess.file_exists(full_scene_path):
		ctx.log_error("Scene file does not exist: " + full_scene_path)
		ctx.quit(1)

	var scene: PackedScene = load(full_scene_path)
	if not scene:
		ctx.log_error("Failed to load scene: " + full_scene_path)
		ctx.quit(1)

	var scene_root: Node = scene.instantiate()

	# Find AnimationPlayer
	var anim_player: AnimationPlayer = scene_root.get_node_or_null("AnimationPlayer")
	if not anim_player:
		# No AnimationPlayer means no animations
		print(JSON.stringify({"animations": []}, "\t"))
		return

	var animations: Array = []

	# Get all animation libraries
	for lib_name in anim_player.get_animation_library_list():
		var lib: AnimationLibrary = anim_player.get_animation_library(lib_name)
		for anim_name in lib.get_animation_list():
			var animation: Animation = lib.get_animation(anim_name)
			animations.append({
				"name": anim_name,
				"library": lib_name,
				"length": animation.length,
				"loop_mode": _loop_mode_to_string(animation.loop_mode),
				"track_count": animation.get_track_count()
			})

	# Output as JSON
	print(JSON.stringify({"animations": animations}, "\t"))


# Helper functions

static func _track_type_to_string(track_type: int) -> String:
	match track_type:
		Animation.TYPE_VALUE:
			return "value"
		Animation.TYPE_POSITION_3D:
			return "position_3d"
		Animation.TYPE_ROTATION_3D:
			return "rotation_3d"
		Animation.TYPE_SCALE_3D:
			return "scale_3d"
		Animation.TYPE_BLEND_SHAPE:
			return "blend_shape"
		Animation.TYPE_METHOD:
			return "method"
		Animation.TYPE_BEZIER:
			return "bezier"
		Animation.TYPE_AUDIO:
			return "audio"
		Animation.TYPE_ANIMATION:
			return "animation"
		_:
			return "unknown"


static func _loop_mode_to_string(loop_mode: int) -> String:
	match loop_mode:
		Animation.LOOP_NONE:
			return "none"
		Animation.LOOP_LINEAR:
			return "linear"
		Animation.LOOP_PINGPONG:
			return "pingpong"
		_:
			return "unknown"
