# Collision operations module
# Handles: add_collision_shape, set_collision_shape_properties, set_collision_layers
# Corresponds to: test_collision.py
class_name CollisionOps


## Add a collision shape to a CollisionObject node
static func add_collision_shape(ctx: SceneTree, params: Dictionary) -> void:
	ctx.log_info("Adding collision shape: " + params.shape_type)

	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 the target node
	var target_node: Node = scene_root.get_node_or_null(NodePath(params.node_path))
	if not target_node:
		ctx.log_error("Node not found: " + params.node_path)
		ctx.quit(1)

	# Check if it's a CollisionObject
	if not (target_node is CollisionObject2D or target_node is CollisionObject3D):
		ctx.log_error("Node is not a CollisionObject2D or CollisionObject3D: " + params.node_path)
		ctx.quit(1)

	# Create CollisionShape node
	var collision_shape: Node
	if target_node is CollisionObject2D:
		collision_shape = CollisionShape2D.new()
	else:
		collision_shape = CollisionShape3D.new()

	collision_shape.name = "CollisionShape"

	# Create the shape resource
	var shape: Shape2D = null if target_node is CollisionObject2D else null
	var shape_class = params.shape_type

	if ctx.debug_mode:
		print("[DEBUG] Creating shape: " + shape_class)

	# Instantiate the shape
	if ClassDB.class_exists(shape_class):
		shape = ctx.instantiate_class(shape_class)
	else:
		ctx.log_error("Unknown shape type: " + shape_class)
		ctx.quit(1)

	if not shape:
		ctx.log_error("Failed to create shape: " + shape_class)
		ctx.quit(1)

	# Set shape properties if provided
	if params.has("shape_properties"):
		var props: Dictionary = {}
		if typeof(params.shape_properties) == TYPE_STRING:
			var json: JSON = JSON.new()
			if json.parse(params.shape_properties) == OK:
				props = json.get_data()
		else:
			props = params.shape_properties

		for prop_name in props:
			var prop_value = props[prop_name]
			# Convert array to Vector2/Vector3
			if prop_name == "size" or prop_name == "extents":
				if typeof(prop_value) == TYPE_ARRAY:
					if prop_value.size() == 2:
						prop_value = Vector2(prop_value[0], prop_value[1])
					elif prop_value.size() == 3:
						prop_value = Vector3(prop_value[0], prop_value[1], prop_value[2])

			if prop_name == "radius" or prop_name == "height":
				prop_value = float(prop_value)

			shape.set(prop_name, prop_value)

	# Assign shape to CollisionShape
	if target_node is CollisionObject2D:
		collision_shape.shape = shape
	else:
		collision_shape.shape = shape

	# Add CollisionShape to target node
	target_node.add_child(collision_shape)
	collision_shape.owner = scene_root

	if ctx.debug_mode:
		print("[DEBUG] CollisionShape added to node")

	# 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("Collision shape '" + params.shape_type + "' added to '" + params.node_path + "'")
		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 properties of a collision shape
static func set_collision_shape_properties(ctx: SceneTree, params: Dictionary) -> void:
	ctx.log_info("Setting collision shape properties")

	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 the target node
	var target_node: Node = scene_root.get_node_or_null(NodePath(params.node_path))
	if not target_node:
		ctx.log_error("Node not found: " + params.node_path)
		ctx.quit(1)

	# Check if it's a CollisionShape
	if not (target_node is CollisionShape2D or target_node is CollisionShape3D):
		ctx.log_error("Node is not a CollisionShape2D or CollisionShape3D: " + params.node_path)
		ctx.quit(1)

	var shape = target_node.shape
	if not shape:
		ctx.log_error("CollisionShape has no shape resource")
		ctx.quit(1)

	# Parse properties
	var props: Dictionary = {}
	if typeof(params.properties) == TYPE_STRING:
		var json: JSON = JSON.new()
		if json.parse(params.properties) == OK:
			props = json.get_data()
	else:
		props = params.properties

	# Set properties
	for prop_name in props:
		var prop_value = props[prop_name]

		# Convert array to Vector2/Vector3
		if typeof(prop_value) == TYPE_ARRAY:
			if prop_value.size() == 2:
				prop_value = Vector2(prop_value[0], prop_value[1])
			elif prop_value.size() == 3:
				prop_value = Vector3(prop_value[0], prop_value[1], prop_value[2])

		shape.set(prop_name, prop_value)

	if ctx.debug_mode:
		print("[DEBUG] Properties set on shape")

	# 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("Collision shape properties updated")
		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 collision layers and masks
static func set_collision_layers(ctx: SceneTree, params: Dictionary) -> void:
	ctx.log_info("Setting collision layers")

	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 the target node
	var target_node: Node = scene_root.get_node_or_null(NodePath(params.node_path))
	if not target_node:
		ctx.log_error("Node not found: " + params.node_path)
		ctx.quit(1)

	# Check if it's a CollisionObject
	if not (target_node is CollisionObject2D or target_node is CollisionObject3D):
		ctx.log_error("Node is not a CollisionObject2D or CollisionObject3D: " + params.node_path)
		ctx.quit(1)

	# Set collision layer
	if params.has("collision_layer"):
		target_node.collision_layer = params.collision_layer
		if ctx.debug_mode:
			print("[DEBUG] Collision layer set to: " + str(params.collision_layer))

	# Set collision mask
	if params.has("collision_mask"):
		target_node.collision_mask = params.collision_mask
		if ctx.debug_mode:
			print("[DEBUG] Collision mask set to: " + str(params.collision_mask))

	# 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("Collision layers configured")
		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 physics body properties
static func set_physics_body_properties(ctx: SceneTree, params: Dictionary) -> void:
	ctx.log_info("Setting physics body properties")

	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 the target node
	var target_node: Node = scene_root.get_node_or_null(NodePath(params.node_path))
	if not target_node:
		ctx.log_error("Node not found: " + params.node_path)
		ctx.quit(1)

	# Check if it's a RigidBody
	if not (target_node is RigidBody2D or target_node is RigidBody3D):
		ctx.log_error("Node is not a RigidBody2D or RigidBody3D: " + params.node_path)
		ctx.quit(1)

	# Set properties
	if params.has("mass"):
		target_node.mass = params.mass
	if params.has("friction"):
		if target_node is RigidBody2D:
			target_node.physics_material_override = target_node.physics_material_override if target_node.physics_material_override else PhysicsMaterial.new()
			target_node.physics_material_override.friction = params.friction
		else:
			target_node.physics_material_override = target_node.physics_material_override if target_node.physics_material_override else PhysicsMaterial.new()
			target_node.physics_material_override.friction = params.friction
	if params.has("bounce"):
		if target_node is RigidBody2D:
			target_node.physics_material_override = target_node.physics_material_override if target_node.physics_material_override else PhysicsMaterial.new()
			target_node.physics_material_override.bounce = params.bounce
		else:
			target_node.physics_material_override = target_node.physics_material_override if target_node.physics_material_override else PhysicsMaterial.new()
			target_node.physics_material_override.bounce = params.bounce
	if params.has("gravity_scale"):
		target_node.gravity_scale = params.gravity_scale
	if params.has("linear_damp"):
		target_node.linear_damp = params.linear_damp
	if params.has("angular_damp"):
		target_node.angular_damp = params.angular_damp

	if ctx.debug_mode:
		print("[DEBUG] Physics properties set")

	# 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("Physics body properties set")
		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)
