class_name Player
extends CharacterBody2D

# Player States
enum State {
	IDLE,
	RUN,
	JUMP,
	ATTACK_1,
	ATTACK_2,
	ATTACK_3,
	HEAVY_ATTACK,
	DASH,
	DASH_ATTACK,
	DEFEND,
	HURT,
	DEATH,
}

# Player Runtime Variables
var direction: float = 0.0
var facing_direction: float = 1.0
var current_state: State = State.IDLE
var is_attacking: bool = false
var combo_step: int = 0
var combo_timer: float = 0.0

@onready var _sprite: AnimatedSprite2D = $AnimatedSprite2D

# Player Exported Variables
@export_group("Movement")
@export var move_speed: float = 200.0

@export_group("Jump")
@export var jump_velocity: float = -300.0
@export var gravity_scale: float = 1.0

@export_group("Combat")
@export var attack_cooldown: float = 0.4
@export var heavy_attack_cooldown: float = 0.6
@export var combo_window: float = 0.6
@export var attack_move_speed: float = 0.0

@export_group("Dash")
@export var dash_speed: float = 500.0
@export var dash_cooldown: float = 0.8

func _ready() -> void:
	_sprite.animation_finished.connect(_on_animation_finished)

func _physics_process(delta: float) -> void:
	_apply_gravity(delta)
	_apply_movement(delta)
	_process_attack_input()
	_update_combo_timer(delta)
	_update_state()
	_update_animation()
	move_and_slide()

func _apply_gravity(delta: float) -> void:
	if not is_on_floor():
		velocity.y += ProjectSettings.get_setting("physics/2d/default_gravity") * gravity_scale * delta

func _apply_movement(delta: float) -> void:
	if is_attacking:
		velocity.x = facing_direction * attack_move_speed
		return

	direction = Input.get_axis("move_left", "move_right")
	velocity.x = direction * move_speed
	if direction != 0.0:
		facing_direction = direction

	if is_on_floor() and Input.is_action_just_pressed("jump"):
		velocity.y = jump_velocity

func _process_attack_input() -> void:
	if is_attacking or not Input.is_action_just_pressed("light_attack"):
		return

	if combo_step > 0 and combo_timer > 0.0:
		combo_step += 1
	else:
		combo_step = 1

	is_attacking = true
	combo_timer = 0.0
	current_state = State.values()[State.ATTACK_1 + combo_step - 1]

func _update_combo_timer(delta: float) -> void:
	if combo_timer > 0.0:
		combo_timer -= delta
		if combo_timer <= 0.0:
			combo_step = 0

func _on_animation_finished() -> void:
	if not is_attacking:
		return

	is_attacking = false
	if current_state == State.ATTACK_3:
		combo_step = 0
	else:
		combo_timer = combo_window

func _update_state() -> void:
	if is_attacking:
		return

	if not is_on_floor():
		current_state = State.JUMP
	elif direction != 0.0:
		current_state = State.RUN
	else:
		current_state = State.IDLE

func _update_animation() -> void:
	var animation_name: String = State.keys()[current_state].to_lower()
	if _sprite.animation != animation_name:
		_sprite.play(animation_name)
	_sprite.flip_h = facing_direction < 0.0
