extends CharacterBody2D

# ActionState should probably be expandable to
enum ActionState {None, Cycling, Firing, Charging}
enum MoveState {Still, Moving, Dashing, Knockback}

@export var speed = 200 # How fast the player will move (pixels/sec).
@export var dash_cooldown = 0.3
@export var hand_size = 3

@onready var camera: Camera2D = %PlayerCamera
@onready var sprite: AnimatedSprite2D = $PlayerSprite

var shield_active = true;
var move_direction = Vector2.ZERO;
var target = Vector2.ZERO # The position of the player's cursor.

const drawpile = [];
@export var hand = [];
const discard_pile = [];
var active_card_index = -1;

var screen_size # Size of the game window.
var action_state = ActionState.None
var move_state = MoveState.Still

var charge_level = 0;
var charge_rate = 1;
var charged = false;

var dash_cooldown_timer = 0;
var dash_on_cooldown = false;

func get_target_pos():
	return self.get_global_mouse_position()

func update_move_direction():
	move_direction = Vector2.ZERO
	if Input.is_action_pressed("move_right"):
		move_direction.x += 1
	if Input.is_action_pressed("move_left"):
		move_direction.x -= 1
	if Input.is_action_pressed("move_down"):
		move_direction.y += 1
	if Input.is_action_pressed("move_up"):
		move_direction.y -= 1
	move_direction = move_direction.normalized()

func update_target_coords():
	target = get_viewport().get_mouse_position()
	sprite.look_at(get_global_mouse_position())

func update_camera_position():
	if not camera:
		return;
	var camera_target = (target - screen_size / 2) / 2
	camera.position = camera.position.lerp(camera_target, 0.1)

func charge():
		# Charge attack
	if not charged and action_state == ActionState.Charging:
		charge_level += charge_rate;
		if charge_level >= 100:
			charged = false;
			charge_level = 0;
	elif charge_level > 0:
		# Gradual charge dropoff
		charge_level = max(charge_level - charge_rate * 2, 0);

func dash():
	var card = hand.get(active_card_index);
	if not card or dash_on_cooldown:
		return;
	
	card.discard(self); # Must set move_state at start and end of dash
	dash_on_cooldown = true;

func play_card():
	if active_card_index >= 0 and active_card_index < hand.size():
		var card = hand[active_card_index];
		card.play(self);

func cycle_card(index_shift):
	if hand.size() > 0:
		active_card_index = (active_card_index + index_shift) % hand.size();
	else:
		draw_card();

func discard_active_card():
	if active_card_index >= 0 and active_card_index < hand.size():
		var card = hand[active_card_index];
		discard_pile.append(card);
		hand.remove_at(active_card_index);
		active_card_index = min(active_card_index, hand.size() - 1);
		draw_card();

func draw_card():
	if drawpile.size() == 0:
		shuffle_deck();
	if drawpile.size() > 0 and hand.size() < hand_size:
		var card = drawpile.pop_back();
		hand.append(card);
		if active_card_index == -1:
			active_card_index = 0;

# TODO: Reboot mechanics
func shuffle_deck():
	for card in discard_pile:
		drawpile.append(card);
	discard_pile.clear();
	drawpile.shuffle();
	active_card_index = 0;

func _ready():
	screen_size = get_viewport_rect().size
	while (hand.size() < hand_size and drawpile.size() > 0):
		draw_card();

func _process(delta):
	update_target_coords();
	update_camera_position();
	if (move_state != MoveState.Dashing):		
		update_move_direction();

	if (dash_on_cooldown):
		dash_cooldown_timer += delta;
		if (dash_cooldown_timer >= dash_cooldown):
			dash_on_cooldown = false;
			dash_cooldown_timer = 0;

	# handle move_state
	if move_state == MoveState.Knockback:
		pass
	elif Input.is_action_just_pressed("dash"):
		dash();
	elif (move_state != MoveState.Dashing):
		velocity = move_direction * speed;
		if velocity.x || velocity.y:
			move_state = MoveState.Moving;
		else:
			move_state = MoveState.Still;

	move_and_slide();
	
	# Handle action_state
	if Input.is_action_pressed("play_card"):
		play_card();
		
	if Input.is_action_just_pressed("cycle_card_left"):
		action_state = ActionState.Cycling;
		cycle_card(-1);
	elif Input.is_action_just_pressed("cycle_card_right"):
		action_state = ActionState.Cycling;
		cycle_card(1);
