extends Node3D

const CONFIG_PATH = "weapons.cfg"

@export var player_root : CharacterBody3D
@onready var raycast = get_node("../Camera3D/AimCast") as RayCast3D
#@onready var crosshair = $Crosshair

var ALL_WEAPONS = {}
var weapons = []

var current_weapon_index = 0
var current_weapon = null

var mouse_mov : Vector3
var sway_lerp = 5

func _ready():
	get_tree().get_current_scene().game_loaded.connect(init)

func init():
	var config = Runtimeloader.loadConfig(CONFIG_PATH) as ConfigFile
	if(config == null):
		return
		
	Init_Config(config)
	
	var init_config = get_tree().get_current_scene().init_config
	
	for w_name in  init_config.get_value("PLAYER", "starting_weapons"):
		GiveWeapon(w_name)


func GiveWeapon(weapon_name):
	if weapon_name in ALL_WEAPONS and not ALL_WEAPONS[weapon_name] in weapons:
		weapons.append(ALL_WEAPONS[weapon_name])
		ChangeWeapon(posmod(current_weapon_index, weapons.size()))

func TakeWeapon(weapon_name):
	if weapon_name in ALL_WEAPONS and ALL_WEAPONS[weapon_name] in weapons: 
		weapons.erase(ALL_WEAPONS[weapon_name])
		ChangeWeapon(posmod(current_weapon_index, weapons.size()))
		

func _input(event):
	if event is InputEventMouseMotion:
		mouse_mov.y = clampf(-event.relative.x, -0.1, 0.1)
		mouse_mov.x = clampf(event.relative.y, -0.1, 0.1)

func _unhandled_input(_event):
	if(weapons.size() == 0):
		return
		
	if weapons.size() > 1 && Input.is_action_just_released("wheel_up"):
		ChangeWeapon(posmod((current_weapon_index + 1),weapons.size()))
	if weapons.size() > 1 && Input.is_action_just_released("wheel_down"):
		ChangeWeapon(posmod(current_weapon_index - 1,weapons.size()))
	
	if Input.is_action_just_pressed("reload"):
		current_weapon.Reload()
	
func ChangeWeapon(i):
	if(current_weapon):
		current_weapon.hide()
	
	if(weapons.size() == 0):
		current_weapon = null
		return

	current_weapon_index = i
	current_weapon = weapons[current_weapon_index]
	current_weapon.show()
	current_weapon.init()
	raycast.target_position.z = -current_weapon.RAY_LEN

var time = 0
func _process(delta):
	if(current_weapon == null):
		return
	
	if Input.is_action_pressed("shoot") && current_weapon.Shoot():
		if(current_weapon.HITSCAN):
			HitScan()
		else:
			Projectile()
			
	if Input.is_action_just_released("shoot"):
		current_weapon.Release()
	
		
	#SWAY
	if mouse_mov != null && mouse_mov.length() > 0:
		current_weapon.MODEL.rotation = current_weapon.MODEL.rotation.lerp(mouse_mov, sway_lerp * delta)
		mouse_mov = Vector3.ZERO
	else:
		current_weapon.MODEL.rotation = current_weapon.MODEL.rotation.lerp(Vector3.ZERO, sway_lerp * delta) 
		
	#BOB
	if player_root.velocity.length() > 0:
		time += delta
		var bobOscillate = sin(time * 4 * (2 * PI)) * 0.01
		position.y = bobOscillate
		bobOscillate = sin(time * 4 * (PI) + PI/4) * 0.015
		position.x = bobOscillate
		

func HitScan():
	if(raycast.is_colliding()):
		var target = raycast.get_collider()
		print_debug("Hit target ", target.name, " with ", current_weapon.name, " ",current_weapon_index, ". Dealt damage ", current_weapon.DAMAGE)
		if(raycast.get_collision_mask_value(10)):
			if(target is Hitable):
				target.Hit(current_weapon.DAMAGE)
			

func Projectile():
	pass


func Init_Config(config):
	for weapon in config.get_sections():
		var root = Weapon.new()
		root.name = weapon
		
		var model_path = config.get_value(weapon, "MODEL") as String
		var weapon_model
		if(model_path.ends_with(".glb") or model_path.ends_with(".gltf")):
			weapon_model = Runtimeloader.load_gltf(model_path, root) as Node3D
		elif(model_path.ends_with(".tscn") or model_path.ends_with(".scn")):
			weapon_model = Runtimeloader.loadScene(model_path, root)
		else:
			printerr("Invalid file extension for "+ model_path)
			continue
			

		root.position = config.get_value(weapon, "HAND_POS")
		root.rotation = config.get_value(weapon, "HAND_ROT")
		root.hide()
		add_child(root)
		
		#Set Weapon Data
		root.MELEE = config.get_value(weapon, "MELEE")
		root.MAX_CLIP = config.get_value(weapon, "MAX_CLIP")
		root.clip = root.MAX_CLIP
		root.DAMAGE = config.get_value(weapon, "DAMAGE")
		root.RPM = config.get_value(weapon, "RPM")
		root.FIREMODE = config.get_value(weapon, "FIREMODE")
		root.HITSCAN = config.get_value(weapon, "HITSCAN")
		if(not root.HITSCAN):
			print("Projectile stats")
		else:
			root.RAY_LEN = config.get_value(weapon, "RAY_LEN")
		
		#Set Anim Data 
		root.MODEL = weapon_model
		root.DRAW_POS = config.get_value(weapon, "DRAW_POS")
		root.DRAW_ROT = config.get_value(weapon, "DRAW_ROT")
		root.MOMENTUM = config.get_value(weapon, "MOMENTUM")
		root.ANGULAR_MOMENTUM = config.get_value(weapon, "ANGULAR_MOMENTUM")
		root.RECOIL_COOLDOWN = config.get_value(weapon, "RECOIL_COOLDOWN")
		root.RELOAD_MOMENTUM = config.get_value(weapon, "RELOAD_MOMENTUM")
		root.RELOAD_ANGULAR_MOMENTUM = config.get_value(weapon, "RELOAD_ANGULAR_MOMENTUM")
		root.RELOAD_TIME = config.get_value(weapon, "RELOAD_TIME")
			
		ALL_WEAPONS[root.name] = root
