extends GdUnitTestSuite

## NEO-85: `CombatTargetsClient` GET parse + target row lookup.

const CombatTargetsClient := preload("res://scripts/combat_targets_client.gd")


class MockHttpTransport:
	extends Node
	signal request_completed(
		result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray
	)
	var last_url: String = ""
	var response_code: int = 200
	var body_json: String = ""

	func request(
		url: String,
		_custom_headers: PackedStringArray = PackedStringArray(),
		_method: HTTPClient.Method = HTTPClient.METHOD_GET,
		_request_data: String = ""
	) -> Error:
		last_url = url
		request_completed.emit(
			HTTPRequest.RESULT_SUCCESS,
			response_code,
			PackedStringArray(),
			body_json.to_utf8_buffer()
		)
		return OK


static func _two_target_snapshot_json() -> String:
	return (
		'{"schemaVersion":1,"targets":['
		+ '{"targetId":"prototype_target_alpha","maxHp":100,"currentHp":75,"defeated":false},'
		+ '{"targetId":"prototype_target_beta","maxHp":100,"currentHp":100,"defeated":false}'
		+ "]}"
	)


func _make_client(transport: Node) -> Node:
	var c: Node = CombatTargetsClient.new()
	c.set("injected_http", transport)
	auto_free(transport)
	auto_free(c)
	add_child(c)
	return c


func test_request_sync_gets_combat_targets_url() -> void:
	# Arrange
	var transport := MockHttpTransport.new()
	transport.body_json = _two_target_snapshot_json()
	var c := _make_client(transport)
	# Act
	c.call("request_sync_from_server")
	# Assert
	assert_that(transport.last_url).contains("/game/world/combat-targets")


func test_targets_received_emits_parsed_snapshot() -> void:
	# Arrange
	var transport := MockHttpTransport.new()
	transport.body_json = _two_target_snapshot_json()
	var c := _make_client(transport)
	var got: Array = []
	c.connect("targets_received", func(snapshot: Dictionary) -> void: got.append(snapshot))
	# Act
	c.call("request_sync_from_server")
	# Assert
	assert_that(got.size()).is_equal(1)
	var snapshot: Dictionary = got[0]
	var targets: Variant = snapshot.get("targets", null)
	assert_that(targets is Array).is_true()
	assert_that((targets as Array).size()).is_equal(2)


func test_target_row_returns_alpha_hp_fields() -> void:
	# Arrange
	var transport := MockHttpTransport.new()
	transport.body_json = _two_target_snapshot_json()
	var c := _make_client(transport)
	var got: Array = []
	c.connect("targets_received", func(snapshot: Dictionary) -> void: got.append(snapshot))
	c.call("request_sync_from_server")
	var snapshot: Dictionary = got[0]
	# Act
	var row: Dictionary = c.call("target_row", "prototype_target_alpha", snapshot) as Dictionary
	# Assert
	assert_that(int(row.get("currentHp", 0))).is_equal(75)
	assert_that(int(row.get("maxHp", 0))).is_equal(100)
	assert_that(bool(row.get("defeated", false))).is_false()


func test_invalid_schema_emits_sync_failed() -> void:
	# Arrange
	var transport := MockHttpTransport.new()
	transport.body_json = '{"schemaVersion":2,"targets":[]}'
	var c := _make_client(transport)
	var failed: Array = []
	c.connect("targets_sync_failed", func(reason: String) -> void: failed.append(reason))
	# Act
	c.call("request_sync_from_server")
	# Assert
	assert_that(failed.size()).is_equal(1)
	assert_that(str(failed[0])).contains("schemaVersion")


func test_http_404_emits_sync_failed() -> void:
	# Arrange
	var transport := MockHttpTransport.new()
	transport.response_code = 404
	transport.body_json = ""
	var c := _make_client(transport)
	var failed: Array = []
	c.connect("targets_sync_failed", func(reason: String) -> void: failed.append(reason))
	# Act
	c.call("request_sync_from_server")
	# Assert
	assert_that(failed.size()).is_equal(1)
	assert_that(str(failed[0])).is_equal("HTTP 404")
