extends Position2D
class_name Entity

const BLOCK_EFFECT = preload("res://Effects/Block.tscn")
const DEATH_PARTICLE = preload("res://Particles/DeathParticle.tscn")

signal dead
# warning-ignore:unused_signal
signal target_enemy_dead
# warning-ignore:unused_signal
signal items_update(items)
signal item_used(items)

export (int) var max_health = 100
export (float) var damage_base = 1
export (float) var block_damage_divider = 4
export (float) var agility_base = 1
export (bool) var can_block: bool = false
export (bool) var can_use_items: bool = true
export (Array, Resource) var items: Array
export (Array, Resource) var awards: Array

onready var animation_player: AnimationPlayer = $AnimationPlayer
onready var draw_pivot = $DrawPivot
onready var sprite = $DrawPivot/Sprite
onready var weapon = $DrawPivot/Weapon
onready var current_effects: Node = $CurrentEffects
onready var tween: Tween = $Tween
onready var healthbar: ProgressBar = $HealthBar

onready var health = max_health setget set_health

var target_enemy: Entity = null
var is_dead: bool = false

func _ready():
	$Label.text = str(health) + "/" + str(max_health)
	healthbar.max_value = max_health
	healthbar.value = health

func add_stats(stats: Dictionary):
	if stats.has("max_health"):
		max_health += stats.max_health
		healthbar.max_value = max_health
		self.health += stats.max_health
	
	if stats.has("max_health_multiply"):
		var multiplied = max_health * stats.max_health_multiply - max_health
		
		max_health += multiplied
		healthbar.max_value = max_health
		self.health += multiplied
	
	if stats.has("can_use_items"):
		can_use_items = stats.can_use_items
	
	if stats.has("damage_base"):
		damage_base += stats.damage_base
	
	if stats.has("block_damage_divider"):
		block_damage_divider += stats.block_damage_divider
		
	if stats.has("agility_base"):
		agility_base += stats.agility_base
	
	if stats.has("items"):
		items = stats.items.duplicate()
	
	if stats.has("awards"):
		awards = stats.awards.duplicate()

func item_use():
	$Tween.interpolate_property(
		draw_pivot, "position", 
		Vector2(0, 5), Vector2.ZERO, 0.25, 
		Tween.TRANS_ELASTIC, Tween.EASE_OUT
	)
	$Tween.start()
	
	var item = items.pop_front()
	if item is Item:
		item.use(self, target_enemy)
	emit_signal("item_used", items)

func item_lose():
	if target_enemy != null:
		var item = items.pop_front()
		target_enemy.item_add(item)
		emit_signal("item_used", items)

func give_awards():
	if target_enemy != null:
		for item in awards:
			target_enemy.item_add(item)

func item_add(item):
	if not item is Item:
		return
	
	if (item.type == item.TYPE.WEAPON 
	or item.type == item.TYPE.PERMANENT):
		item.use(self, target_enemy)
	elif items.size() < 5:
		items.append(item)
		emit_signal("items_update", items)

func hurt(damage):
	self.health -= damage
	Audio.play_sound_random(["Hit", "Hit2", "Hit3"], rand_range(0.9, 1.1))
	var _no_use
	_no_use = tween.interpolate_property(
		draw_pivot, "position", 
		Vector2(draw_pivot.scale.x * 5, 0), Vector2.ZERO, 0.5, 
		Tween.TRANS_ELASTIC, Tween.EASE_OUT
	)
	_no_use = tween.start()
	#print(damage)

func bleed(damage):
	self.health -= damage
	var _no_use
	_no_use = tween.interpolate_property(
		draw_pivot, "modulate", 
		Color(1.0, 0.5, 0.5, 1.0), Color(1.0, 1.0, 1.0, 1.0), 0.25, 
		Tween.TRANS_LINEAR, Tween.EASE_IN_OUT
	)
	_no_use = tween.start()
	#print(damage)

func poison(damage):
	self.health -= damage
	var _no_use
	_no_use = tween.interpolate_property(
		draw_pivot, "modulate", 
		Color(0.5, 1.0, 0.25, 1.0), Color(1.0, 1.0, 1.0, 1.0), 0.25, 
		Tween.TRANS_LINEAR, Tween.EASE_IN_OUT
	)
	_no_use = tween.start()

func hit():
	Audio.play_sound_random(["Swipe", "Swipe2"])
	if target_enemy == null:
		return
	#if damage_base > 0:
	#	target_enemy.hurt(damage_base)
	var current_weapon = weapon.get_child(0)
	for effect in current_weapon.effects.get_children():
		var new_effect = effect.duplicate()
		if new_effect.type == "Damage":
			new_effect.damage *= damage_base
		
		if target_enemy != null:
			target_enemy.add_effect(new_effect)
	
	#current_weapon.apply_effects(target_enemy)

func attack():
	if animation_player.current_animation != "AttackSwing":
		if target_enemy != null:
			target_enemy.target_enemy_attacked()
		animation_player.play("AttackSwing")
		var current_weapon = weapon.get_child(0)
		if current_weapon != null:
			animation_player.playback_speed = current_weapon.speed * agility_base
			
			for effect in current_effects.get_children():
				if effect.type == "Frost":
					animation_player.playback_speed /= 2
					break

func attack_animation_finished():
	animation_player.play("Idle")
	animation_player.playback_speed = 1
	can_block = false
	#print("Attack finished")

func block():
	if animation_player.current_animation != "Block":
		if target_enemy != null:
			target_enemy.target_enemy_blocked()
		animation_player.play("Block")
		animation_player.playback_speed = 1
		
		for effect in current_effects.get_children():
			if effect.type == "Frost":
				animation_player.playback_speed /= 2
				break

func block_effect():
	var effect = add_effect(BLOCK_EFFECT.instance())
	effect.damage_divider = block_damage_divider
	effect.life_timer.wait_time = 1
	effect.life_timer.start()

func flip_h(value: bool):
	draw_pivot.scale.x = -1 if value else 1

func appear_animation(force):
	draw_pivot.position = Vector2.RIGHT * force
	var _no_use
	_no_use = tween.interpolate_property(
		draw_pivot, "position", Vector2.RIGHT * force, Vector2.ZERO, 0.5, 
		Tween.TRANS_ELASTIC, Tween.EASE_OUT
	)
	_no_use = tween.start()

func change_weapon(weapon_instance):
	if weapon_instance == null:
		return
	for child in weapon.get_children():
		child.queue_free()
	weapon.add_child(weapon_instance)

func die():
	Audio.play_sound_random(["Meaty", "Meaty2", "Meaty3"])
	if Global.battle_node != null:
		var inst = DEATH_PARTICLE.instance()
		inst.global_position = global_position
		Global.battle_node.add_child(inst)
	
	give_awards()
	
	#print("I'm dead, dude. ", name)
	emit_signal("dead")
	is_dead = true
	queue_free()

func set_health(value):
	health = min(value, max_health)
	$Label.text = str(int(health)) + "/" + str(max_health)
	healthbar.value = health
	#$Label.value = value
	if health < 1 and not is_dead:
		die()

func target_enemy_attacked():
	pass

func target_enemy_blocked():
	pass

func target_enemy_dead():
	target_enemy = null
	if get_node_or_null("Timer") != null:
		$Timer.stop()

func add_effect(new_effect: Node):
	for old_effect in current_effects.get_children():
		#print(self.name, " new EFFECT: ", new_effect.name, " ", new_effect.type)
		#print(self.name, " old EFFECT: ", old_effect.name, " ", old_effect.type)
		#print("##### ", old_effect.get_index())
		if old_effect.type == new_effect.type:
			old_effect.queue_free()
			#print(old_effect.name, " is already exists")
		elif (old_effect.type == "Armor" or old_effect.type == "Block") \
		and new_effect.type == "Damage":
			new_effect.damage /= old_effect.damage_divider
			Audio.play_sound("Block")
			print("blocked! ", new_effect.damage)
	
	current_effects.add_child(new_effect)
	new_effect.target = self
	new_effect.init()
	
	icons_updated()
	var _no_use = new_effect.connect("tree_exited", self, "icons_updated")
	
	return new_effect

func icons_updated():
	$EffectIcons.effect_icons.clear()
	var effects = current_effects.get_children()
	for effect in effects:
		if effect.icon.a != 0.0:
			$EffectIcons.effect_icons.append(effect.icon)
	$EffectIcons.update()
