## Player — Replicated player state.
##
## Server-authoritative movement model (Phase 0 placeholder).
## The player who owns this node (multiplayer authority) sends input,
## server validates and broadcasts position to all peers.
##
## Phase 0: simple position RPC replication.
## Phase 1+: full input → movement → state broadcast loop.

extends Node3D

# ---------------------------------------------------------------------------
# Exports
# ---------------------------------------------------------------------------
@export var movement_speed: float = 5.0
@export var sync_rate: float = 10.0  # Hz — how often to broadcast state

# ---------------------------------------------------------------------------
# State
# ---------------------------------------------------------------------------
var is_local: bool = false  # True for the local player instance
var is_client_controlled: bool = false

var _sync_timer: float = 0.0

# Interpolation state for remote players
var _remote_position: Vector3 = Vector3.ZERO
var _remote_velocity: Vector3 = Vector3.ZERO

# ---------------------------------------------------------------------------
# Lifecycle
# ---------------------------------------------------------------------------
func _ready() -> void:
	is_local = multiplayer.get_unique_id() == multiplayer.get_multiplayer_authority()
	
	if is_local:
		# This is our own player — we'll send input to server
		is_client_controlled = not multiplayer.is_server()
		if is_client_controlled:
			print("[Player] Local player (client-controlled): %d" % multiplayer.get_unique_id())
	else:
		# Remote player — disable direct control
		set_process(false)
		set_physics_process(false)
		print("[Player] Remote player: %d (authority: %d)" % [multiplayer.get_unique_id(), multiplayer.get_multiplayer_authority()])

# ---------------------------------------------------------------------------
# Client-side: send position to server
# ---------------------------------------------------------------------------
func _process(delta: float) -> void:
	if not is_client_controlled:
		return
	
	# Simple movement for Phase 0 testing
	var input_dir := Vector3.ZERO
	if Input.is_action_pressed("ui_right"):
		input_dir.x += 1.0
	if Input.is_action_pressed("ui_left"):
		input_dir.x -= 1.0
	if Input.is_action_pressed("ui_up"):
		input_dir.z -= 1.0
	if Input.is_action_pressed("ui_down"):
		input_dir.z += 1.0
	
	if input_dir != Vector3.ZERO:
		input_dir = input_dir.normalized()
		position += input_dir * movement_speed * delta
	
	# Rate-limited position update to server
	_sync_timer += delta
	if _sync_timer >= (1.0 / sync_rate):
		_sync_timer = 0.0
		_send_position.rpc_id(1, position)

@rpc("unreliable", "any_peer")
func _send_position(pos: Vector3) -> void:
	# Server receives position from client
	if not multiplayer.is_server():
		return
	
	var peer_id: int = multiplayer.get_remote_sender_id()
	if peer_id != multiplayer.get_multiplayer_authority():
		# Peer is not authorized for this player — reject
		push_warning("[Player] Unauthorized position update from peer %d" % peer_id)
		return
	
	# Server validates and broadcasts to all other peers
	position = pos
	_broadcast_position.rpc(pos)

@rpc("unreliable", "authority", "call_local")
func _broadcast_position(pos: Vector3) -> void:
	# All peers (including server) update this player's position
	if not is_local:
		# Remote player — store for interpolation
		_remote_position = pos
		position = pos
	else:
		# Local player — authoritative position already set via input
		pass
