extends Player
const PhysicsFunc = preload("res://src/Utilities/Physic/PhysicsFunc.gd")

onready var players = get_tree().get_nodes_in_group("player")

onready var vision_raycast: RayCast2D = $VisionRayCast
onready var orientation: RayCast2D = $Orientation 
onready var jump_timer: Timer
onready var target_lost_timer: Timer

export var score := 100
# Is given in blocks
export var vision_distance := 6.0

# Also in blocks
var movement_radius: float
var anchor: Node2D
var is_bound := false

var target: Object = null

var start_x := 0.0
var in_air := false
var is_hurt := false
var stored_x_vel = 0.0

var current_delta = 0.0

var reversing_possible_searching := true

func _ready():
	jump_timer = Timer.new()
	jump_timer.set_one_shot(true)
	jump_timer.connect("timeout", self, "jump")
	target_lost_timer = Timer.new()
	target_lost_timer.connect("timeout", self, "lose_target")
	add_child(jump_timer)
	add_child(target_lost_timer)


func bind_to_anchor(anchor_node: Node2D, radius: float ) -> void:
	anchor = anchor_node
	movement_radius = radius * 24
	is_bound = true


func _on_StompDetector_body_entered(body: Node) -> void:
	if body.global_position.y > get_node("StompDetector").global_position.y:
		return
	if body.is_in_group("player"):
		remove_from_group("harmful")
		is_hurt = true


func execute_movement(delta: float) -> void:
	current_delta = delta
	velocity.y += _gravity * delta
	if(is_bound):
		var next_position = global_position + velocity * current_delta
		var current_distance = global_position.distance_to(anchor.global_position)
		var new_distance = next_position.distance_to(anchor.global_position)
		if(current_distance >= movement_radius && new_distance > current_distance):
			velocity.x = velocity.x * 0.8
	velocity = move_and_slide(velocity, FLOOR_NORMAL, false, 4, 0.785398,false)
	if(is_on_floor()):
		velocity = Vector2(0,0)
	# Reverse direction when hitting limit


func die() -> void:
	GlobalState.score += score
	queue_free()


func _on_EnemySkin_area_entered(area:Area2D) -> void:
	if area.is_in_group("harmful"):
		get_node("EnemyBody").disabled = true
		die()


func searching() -> Vector2:
	detect_player()

	if(is_on_floor()):
		if(jump_timer.is_stopped()):
			if(target != null):
				jump_timer.start(rand_range(0.3,1))
			else:
				jump_timer.start(rand_range(0.3,3.333))
		if(in_air):
			in_air = false
			#print("Jump distance: ",global_position.x - start_x)
	else:
		if(!in_air):
			start_x = global_position.x
		reversing_possible_searching = true
		jump_timer.stop()
		in_air = true

	return velocity


func detect_player() -> void:
		var player
		if(!players.empty()):
			player = players[0]
		vision_raycast.cast_to = (player.global_position - global_position).normalized() * 24 * vision_distance
		var ray_angle_to_facing = vision_raycast.cast_to.angle_to(orientation.cast_to)
		var collider = vision_raycast.get_collider()
		if(target == null && abs(ray_angle_to_facing) < PI/4 && collider != null && collider.is_in_group("player")):
			target_lost_timer.stop()
			target = collider
			print("target found")
		elif(target != null && target_lost_timer.is_stopped()):
			target_lost_timer.start(3.0)


func sleeping() -> Vector2:
	jump_timer.stop()
	detect_player()
	return velocity


func lose_target() -> void:
	print("target lost")
	target = null


func jump():
	var v: Vector2 = velocity_for_jump_distance()
	var jump_height = (pow(v.length(), 2) * pow(sin(deg2rad(65)),2))/(2*_gravity)
	#print("Jump height: ", jump_height)
	velocity = v

	if(is_bound):
		var next_position = global_position + velocity * get_facing_direction() * current_delta
		var current_distance = global_position.distance_to(anchor.global_position)
		var new_distance = next_position.distance_to(anchor.global_position)
		#print(current_distance)
		#print(new_distance)
		if(new_distance >= movement_radius && new_distance > current_distance):
			if can_reverse_facing_direction():
				reverse_facing_direction()
		elif (($Left_Wallcast.is_colliding() || $Right_Wallcast.is_colliding()) && can_reverse_facing_direction()):
			reverse_facing_direction()
	elif (($Left_Wallcast.is_colliding() || $Right_Wallcast.is_colliding()) && can_reverse_facing_direction()):
		reverse_facing_direction()

	if sign(velocity.x) != get_facing_direction():
		velocity.x *= -1

	$CeilingRayCast.cast_to = Vector2(1.5*24 * get_facing_direction(), - jump_height)


func velocity_for_jump_distance(distance: float = 3*24, angle: float = deg2rad(65)) -> Vector2:
	var abs_velocity = sqrt((distance * _gravity)/sin(2*angle))
	return Vector2(abs_velocity,0).rotated(-1*angle)


func can_reverse_facing_direction() -> bool:
	if(is_on_floor()):
			return true
	return false


func reverse_facing_direction() -> void:
	print("reversing direction")
	orientation.cast_to.x *= -1
	pass


func get_facing_direction() -> float:
	return orientation.cast_to.x
