extends StateMachine

signal got_grounded

onready var coyoteTimer = $CoyoteTimer
export var coyote_hanging = false
export var init_boost = false
export var init_boost_type = ""
onready var jumpBufferTimer = $JumpBufferTimer
onready var anim_player = parent.get_node("BlobbySprite/BlobbymationPlayer")
onready var anim_state_playback = parent.get_node("BlobbySprite/AnimationTree").get("parameters/playback")
onready var anim_tree = parent.get_node("BlobbySprite/AnimationTree")
onready var sprite = parent.get_node("BlobbySprite")

var facing = 1
var didTurn

# Adds the intial states
func _ready():
	add_state("idle")
	add_state("duck")
	add_state("run")
	add_state("walk")
	add_state("jump")
	add_state("fall")
	add_state("wallslide")
	state = states.idle
	set_state(states.idle)


# Calls the parent behaviours according to state
func _state_logic(delta):
	# RayCasts for visual debugging
	# TODO Global context switch for debug/build mode
	# \ is for new line in multiline statements
	# parent.get_node("CollisionShape2D/RayCaster")._raycast(
	# 	Vector2.DOWN,
	# 	parent.get_node("CollisionShape2D").get_shape(),
	# 	parent.collision_mask
	# )

	var handle_input_ref

	match self.state:
		"idle":
			handle_input_ref = funcref(self, "handle_idle_input")
		"duck":
			handle_input_ref = funcref(self, "handle_duck_input")
		"walk":
			handle_input_ref = funcref(self, "handle_walk_input")
		"run":
			handle_input_ref = funcref(self, "handle_run_input")
		"jump":
			handle_input_ref = funcref(self, "handle_jump_input")
		"fall":
			handle_input_ref = funcref(self, "handle_fall_input")
		"wallslide":
			handle_input_ref = funcref(self, "handle_wallslide_input")
		_:
			print("don't panik")

	var direction = get_horizontal_direction()
	didTurn = false

	#TODO use blendspace value 0 for turn animations instead of this?
	# Can you make the blendspace animation play out till end?
	if direction.x < 0 && facing == 1:
		didTurn = true
		facing = -1
	elif direction.x > 0 && facing == -1:
		didTurn = true
		facing = 1

	#TODO Yeah... deal with it
	anim_tree.set("parameters/wallslideToJump/blend_position", parent.wall_touch_direction)
	anim_tree.set("parameters/wallsliding/blend_position", parent.wall_touch_direction)
	if didTurn:
		_set_blendspaces_direction(facing)
		_trigger_turn_animation()

	parent.velocity = handle_input_ref.call_func(delta, direction)

	parent.execute_movement()


func handle_idle_input(delta, direction) -> Vector2:
		return parent.handle_grounded_movement(delta, direction)

func handle_duck_input(delta, direction) -> Vector2:
		return parent.handle_duck_movement(delta, direction)

func handle_walk_input(delta, direction) -> Vector2:
	return parent.handle_grounded_movement(delta, direction)


func handle_run_input(delta, direction) -> Vector2:
	return parent.handle_grounded_movement(delta, direction)


func handle_jump_input(delta, direction) -> Vector2:
	return parent.handle_jump_movement(delta, direction)


func handle_fall_input(delta, direction) -> Vector2:
	return parent.handle_fall_movement(delta, direction)


func handle_wallslide_input(delta, direction) -> Vector2:
	return parent.handle_wallslide_movement(delta, direction)


func get_horizontal_direction() -> Vector2:
	#TODO Check if this is fixed yet
	if Input.get_connected_joypads().size() > 0:
		if Input.is_joy_button_pressed(Input.get_connected_joypads()[0], 14):
			return Vector2(-1, 0)
		if Input.is_joy_button_pressed(Input.get_connected_joypads()[0], 15):
			return Vector2(1, 0)
	return Vector2(
		(
			Input.get_action_strength("move_right")
			- Input.get_action_strength("move_left")
		),
		0
	)


# Determines which state should be active at the moment
func _get_transition(_delta):
	parent.get_node("StateLabel").text = (
		self.state
		+ " x vel:"
		+ String(round(parent.velocity.x))
		+ " y vel/10:"
		+ String(round(parent.velocity.y / 10))
	)
	var new_state
	if !parent.is_on_floor():
		if parent.velocity.y < 0:
			new_state = states.jump

		if parent.velocity.y >= 0:
			new_state = states.fall
			if parent.is_touching_wall_completely():
				new_state = states.wallslide
			# Begins coyote time only if walking from ledge
			elif [states.walk, states.run].has(self.state) && !coyote_hanging:
				coyoteTimer.start()
				coyote_hanging = true

			if new_state == states.fall && jumpBufferTimer.is_stopped():
				jumpBufferTimer.start()

			if (
				coyoteTimer.is_stopped()
				|| [states.idle, states.jump].has(self.state)
			):
				coyote_hanging = false
			if coyote_hanging:
				new_state = self.state

	elif parent.velocity.x != 0:
		if Input.is_action_pressed("boost_move"):
			new_state = states.run
		else:
			new_state = states.walk
		if Input.is_action_pressed("duck"):
			new_state = states.duck
		coyote_hanging = false

	else:
		new_state = states.idle
		if Input.is_action_pressed("duck"):
			new_state = states.duck
		coyote_hanging = false
	if new_state != self.state:
		return new_state
	init_boost = false
	return null


func _enter_state(new_state, old_state):
	if old_state == "idle" && (new_state == "walk" || new_state == "run"):
		init_boost = true
		init_boost_type = old_state + "_" + new_state
	else:
		init_boost = false
		init_boost_type = ""

	if !["run", "walk", "idle", "duck"].has(old_state) && parent.is_on_floor():
		emit_signal("got_grounded")


	match new_state:
		states.walk:
		# TODO I need this when there is a turn happening between two different states
			if old_state == states.idle && didTurn:
				anim_state_playback.travel("idleTurn")
			else:
				anim_state_playback.travel("walking")
		states.idle:
			anim_state_playback.travel("idling")
		states.duck:
		# TODO HA! H! HAAA! 
			anim_state_playback.travel("ducking")
		states.jump:
			anim_state_playback.travel("jumping")
		states.fall:
			anim_state_playback.travel("falling")
		states.run:
			anim_state_playback.travel("running")
		states.wallslide:
			anim_state_playback.travel("wallsliding")



func _exit_state(old_state, new_state):
	pass

func _set_blendspaces_direction(value):
	anim_tree.set("parameters/ducking/blend_position", value)
	anim_tree.set("parameters/falling/blend_position", value)
	anim_tree.set("parameters/idling/blend_position", value)
	anim_tree.set("parameters/jumpToFall/blend_position", value)
	anim_tree.set("parameters/jumping/blend_position", value)
	anim_tree.set("parameters/runToJump/blend_position", value)
	anim_tree.set("parameters/running/blend_position", value)
	anim_tree.set("parameters/turnToRun/blend_position", value)
	anim_tree.set("parameters/walking/blend_position", value)

func _trigger_turn_animation():
	match self.state:
		states.duck:
			anim_state_playback.travel("duckTurn")
		states.walk:
			anim_state_playback.travel("idleTurn")
		states.idle:
			anim_state_playback.travel("idleTurn")
	
