class_name AICharacter 
extends CharacterBody2D

@export var player_character: PlayableCharacter
@export var health = 100
@export var attack_power = 30
@export var KNOCKBACK_POWER = 40
@export var KNOCKBACK_REPOSITION_POWER = 75
@export var KNOCKBACK_RANDOMNESS = 50
@export var MELEE_RADIUS = 75
@onready var anim_tree: AnimationTree = $AnimationTree
@onready var anim_playback: AnimationNodeStateMachinePlayback = anim_tree["parameters/playback"]
@onready var state_machine: StateChart = $StateMachine

var timer = 0

# Getting hurt variables
var attacked_from = Vector2.ZERO
var received_damage = 0
var hit_counter = 0
var attack_counter = 0
var attack_counter_limit = 0

var wants_to_melee = false

signal _got_hurt(damage: int, attack_direction: Vector2)
signal attack_did_hit(other: Area2D, power: int, attack_direction: Vector2)
signal defeated

func _ready():
	state_machine.set_expression_property("melee_stage", 0)

func set_animation_direction(facing_direction: Vector2):
	anim_tree.set("parameters/idle/blend_position", facing_direction)
	anim_tree.set("parameters/walk/blend_position", facing_direction)
	anim_tree.set("parameters/melee/0/blend_position", facing_direction)
	anim_tree.set("parameters/melee/1/blend_position", facing_direction)
	anim_tree.set("parameters/melee/2/blend_position", facing_direction)
	anim_tree.set("parameters/hurt/blend_position", facing_direction)
	
func follow_player(speed: float):
	var approach_direction = position.direction_to(player_character.position)
	velocity = speed * approach_direction
	set_animation_direction(approach_direction)

func _physics_process(_delta):
	move_and_slide()

func _on_player_attack_did_hit(other, attack_power: int, attack_direction: Vector2):
	if other.get_parent().get_instance_id() == get_instance_id() :
		_on_ai_got_hurt(attack_power, attack_direction)
		_got_hurt.emit(attack_power, attack_direction)

func _on_ai_got_hurt(attack_power: int, attack_direction: Vector2):
	attacked_from = attack_direction
	received_damage = attack_power
	$Attackbox/Collider.set_deferred("disabled", true)
	state_machine.send_event("been_hurt")

## Thinking state
## Once some time passes out, do_thinking is called
func _on_think_state_entered():
	timer = randf_range(3.0/60.0, 1.5)
	if timer <= 88.0/90.0:
		timer = timer * 0.75

func _on_think_state_processing(delta):
	timer -= delta
	if timer <= 0:
		do_thinking()

## This function actually determines what to do	
func do_thinking():
	var distance = position.distance_to(player_character.position)
	if distance > MELEE_RADIUS:
		state_machine.set_expression_property("melee_stage", 0)
		# range attacks here
	else:
		state_machine.send_event("wants_tomelee")

func _on_hurt_state_entered():
	var facing_direction = attacked_from * -1
	health = health - received_damage
	hit_counter = hit_counter + 1
	
	
	# 1. If hit_counter variable >= 4, then you need to make the state_machine
	# #  1.1  send an event "will_reposition"
	# 2. On the Hurt state, make a State transition node, name it "ToHurtReposition"
	# # 2.1 Set its transition node to HurtReposition
	# # 2.2 Set its event to "will_reposition"
	# 3. On the HurtReposition, make another State transition node, name it "ToThink"
	# # 3.1 Set its transition node to Think
	# # 3.2 Set its event to "hurt_complete"
	# 4. On the HurtReposition node, connect the signals state_entered() and state_exited() to
	# _on_hurt_reposition_state_entered() and _on_hurt_reposition_state_exited() respectively
	# 5. Inside the _on_hurt_reposition_state_entered() function,
	# you need to reset hit_counter back to 0.
	
	if health <= 0:
		state_machine.send_event("been_defeated")
		defeated.emit()
	
	if hit_counter >= 4:
		state_machine.send_event("will_reposition")
	else:
		set_animation_direction(facing_direction)
		anim_playback.travel("hurt")
		var knockback_direction = attacked_from.rotated(deg_to_rad(randf_range(-1, 1) * KNOCKBACK_RANDOMNESS))
		velocity = KNOCKBACK_POWER * knockback_direction.normalized()
		
		state_machine.set_expression_property("melee_stage", 0)
	
func _on_hurt_state_exited():
	velocity = Vector2.ZERO
	
func _on_hurt_reposition_state_entered():
	var facing_direction = attacked_from * -1
	set_collision_layer_value(5, true)
	set_collision_layer_value(1, false)
	set_collision_mask_value(5, true)
	set_collision_mask_value(1, false)
	#$MovementCollider.set_deferred("disabled", true)
	set_animation_direction(facing_direction)
	anim_playback.travel("hurt")
	velocity = attacked_from * KNOCKBACK_REPOSITION_POWER * -1
	
func _on_hurt_reposition_state_exited():
	velocity = Vector2.ZERO
	set_collision_layer_value(5, false)
	set_collision_layer_value(1, true)
	set_collision_mask_value(5, false)
	set_collision_mask_value(1, true)
	#$MovementCollider.set_deferred("disabled", false)
	hit_counter = 0

func _on_animation_tree_animation_finished(anim_name):
	if anim_name.contains("hurt"):
		state_machine.send_event("hurt_complete")
	elif (anim_name.contains("kick") or anim_name.contains("punch")):
		attack_counter = attack_counter + 1
		wants_to_melee = wants_to_melee and attack_counter < attack_counter_limit
		if wants_to_melee:
			var animation_rng = randf_range(0, 1)
			anim_tree.set("parameters/melee/blend_position", animation_rng)
			anim_tree.set("parameters/conditions/melee", true)
		else:
			state_machine.send_event("melee_complete")

func _on_defeat_state_entered():
	if Globals.nsfw:
		anim_playback.travel("naked_start")
	else:
		anim_playback.travel("defeated")

## Aproaching
func _on_approach_state_entered():
	follow_player(25)
	anim_tree.set("parameters/conditions/is_moving", true)
	timer = 1

func _on_approach_state_processing(delta):
	timer -= delta
	if timer < 0:
		state_machine.send_event("approach_complete")


func _on_approach_state_exited():
	anim_tree.set("parameters/conditions/is_moving", false)
	velocity = Vector2.ZERO


func _on_approach_to_think_taken():
	state_machine.set_expression_property("melee_stage", 1)

## Chasing
func _on_chase_state_entered():
	anim_tree.set("parameters/conditions/is_moving", true)

func _on_chase_state_processing(_delta):
	follow_player(65)
	var distance = position.distance_to(player_character.position)
	if distance >= MELEE_RADIUS:
		state_machine.send_event("melee_aborted")

func _on_chase_state_exited():
	anim_tree.set("parameters/conditions/is_moving", false)
	velocity = Vector2.ZERO

func _on_chase_to_think_taken():
	state_machine.set_expression_property("melee_stage", 0)

## Melee
func _on_meleebox_body_entered(body):
	if body == player_character:
		wants_to_melee = true
		state_machine.send_event("will_melee")

func _on_melee_state_entered():
	attack_counter = 0
	attack_counter_limit = randi_range(3, 5)
	anim_tree.set("parameters/conditions/melee", true)
	state_machine.set_expression_property("melee_stage", 0)

func _on_meleebox_body_exited(body):
	if body == player_character:
		wants_to_melee = false

func _on_melee_state_processing(_delta):
	follow_player(0)

func _on_melee_state_exited():
	anim_tree.set("parameters/conditions/melee", false)


func _on_attackbox_area_entered(area):
	attack_did_hit.emit(area, attack_power, anim_tree.get("parameters/melee/0/blend_position"))


func _on_victory_state_entered():
	wants_to_melee = false
	anim_tree.set("parameters/conditions/melee", false)
	state_machine.set_expression_property("melee_stage", 0)
	velocity = Vector2.ZERO


func _on_player_been_defeated():
	state_machine.send_event("has_won")
