extends CharacterBody2D

class_name MainPlayer

enum MOVEMENT_STATUS {
	IDLE,
	WALKING,
	RUNNING,
	LAYING_STAY,
	LAYING_MOVING,
	CLIMBING_STAY,
	CLIMBING,
}

@export var action_locked := false:
	set(val):
		action_locked = val
		_process_action_lock()
@export var current_status : MOVEMENT_STATUS
@export var facing_direction := Vector2(1.0, -1.0)
@export var is_laying := false:
	set(val):
		is_laying = val
		# reset the facing direction wether the player is laying or not.
		_reset_face_direction()
		if is_laying:
			is_climbing = false
@export var is_climbing := false:
	set(val):
		is_climbing = val
		# reset the facing direction wether the player is climbing or not.
		_reset_face_direction()
		if is_climbing:
			is_laying = false
@export var running_locked := false
@export var speed_walking := 300.0
@export var speed_runnig := 500.0
@export var speed_laying := 150.0
@export var speed_climbing := 170.0
#const JUMP_VELOCITY = -400.0

@onready var camera = %MainCamera as Camera2D
@onready var sprite = %AnimatedSprite2D as AnimatedSprite2D

func _ready() -> void:
	_reset_face_direction()

func _reset_face_direction() -> void:
	facing_direction = Vector2(1, -1)

func _process_action_lock() -> void:
	# reset status to idle or stay
	if action_locked:
		if current_status == MOVEMENT_STATUS.WALKING or current_status == MOVEMENT_STATUS.RUNNING:
			current_status = MOVEMENT_STATUS.IDLE
		elif current_status == MOVEMENT_STATUS.LAYING_MOVING:
			current_status = MOVEMENT_STATUS.LAYING_STAY
		elif current_status == MOVEMENT_STATUS.CLIMBING:
			current_status = MOVEMENT_STATUS.CLIMBING_STAY
	_play_animation()

# return whether the player status or facing direction has changed.
func _check_status(direction) -> bool:
	var tmp_status = current_status
	var new_facing_direction := facing_direction
	if is_laying:
		if direction.x:
			new_facing_direction.x = direction.x
			tmp_status = MOVEMENT_STATUS.LAYING_MOVING
		else:
			tmp_status = MOVEMENT_STATUS.LAYING_STAY
	elif is_climbing:
		if direction.y:
			new_facing_direction.y = direction.y
			tmp_status = MOVEMENT_STATUS.CLIMBING
		else:
			tmp_status = MOVEMENT_STATUS.CLIMBING_STAY
	else:
		if direction.x:
			new_facing_direction.x = direction.x
			tmp_status = MOVEMENT_STATUS.WALKING
			if !running_locked and Input.is_action_pressed("run"):
				tmp_status = MOVEMENT_STATUS.RUNNING
		else:
			tmp_status = MOVEMENT_STATUS.IDLE
	if new_facing_direction != facing_direction or tmp_status != current_status:
		facing_direction = new_facing_direction
		current_status = tmp_status
		return true
	return false

func _play_animation() -> void:
	match current_status:
		MOVEMENT_STATUS.IDLE:
			if facing_direction.x > 0.0:
				sprite.play(&"idle_r")
			else:
				sprite.play(&"idle_l")
		MOVEMENT_STATUS.WALKING:
			if facing_direction.x > 0.0:
				sprite.play(&"walking_r")
			else:
				sprite.play(&"walking_l")
		MOVEMENT_STATUS.RUNNING:
			if facing_direction.x > 0.0:
				sprite.play(&"running_r")
			else:
				sprite.play(&"running_l")
		MOVEMENT_STATUS.LAYING_STAY:
			if facing_direction.x > 0.0:
				sprite.play(&"laying_stay_r")
			else:
				sprite.play(&"laying_stay_l")
		MOVEMENT_STATUS.LAYING_MOVING:
			if facing_direction.x > 0.0:
				sprite.play(&"laying_moving_r")
			else:
				sprite.play(&"laying_moving_l")
		MOVEMENT_STATUS.CLIMBING_STAY:
			sprite.play(&"climbing_stay")
		MOVEMENT_STATUS.CLIMBING:
			if facing_direction.y > 0.0:
				sprite.play(&"climbing_down")
			else:
				sprite.play(&"climbing_up")

func _get_speed(direction: Vector2) -> Vector2:
	match current_status:
		MOVEMENT_STATUS.WALKING:
			return Vector2(speed_walking * direction.x, 0.0)
		MOVEMENT_STATUS.RUNNING:
			return Vector2(speed_runnig * direction.x, 0.0)
		MOVEMENT_STATUS.LAYING_MOVING:
			return Vector2(speed_laying * direction.x, 0.0)
		MOVEMENT_STATUS.CLIMBING:
			return Vector2(0, speed_climbing * direction.y)
	return Vector2(0, 0)

func _physics_process(_delta: float) -> void:
	if action_locked:
		velocity = Vector2.ZERO
		return

	# Add the gravity.
	#if not is_on_floor():
		#velocity += get_gravity() * delta
	#if Input.is_action_just_pressed("jump") and is_on_floor():
		#velocity.y = JUMP_VELOCITY
	var x_direction := Input.get_axis("left", "right")
	var y_direction := Input.get_axis("up", "down")
	var direction := Vector2(x_direction, y_direction)
	if _check_status(direction):
		_play_animation()
	var speed := _get_speed(direction) as Vector2
	velocity.x = move_toward(velocity.x, speed.x, 300.0)
	velocity.y = move_toward(velocity.y, speed.y, 300.0)
	move_and_slide()
	_tweak_camera_marker()

# drag the camera marker against the player movement
# so there will be a better vision in front of the player.
func _tweak_camera_marker():
	var marker = get_node("./CameraFocusMarker") as Node2D
	if marker:
		marker.position.x = facing_direction.x * abs(velocity.x) * 0.11
		marker.position.y = facing_direction.y * abs(velocity.y) * 0.11
