extends KinematicBody

#Constants
const GRAVITY = -30
const AIR_FRICTION = Vector3(0.9,1,0.9)
const MAX_SLOPE_ANGLE = 75

#Camera settings
var camera_angle = 0
var mouse_sensitivity = 0.15
var camera_change = Vector2()
var cam_bob = 0
var cam_bob_max = 0
var cam_bob_multiplier = 1
var default_fov = 80
var render_distance = 5000

#General Variables
var dead = false
var iframes = false

#Counters, Checkers, and Initializers
onready var start_time = OS.get_ticks_msec()
var cam_init
var is_walking = true
var is_cutscene = false

#Interaction Variables
var action = ""
var text = ""

#Movement Vars
var velocity = Vector3()
var dir = Vector3()
var friction = 1
var jump_height = 10

#Movement Speeds
enum MOVE_VARS {
	SPEED = 8,
	ACCEL = 8,
	DEACCEL = 11,
}

enum RUN_VARS {
	SPEED = 4,
	ACCEL = 12,
	DEACCEL = 10,
}

enum FLY_VARS {
	SPEED = 35,
	ACCEL = 5,
}

#Misc
onready var lookat : Node = $Lookingat


#Equipment
var has_flashlight = true
var using_flashlight = false



#Hide self, capture mouse, and initialize
func _ready():
	$MeshInstance.hide()
	Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
	$Head/Camera.far = render_distance
	cam_init = $Head/Camera.translation.y
	$Head/Flashlight.visible = using_flashlight
	


#Check between normal and noclip modes
func _physics_process(delta):
	if is_walking:
		if !dead:
			walk(delta)
	else:
		fly(delta)
		
		
func _input(event):
	#Aim when the mouse is moved
	if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
		$Head.rotate_x(deg2rad(event.relative.y * mouse_sensitivity * -1))
		self.rotate_y(deg2rad(event.relative.x * mouse_sensitivity * -1))
		
		var camera_rot = $Head.rotation_degrees
		camera_rot.x = clamp(camera_rot.x, -89, 89)
		$Head.rotation_degrees = camera_rot
	
	#Toggle between walking and noclip
	if Input.is_action_just_pressed("fly"):
		is_walking = !is_walking
		$CollisionShape.disabled = !is_walking
		
	
	#Toggle flashlight
	if Input.is_action_just_pressed("flashlight"):
		if has_flashlight:
			using_flashlight = !using_flashlight
			$Head/Flashlight.visible = using_flashlight
		
		
	#Interact	
	if Input.is_action_just_pressed("interact"):
		if action != "":
			var interacter = lookat.get_collider()
			if interacter.has_method("interact"):
				if interacter.is_in_group("sign"):
					text = lookat.get_collider().interact()
				else:
					lookat.get_collider().interact()


func _process(delta):
	#Bob the camera while walking
	cam_bob = sin((OS.get_ticks_msec()-start_time)/(100/cam_bob_multiplier))*(cam_bob_max)
	$Head/Camera.translation.y = cam_init + cam_bob
	
	if lookat.is_colliding():
		if lookat.get_collider() != null:
			if lookat.get_collider().is_in_group("interactable"):
				action = lookat.get_collider().action
	else:
		action = ""

	update_hud()
	
	#Reload the scene if the player falls out of the map
	if translation.y <= -200:
		get_tree().reload_current_scene()


func walk(delta):
	#Reset direction every frame
	dir = Vector3()
	
	#Walk
	var cam_xform = $Head/Camera.get_global_transform()
	var input_movement_vector = Vector2()
	
	if Input.is_action_pressed("ui_up"):
		input_movement_vector.y += 1
	if Input.is_action_pressed("ui_down"):
		input_movement_vector.y -= 1
	if Input.is_action_pressed("ui_left"):
		input_movement_vector.x -= 1
	if Input.is_action_pressed("ui_right"):
		input_movement_vector.x += 1
		
	input_movement_vector = input_movement_vector.normalized()

	dir += -cam_xform.basis.z * input_movement_vector.y
	dir += cam_xform.basis.x * input_movement_vector.x
		
	var floor_normal = $RayCast.get_collision_normal()
	
#	if is_on_floor():
#		jumping = false
#		friction = 1
#		if Input.is_action_just_pressed("ui_select"):
#			velocity.y = jump_height
#			velocity = move_and_slide_with_snap(velocity, Vector3.ZERO, Vector3.UP,true)
#	else:
#		friction = AIR_FRICTION

	dir.y = 0
	dir = dir.normalized()

	if !is_on_floor():
		velocity.y += GRAVITY * delta
	
	var hvelocity = velocity
	hvelocity.y = 0
	
	# Speed Setup
	var speed = MOVE_VARS.SPEED
	var accel
	var accelspeed = MOVE_VARS.ACCEL
	var deccelsepeed = MOVE_VARS.DEACCEL
	$Head/Camera.fov = lerp($Head/Camera.fov, default_fov, 0.5)
	set_camera_bob(0.2,1.5)

	# Run
	if Input.is_action_pressed("silent") and (dir.x != 0 or dir.y != 0):
		speed = RUN_VARS.SPEED
		accelspeed = RUN_VARS.ACCEL
		deccelsepeed = RUN_VARS.DEACCEL
		$Head/Camera.fov = lerp($Head/Camera.fov, default_fov-8, 0.5)
		set_camera_bob(0.1,1.0)

	# Do final checks then move
	if dir.dot(hvelocity) > 0:
		accel = accelspeed
	else:
		accel = deccelsepeed
	
	var target = dir * speed
	
	hvelocity = hvelocity.linear_interpolate(target, accel * delta)
	velocity.x = hvelocity.x
	velocity.z = hvelocity.z
	
	#Dont bob the camera under certain conditions
	if is_on_wall() or !is_on_floor() or (input_movement_vector.x == 0 and input_movement_vector.y == 0):
		set_camera_bob(0)
	
	velocity = move_and_slide_with_snap(velocity*friction, -floor_normal, Vector3.UP, true, 4)
	

func fly(delta):
	set_camera_bob(0,1)
	
	#Reset direction every frame
	dir = Vector3()
	
	#Get the direction of the camera and walk relative to looking direction
	var aim = $Head/Camera.get_global_transform().basis

	if Input.is_action_pressed("ui_up"):
		dir -= aim.z
	if Input.is_action_pressed("ui_down"):
		dir += aim.z
	if Input.is_action_pressed("ui_left"):
		dir -= aim.x
	if Input.is_action_pressed("ui_right"):
		dir += aim.x
		
	dir = dir.normalized()
	
	#Do some setup then move
	var target = dir * FLY_VARS.SPEED
	velocity = velocity.linear_interpolate(target,FLY_VARS.ACCEL*delta)
	
	move_and_slide(velocity)
	
	
func update_hud():
	pass


func set_camera_bob(maximum=0,multiplier=1):
	cam_bob_max = maximum/1.5
	cam_bob_multiplier = multiplier
	
	
func cutscene_mode(cutscene = true, show_self = false):
	print("bruh")
	is_cutscene = cutscene
	if is_cutscene:
		hide_hud(true)		
	elif !is_cutscene:
		hide_hud(false)
		
	$MeshInstance.visible = show_self
		
		
func hide_hud(hide = true):
	if hide:
		for child in $Head/CanvasLayer.get_children():
			child.visible = false
			
	if !hide:
		for child in $Head/CanvasLayer.get_children():
			child.visible = true	
