class_name NetworkJobService
extends Node

const MAX_SESSION_ID_LENGTH: int = 96

var _session: NetworkSession
var _jobs: PlayerJobService
var _sequence: int = 0
var _last_received_sequence: int = -1


func setup(session: NetworkSession, jobs: PlayerJobService) -> void:
	_session = session
	_jobs = jobs
	_session.state_changed.connect(_on_session_state_changed)
	_session.peer_authenticated.connect(_on_peer_authenticated)
	_jobs.board_changed.connect(_on_board_changed)


func _on_session_state_changed(state: NetworkSession.State) -> void:
	_sequence = 0
	_last_received_sequence = -1
	if state == NetworkSession.State.JOINED_CLIENT:
		if not _session.supports_server_capability(NetworkProtocol.JOBS_CAPABILITY):
			_jobs.clear_remote_board()
	elif state in [
		NetworkSession.State.INACTIVE,
		NetworkSession.State.DISCONNECTING,
		NetworkSession.State.CONNECTION_FAILED,
		NetworkSession.State.SERVER_LOST,
	]:
		_jobs.clear_remote_board()


func _on_peer_authenticated(peer_id: int, _display_name: String) -> void:
	if (
		_session == null
		or not _session.is_host()
		or not _session.peer_supports_capability(
			peer_id, NetworkProtocol.JOBS_CAPABILITY
		)
	):
		return
	_send_board(peer_id)


func _on_board_changed() -> void:
	if _session == null or not _session.is_host():
		return
	for peer_id: int in _session.get_authenticated_peer_ids():
		if (
			peer_id != _session.get_local_peer_id()
			and _session.peer_supports_capability(
				peer_id, NetworkProtocol.JOBS_CAPABILITY
			)
		):
			_send_board(peer_id)


func _send_board(peer_id: int) -> void:
	var board: Dictionary = _jobs.get_host_board_network_data()
	if board.is_empty() or not PlayerJobService.validate_board(board):
		return
	_sequence += 1
	receive_job_board.rpc_id(peer_id, {
		"session_id": _session.get_session_id(),
		"sequence": _sequence,
		"board": board,
	})


@rpc("authority", "call_remote", "reliable", 0)
func receive_job_board(data: Dictionary) -> void:
	if (
		_session == null
		or _jobs == null
		or not _session.is_joined_client()
		or not _session.supports_server_capability(NetworkProtocol.JOBS_CAPABILITY)
		or not validate_snapshot(data)
		or str(data.get("session_id", "")) != _session.get_session_id()
	):
		return
	var sequence: int = int(data.get("sequence", -1))
	if sequence <= _last_received_sequence:
		return
	var board: Dictionary = data.get("board", {})
	if _jobs.apply_remote_board(board):
		_last_received_sequence = sequence


static func validate_snapshot(value: Variant) -> bool:
	if typeof(value) != TYPE_DICTIONARY:
		return false
	var data: Dictionary = value
	return (
		typeof(data.get("session_id")) == TYPE_STRING
		and not str(data.get("session_id", "")).is_empty()
		and str(data.get("session_id", "")).length() <= MAX_SESSION_ID_LENGTH
		and typeof(data.get("sequence")) == TYPE_INT
		and int(data.get("sequence", -1)) >= 0
		and PlayerJobService.validate_board(data.get("board"))
	)
