extends GdUnitTestSuite

## NEO-86: defeat cast accept triggers gig-progression GET refresh only.

const CastClient := preload("res://scripts/ability_cast_client.gd")


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

	func request(
		_url: String,
		_custom_headers: PackedStringArray = PackedStringArray(),
		_method: HTTPClient.Method = HTTPClient.METHOD_POST,
		_request_data: String = ""
	) -> Error:
		request_completed.emit(
			HTTPRequest.RESULT_SUCCESS, 200, PackedStringArray(), body_json.to_utf8_buffer()
		)
		return OK


class SpyGigProgressionClient:
	extends Node
	var sync_calls: int = 0

	func request_sync_from_server() -> void:
		sync_calls += 1


class GigRefreshHarness:
	extends Node
	var gig_sync_calls: int = 0
	var _cast: Node
	var _gig: SpyGigProgressionClient

	func setup(parent: Node, cast_transport: Node) -> void:
		_gig = SpyGigProgressionClient.new()
		_cast = CastClient.new()
		_cast.set("injected_http", cast_transport)
		parent.add_child(_cast)
		parent.add_child(_gig)
		_cast.connect("cast_result_received", Callable(self, "_on_cast_result"))

	func _on_cast_result(accepted: bool, _reason_code: String, resolution: Dictionary) -> void:
		if not accepted:
			return
		if bool(resolution.get("targetDefeated", false)):
			_request_gig_progression_refresh()

	func _request_gig_progression_refresh() -> void:
		gig_sync_calls += 1
		_gig.request_sync_from_server()

	func request_cast() -> void:
		_cast.call("request_cast", 0, "prototype_pulse", "prototype_target_alpha")


func test_defeat_cast_triggers_gig_progression_sync() -> void:
	# Arrange
	var transport := MockCastTransport.new()
	transport.body_json = (
		'{"schemaVersion":1,"accepted":true,"combatResolution":'
		+ '{"abilityId":"prototype_pulse","targetId":"prototype_target_alpha",'
		+ '"damageDealt":25,"targetRemainingHp":0,"targetDefeated":true}}'
	)
	var harness := GigRefreshHarness.new()
	auto_free(transport)
	auto_free(harness)
	add_child(harness)
	harness.setup(self, transport)
	monitor_signals(harness._cast)
	# Act
	harness.request_cast()
	# Assert
	await assert_signal(harness._cast).is_emitted("cast_result_received", true, "", any())
	assert_that(harness.gig_sync_calls).is_equal(1)
	assert_that(harness._gig.sync_calls).is_equal(1)


func test_non_defeat_cast_skips_gig_progression_sync() -> void:
	# Arrange
	var transport := MockCastTransport.new()
	transport.body_json = (
		'{"schemaVersion":1,"accepted":true,"combatResolution":'
		+ '{"abilityId":"prototype_pulse","targetId":"prototype_target_alpha",'
		+ '"damageDealt":25,"targetRemainingHp":75,"targetDefeated":false}}'
	)
	var harness := GigRefreshHarness.new()
	auto_free(transport)
	auto_free(harness)
	add_child(harness)
	harness.setup(self, transport)
	monitor_signals(harness._cast)
	# Act
	harness.request_cast()
	# Assert
	await assert_signal(harness._cast).is_emitted("cast_result_received", true, "", any())
	assert_that(harness.gig_sync_calls).is_equal(0)


func test_denied_cast_skips_gig_progression_sync() -> void:
	# Arrange
	var transport := MockCastTransport.new()
	transport.body_json = ('{"schemaVersion":1,"accepted":false,"reasonCode":"target_defeated"}')
	var harness := GigRefreshHarness.new()
	auto_free(transport)
	auto_free(harness)
	add_child(harness)
	harness.setup(self, transport)
	monitor_signals(harness._cast)
	# Act
	harness.request_cast()
	# Assert
	await assert_signal(harness._cast).is_emitted(
		"cast_result_received", false, "target_defeated", any()
	)
	assert_that(harness.gig_sync_calls).is_equal(0)
