@tool
extends Node3D

@export var size: Vector3 = Vector3(0.5, 0.2, 0.5)
@export var requiredPlacements: int = 3
@export var distanceThreshold: float = 0.05
@export var rotationThreshold: float = 0.25
@export var minNewShapeDistance: float = 0.4
@export var minNewGoalDistance: float = 0.4

var placedTShapes: int = 0
var entered: bool = false

func _ready():
	if not Engine.is_editor_hint():
		$TaskArea.mesh.material.albedo_color.a = 0
	randomizeShapes()

func _process(_delta):
	# setup, which I also want to see in editor
	$TaskArea.mesh.size = size
	$TaskArea.position.y = size.y / 2
	$TaskArea/Area3D/CollisionShape3D.shape.size = size
	$Gate.mesh.size = Vector3(size.x, 0.5, 0.05)
	$Gate/StaticBody3D/CollisionShape3D.shape.size = $Gate.mesh.size
	$Gate.position = Vector3(0, 0.25, -size.z / 2 - 0.025)

	if (placedTShapes == requiredPlacements):
		if (not $AnimationPlayer.is_playing()):
			queue_free()
		return

	# game logic
	if (shapesAlign()):
		placedTShapes += 1
		randomizeShapes()
		if (placedTShapes == requiredPlacements):
			$TShape.queue_free()
			$Goal.queue_free()
			lowerGate()
			Signals.emit_signal("TShapeTaskCompleted")

func randomizeShapes():
	Signals.emit_signal("ForceRelease")
	$TShape.rotation = Vector3(randf() * PI, randf() * PI, randf() * PI)
	var newShapePosition = randPosInBox(size)
	while (newShapePosition.distance_to($TShape.position) < minNewShapeDistance):
		newShapePosition = randPosInBox(size)
	$TShape.position = newShapePosition

	$Goal.rotation = Vector3(randf() * PI, randf() * PI, randf() * PI)
	var newGoalPosition = randPosInBox(size)
	while (newGoalPosition.distance_to($TShape.position) < minNewGoalDistance):
		newGoalPosition = randPosInBox(size)
	$Goal.position = newGoalPosition

func shapesAlign():
	if $TShape.position.distance_to($Goal.position) > distanceThreshold:
		return false
	if ($TShape.quaternion.angle_to($Goal.quaternion) < rotationThreshold or
	 	  $TShape.quaternion.angle_to($Goal.quaternion * Quaternion(0, 1, 0, 0)) < rotationThreshold):
		return true
	return false

func lowerGate():
	$AnimationPlayer.play("lower")
	$AnimationPlayer.queue("keep_lowered")

func randPosInBox(boxSize: Vector3):
	return Vector3(
		randf_range(-0.5, 0.5) * boxSize.x,
		randf_range(0.4, 1) * boxSize.y,
		randf_range(-0.5, 0.5) * boxSize.z
	)

func _on_area_3d_body_entered(_body:Node):
	if entered:
		return
	entered = true
	Signals.emit_signal("TShapeTaskStarted")
