extends "res://src/actors/character/Character.gd"


enum States {
	IDLE,
	MOVE,
	ATTACK,
	DEAD
}


enum Events {
	INVALID=-1,
	IDLE,
	MOVE,
	ATTACK,
	DEAD
}

const MAX_SPEED = 400
const ACCELERATION = 3000
const FRICTION = 3000

var _speed = 0 
var _velocity = Vector2()
var _collision_normal = Vector2()
var _last_input_direction = Vector2()
var player_inventory = null
var equipment = null
var can_attack = true


onready var animationPlayer = $AnimationPlayer
onready var animationTree = $AnimationTree
onready var collisionShape2D = $CollisionShape2D
onready var animationState = animationTree.get("parameters/playback")
onready var cam  = get_tree().get_root().find_node("PlayerCam", true, false)

onready var dialogue_box_node  = get_tree().get_root().find_node("DialogueBox", true, false)

onready var attack_obj = $Attack
#the ranged attack is implemented very siple and dirty right now.. will be fixed soon
onready var ranged_attack_obj = $RangedAttack


func _init() -> void:
	_transitions = {
		[States.IDLE, Events.MOVE]: States.MOVE,
		[States.IDLE, Events.DEAD]: States.DEAD,
		[States.MOVE, Events.IDLE]: States.IDLE,
		[States.MOVE, Events.DEAD]: States.DEAD,
		[States.MOVE, Events.ATTACK]: States.ATTACK,
		[States.IDLE, Events.ATTACK]: States.ATTACK,
		[States.ATTACK, Events.IDLE]: States.IDLE,
		[States.ATTACK, Events.MOVE]: States.MOVE,
		[States.ATTACK, Events.DEAD]: States.DEAD,
	}


func _ready() -> void:
	animationTree.active = true
	collisionShape2D.disabled = false
	attack_obj.stop_attack()
	connect("direction_changed", attack_obj, "on_parent_direction_changed")
	playerData.init_data()
	player_inventory = playerData.inventory_component
	equipment = playerData.equipment_component
	



func _physics_process(delta) -> void:
	var input = get_raw_input()
	
	if Input.is_action_pressed("simulate_player_damage"):
		$Health.take_damage(1)
	if Input.is_action_pressed("simulate_player_heal"):
		$Health.recover_health(1)
	

	
	match state:
		States.MOVE, States.IDLE:
			_move(input.direction, delta)
		States.ATTACK:
			_attack()
		States.DEAD:
			pass


func start_attack(input_vector) -> void:
	
	if not can_attack:
		return

	if animationState.get_current_node() == "Attack":
		return #fixes a bug where start_attack gets called twice sometimes
		#checking the player state results in "Idle" while the animation state is "Attack",
		#meaning that the player state gives wrong results here
	if cam != null:
		input_vector = (get_viewport().get_mouse_position() - (get_viewport_rect().size / 2) + (cam.position - self.position)).normalized()
		
	emit_signal("direction_changed", input_vector)
	weapon.change_direction(input_vector)
	attack_obj.start_attack()

	animationTree.set("parameters/Idle/blend_position", input_vector)
	animationTree.set("parameters/Attack/blend_position", input_vector)
	change_state(Events.ATTACK)


func enter_state() -> void:
	weapon.change_state(state)


func _move(direction, delta) -> void:
	var input_vector = direction
	can_attack = true
	
	input_vector.y = input_vector.y * 0.5
	
	input_vector = input_vector.normalized()
	
	if input_vector!= Vector2.ZERO:
		animationTree.set("parameters/Idle/blend_position", input_vector)
		animationTree.set("parameters/Walk/blend_position", input_vector)
		animationTree.set("parameters/Attack/blend_position", input_vector)
		emit_signal("direction_changed", input_vector)
		
		change_state(Events.MOVE)
		animationState.travel("Walk")
		_velocity = _velocity.move_toward(input_vector * MAX_SPEED, ACCELERATION * delta)
	else:
		change_state(Events.IDLE)
		animationState.travel("Idle")
		_velocity = _velocity.move_toward(Vector2.ZERO, FRICTION * delta)
		
		
	
	_velocity = move_and_slide(_velocity)
	emit_signal("position_changed", self.position)
	
	if Input.is_action_pressed("attack"):
		
		if utils.is_mouse_over_element(player_inventory.window_ref) == true:
			can_attack = false
			
		if utils.is_mouse_over_element(equipment.window_ref) == true:
			can_attack = false
			
		if get_viewport().gui_is_dragging():
			can_attack = false
		
		if dialogue_box_node.visible:
			can_attack = false
		
		
		start_attack(input_vector)


func _attack() -> void:
	_velocity = Vector2.ZERO
	animationState.travel("Attack")


func attack_animation_finished() -> void:
	change_state(Events.IDLE)
	attack_obj.stop_attack()


static func get_raw_input():
	return {
		direction = utils.get_input_direction(),	
	}
	
	
func _on_item_interacted(sender, item, amount):
	if $InventoryComponent.add_to_inventory(item, amount):
		sender.queue_free()
