extends Node

# Attached to ChunkManager node.
# Server: intercepts block changes and broadcasts to clients.
# Client: receives and applies block changes locally.

var _chunk_manager: Node = null


func _ready() -> void:
	_chunk_manager = get_parent()


# Called by Main.gd instead of world.break_block / world.place_block when in multiplayer.
func server_break_block(world_pos: Vector3) -> int:
	if not NetworkManager.is_server():
		# Client sends request to server
		request_break.rpc_id(1, world_pos)
		return 0
	var broken_id: int = _chunk_manager.break_block(world_pos)
	if broken_id > 0:
		broadcast_block_change.rpc(world_pos, 0)
	return broken_id


func server_place_block(world_pos: Vector3, block_id: int) -> bool:
	if not NetworkManager.is_server():
		# Client sends request to server
		request_place.rpc_id(1, world_pos, block_id)
		return false
	var placed: bool = _chunk_manager.place_block(world_pos, block_id)
	if placed:
		broadcast_block_change.rpc(world_pos, block_id)
	return placed


@rpc("any_peer", "reliable")
func request_break(pos: Vector3) -> void:
	if not NetworkManager.is_server():
		return
	var sender_id: int = multiplayer.get_remote_sender_id()
	var broken_id: int = _chunk_manager.break_block(pos)
	if broken_id > 0:
		broadcast_block_change.rpc(pos, 0)
		# Notify requesting peer of item pickup
		notify_break_result.rpc_id(sender_id, broken_id)


@rpc("any_peer", "reliable")
func request_place(pos: Vector3, block_id: int) -> void:
	if not NetworkManager.is_server():
		return
	var placed: bool = _chunk_manager.place_block(pos, block_id)
	if placed:
		broadcast_block_change.rpc(pos, block_id)


@rpc("authority", "call_local", "reliable")
func broadcast_block_change(world_pos: Vector3, new_id: int) -> void:
	# Applied on all peers including server via call_local
	if multiplayer.is_server():
		return  # already applied on server
	if new_id == 0:
		_chunk_manager.break_block(world_pos)
	else:
		_chunk_manager.place_block(world_pos, new_id)


@rpc("authority", "reliable")
func notify_break_result(broken_id: int) -> void:
	# Signal to Main.gd to add item to local inventory
	var main := get_tree().get_first_node_in_group("main")
	if is_instance_valid(main) and main.has_method("_on_remote_block_broken"):
		main._on_remote_block_broken(broken_id)
