extends Area2D
class_name Demon

@onready var sprite: AnimatedSprite2D = $AnimatedSprite2D
@onready var vision: ShapeCast2D = $Vision
@onready var vision_polygon: Polygon2D = $Vision/Polygon2D

@onready var gun_shot_sound: AudioStreamPlayer = $GunShotSound

@export var shot_probability: float = 0.5
var sp_modifier: float = 0.0

var ammo: int = 0

enum State {
	STATE_IDLE,
	STATE_SHOOTING,
	STATE_RELOADING,
}
var state: State = State.STATE_IDLE

var is_being_dragged: bool = false

func _ready() -> void:
	ammo = Game.max_ammo

func _process(_delta: float) -> void:
	vision_polygon.visible = GlobalInput.visible_vision

func _physics_process(_delta: float) -> void:
	if state != State.STATE_IDLE:
		return
		
	vision.force_shapecast_update()
	if not vision.is_colliding():
		return
	
	var foe = vision.get_collider(0)
	if foe == null || not (foe is Area2D) || not foe.visible:
		return
	
	var value = randf()
	var actual_probability = shot_probability + sp_modifier
	if value <= actual_probability:
		sp_modifier = 0.0
		await shoot_at(foe as Area2D)
	else:
		sp_modifier += 0.1
		print("%s: not shooting (%.2f > %.2f)" % [name, value, actual_probability])

func _on_mouse_entered():
	if not GlobalInput.is_dragging():
		# TODO: add custom cursor image
		Input.set_custom_mouse_cursor(null, Input.CURSOR_MOVE)

func _on_mouse_exited():
	if not GlobalInput.is_dragging():
		# TODO: add custom cursor image
		Input.set_custom_mouse_cursor(null, Input.CURSOR_ARROW)

func _on_input_event(_viewport: Node, event: InputEvent, _shape_idx: int):
	if event is InputEventMouseButton:
		handle_click(event)

func handle_click(event: InputEventMouseButton):
	if event.button_index != MOUSE_BUTTON_LEFT:
		return
	
	if event.pressed && not GlobalInput.is_dragging():
		is_being_dragged = true
		GlobalInput.start_dragging(self)
	elif not event.pressed && is_being_dragged:
		is_being_dragged = false
		GlobalInput.stop_dragging()

func reload() -> void:
	state = State.STATE_RELOADING
	print("%s: reloading (%.2f seconds)" % [name, Game.reload_time])
	await get_tree().create_timer(Game.reload_time).timeout
	print(name + ": done reloading")
	ammo = Game.max_ammo
	state = State.STATE_IDLE

func shoot_at(foe: Area2D) -> void:
	if state != State.STATE_IDLE:
		return
	
	print("%s: Ammo = %d/%d" % [name, ammo, Game.max_ammo])
	
	if ammo <= 0:
		await reload()
	else:
		state = State.STATE_SHOOTING
		ammo -= 1
		gun_shot_sound.play()
		sprite.play("shoot")
		
		var distance: float = clampf((foe.global_position - global_position).length(), 140.0, 250.0)
		var distance_percent: float = 1.0 - ((distance - 140.0) / 110.0)
		#print(distance_percent)
		var speed: float = minf(foe.speed, 100.0)
		var speed_percent: float = 1.0 - ((speed - 64.0) / 36.0)
		#print(speed_percent)
		var base = Game.base_accuracy
		var rest = (1.0 - base) / 2.0
		var hit_chance: float = Game.base_accuracy + distance_percent * rest + speed_percent * rest
		print("%s: Shooting at %s with %.2f hit chance" % [name, foe.name, hit_chance])
		
		var hit: float = randf()
		if hit > hit_chance:
			print("%s: missed shot (%.2f > %.2f)" % [name, hit, hit_chance])
		else:
			if foe.has_method("die"):
				foe.die()
			else:
				foe.queue_free()
		
		await sprite.animation_finished
		if ammo <= 0:
			await reload()
		else:
			state = State.STATE_IDLE

func _on_animation_finished():
	sprite.animation = "idle"
	sprite.frame = 0
	
