extends KinematicBody2D

# Declare member variables here. Examples:
# var a: int = 2
# var b: String = "text"
onready var sightcone: Node2D = $SightCone
onready var aimline: RayCast2D = $Aimline
onready var laserpoint: Sprite = $Laserpoint
onready var turret_state_machine = $TurretStateMachine
onready var lock_on_timer = $LockOnTimer
onready var sight_lost_timer = $SightLostTimer
onready var turret_search_animation = $AnimationPlayer.get_animation("Turret Rotation")
onready var turret_return_animation = $AnimationPlayer.get_animation("Turret Returning")
onready var Bullet = preload("res://src/HarmfulObjects/Bullet.tscn")
# Derives the freedom from the number of bald head eagles
onready var angle_of_freedom = deg2rad(
	turret_search_animation.track_get_key_value(
		0, turret_search_animation.track_get_key_count(0) - 1
	)
)
onready var original_rotation = rotation
onready var rotation_speed_divider = 80
# TODO causes oscilation
onready var min_rotation_speed = deg2rad(0.3)
var prey_ref = weakref(null)
# Ray that goes from the turret to the target
var target_ray

func prey():
	return prey_ref.get_ref()

func position_laserpoint():
	if aimline.is_colliding():
		laserpoint.global_position = aimline.get_collision_point()
	

func searching():
	position_laserpoint()
	for sightline in sightcone.get_children():
		if sightline.is_colliding():
			# The collider returns not the area or body it hit, but the parent of them
			var collider = sightline.get_collider()
			if collider.is_in_group("player"):
				prey_ref = weakref(collider)
				break

# TODO should this stand still?
# TODO Use yield and coroutine instead
func start_locking():
	position_laserpoint()
	target_ray = RayCast2D.new()
	add_child(target_ray)
	target_ray.enabled = true
	target_ray.exclude_parent = true
	if(prey() != null):
		target_ray.set_cast_to(to_local(prey().position))
	lock_on_timer.start()


func is_locked_on_target():
	return lock_on_timer.is_stopped()

func is_tracking_prey():
	return true if(prey() != null) else false

func aiming():
	var target_angle = target_ray.cast_to.angle_to(aimline.cast_to)
	var rotation_speed = max(
		min_rotation_speed, abs(target_angle / rotation_speed_divider)
	)
	if abs(target_angle) < min_rotation_speed:
		rotation = rotation - target_angle
	else:
		rotation = rotation - rotation_speed * sign(target_angle)
	rotation = clamp(
		rotation, original_rotation, original_rotation + angle_of_freedom
	)

# Shoots and can loose the target
func shooting():
	aiming()
	for sightline in sightcone.get_children():
		if sightline.is_colliding():
			# The collider returns not the area or body it hit, but the parent of them
			var collider = sightline.get_collider()
			if collider.is_in_group("player"):
				sight_lost_timer.stop()
				target_ray.cast_to = to_local(prey().position)
			else:
				if (
					sight_lost_timer.get_time_left() < 0.1
					&& sight_lost_timer.get_time_left() > 0
				):
					prey_ref = weakref(null)
					target_ray.queue_free()
					return
				if sight_lost_timer.is_stopped():
					sight_lost_timer.start()
				elif(prey() != null):
					target_ray.cast_to = to_local(prey().position)
			return

func spawn_projectile():
	var b = Bullet.instance()
	get_parent().add_child(b)
	b.set_collision_mask_bit(1, false)
	b.transform = $Muzzle.global_transform


func _on_FiringRateTimer_timeout():
		spawn_projectile()
