class_name PlayerArcade
extends CharacterBody3D

# Arcade player: same FPS controller as the demo, plus HP and a melee
# attack on left-click. Emits hp_changed and died signals; arcade_scene
# listens and updates the HUD / restart logic.

signal hp_changed(current: int, maximum: int)
signal died
signal attacked(hit_point: Vector3, hit_body: Node)

@export var speed := 6.0
@export var run_multiplier := 1.8
@export var jump_velocity := 6.0
@export var gravity := 22.0
@export var mouse_sensitivity := 0.002
@export var max_hp := 20
@export var melee_range := 1.6
@export var melee_damage := 6
@export var melee_cooldown := 0.35

@onready var camera: Camera3D = $Camera3D

var hp := 20
var _pitch := 0.0
var _captured := false
var _melee_timer := 0.0
var _alive := true

func _ready() -> void:
	hp = max_hp
	hp_changed.emit(hp, max_hp)
	_capture()

func _capture() -> void:
	Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
	_captured = true

func _release() -> void:
	Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
	_captured = false

func _unhandled_input(event: InputEvent) -> void:
	if not _alive:
		return
	if event is InputEventMouseMotion and _captured:
		var m := event as InputEventMouseMotion
		rotation.y -= m.relative.x * mouse_sensitivity
		_pitch -= m.relative.y * mouse_sensitivity
		_pitch = clamp(_pitch, deg_to_rad(-85.0), deg_to_rad(85.0))
		camera.rotation.x = _pitch
	elif event is InputEventKey and event.pressed and event.keycode == KEY_ESCAPE:
		_release()
	elif event is InputEventMouseButton and event.pressed:
		if not _captured:
			_capture()
		elif event.button_index == MOUSE_BUTTON_LEFT:
			_try_attack()

func _physics_process(delta: float) -> void:
	if not _alive:
		return
	if _melee_timer > 0.0:
		_melee_timer -= delta

	if not is_on_floor():
		velocity.y -= gravity * delta

	var input := Vector2.ZERO
	if Input.is_key_pressed(KEY_W): input.y -= 1.0
	if Input.is_key_pressed(KEY_S): input.y += 1.0
	if Input.is_key_pressed(KEY_A): input.x -= 1.0
	if Input.is_key_pressed(KEY_D): input.x += 1.0
	input = input.normalized()

	var s := speed
	if Input.is_key_pressed(KEY_SHIFT):
		s *= run_multiplier

	var forward := -transform.basis.z
	var right := transform.basis.x
	var horiz := (forward * -input.y + right * input.x) * s
	velocity.x = horiz.x
	velocity.z = horiz.z

	if is_on_floor() and Input.is_key_pressed(KEY_SPACE):
		velocity.y = jump_velocity

	move_and_slide()

# Deal damage to any enemy within melee_range in front of the camera.
func _try_attack() -> void:
	if _melee_timer > 0.0:
		return
	_melee_timer = melee_cooldown

	var origin := camera.global_position
	var dir := -camera.global_transform.basis.z
	var space := get_world_3d().direct_space_state
	var query := PhysicsRayQueryParameters3D.create(origin, origin + dir * melee_range)
	query.exclude = [self]
	var hit := space.intersect_ray(query)
	if hit.is_empty():
		return
	var body := hit.get("collider") as Node
	if body and body.has_method("take_damage"):
		body.take_damage(melee_damage, self)
	attacked.emit(hit.get("position", Vector3.ZERO), body)

# Called by enemies.
func take_damage(amount: int, _source: Node) -> void:
	if not _alive:
		return
	hp = max(0, hp - amount)
	hp_changed.emit(hp, max_hp)
	if hp <= 0:
		_alive = false
		died.emit()
