extends RigidBody2D

var initial_self_position: Vector2 = Vector2.ZERO
var initial_mouse_position: Vector2 = Vector2.ZERO

@onready var rand_walk_timer: Timer = Timer.new()
var rng = RandomNumberGenerator.new()
enum State {STATE_IDLE, STATE_WALK, STATE_PICKED, STATE_RUN, STATE_THROWN}
var state: State = State.STATE_IDLE
var walk_dir: Vector2 = Vector2.ZERO
var last_dir: int = 1
var last_mouse_pos: Vector2 = Vector2.ZERO


@export var min_run_dist = 200
@export var max_run_dist = 250

@export var walk_speed = 150
@export var run_speed = 500

@export var drag_damp = 40
@export var normal_damp = 4
@export var thrown_damp = 2


# Called when the node enters the scene tree for the first time.
func _ready():
	add_child(rand_walk_timer)
	rand_walk_timer.one_shot = true;
	rand_walk_timer.connect("timeout", _on_timer_timeout)
	init_timer()

func init_timer():
	if state == State.STATE_IDLE:
		var rand_time = max(0, rng.randfn(4, 1.5))
		rand_walk_timer.start(rand_time)
	elif state == State.STATE_WALK:
		rand_walk_timer.start(5)


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
	# Update state
	var curr_mpos = get_viewport().get_mouse_position()
	last_mouse_pos = curr_mpos
	
	if state == State.STATE_PICKED and not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):
		pick_down()

	var mouse_dis = position.distance_to(curr_mpos)
	if (state == State.STATE_IDLE or state == State.STATE_WALK) and mouse_dis < min_run_dist:
		# Run away from mouse
		state = State.STATE_RUN
		rand_walk_timer.stop()
	elif state == State.STATE_RUN and mouse_dis > max_run_dist:
		state = State.STATE_IDLE
		init_timer()

func _physics_process(delta):
	gravity_scale = 0
	if state == State.STATE_THROWN and linear_velocity.length() < 300:
		linear_velocity = Vector2.ZERO
		state = State.STATE_WALK
		init_timer()
	
	var force = Vector2.ZERO

	if state == State.STATE_WALK:
		force = walk_speed * walk_dir
	elif state == State.STATE_RUN:
		var run_dir = -position.direction_to(last_mouse_pos)
		force = run_speed * run_dir
	elif state == State.STATE_PICKED:
		var dest_position = initial_self_position +  (last_mouse_pos - initial_mouse_position)
		apply_central_force(50 * (dest_position - position) * dest_position.distance_to(position) * delta)
	else:
		pass

	if force.length_squared() > 0.001:
		apply_central_force(force)
		last_dir = sign(force.dot(Vector2.LEFT))

	scale.x = last_dir

	if state == State.STATE_PICKED:
		linear_damp = drag_damp
	elif state == State.STATE_THROWN:
		linear_damp = thrown_damp
	else:
		linear_damp = normal_damp


func _on_input_event(viewport, event, shape_idx):
	if event is InputEventMouseButton:
		var was_picked_up = state == State.STATE_PICKED
		var is_picked_up = event.pressed
		initial_mouse_position = event.position
		initial_self_position = position

		if not was_picked_up and is_picked_up:
			state = State.STATE_PICKED
			rand_walk_timer.stop()
		elif was_picked_up and not is_picked_up:
			pick_down()

func pick_down():
	state = State.STATE_THROWN
	init_timer()


func _on_timer_timeout():
	if state == State.STATE_IDLE:
		state = State.STATE_WALK
		walk_dir = Vector2.from_angle(rng.randf_range(0, 2*PI))
	elif state == State.STATE_WALK:
		state = State.STATE_IDLE
	init_timer()