extends SceneTree

const BattleStateScript := preload("res://scripts/core/battle_state.gd")
const BattleSceneScript := preload("res://scripts/scenes/battle_scene.gd")


func _init() -> void:
	var failures: Array[String] = []
	_check_panacea_cleanses_debuffs(failures)
	_check_no_effect_panacea_is_not_consumed(failures)
	_check_panacea_menu_text(failures)

	if failures.is_empty():
		print("item debuff cleanse smoke ok")
		quit(0)
		return

	for failure in failures:
		push_error(failure)
	quit(1)


func _check_panacea_cleanses_debuffs(failures: Array[String]) -> void:
	var state = BattleStateScript.new()
	if not state.load_battle("res://data/scenarios/001_yellow_turbans.json"):
		failures.append("could not load opening battle")
		return

	var cao_cao: Dictionary = state.get_unit("cao_cao")
	if cao_cao.is_empty():
		failures.append("missing Cao Cao")
		return
	cao_cao["status_effects"] = _mixed_status_effects()
	state.battle_inventory["panacea"] = 1

	var preview: Dictionary = state.get_item_preview("cao_cao", "panacea", cao_cao["pos"])
	var cure_names: Array = preview.get("cure_statuses", [])
	for expected in ["Poison", "Seal", "ATK down", "MOVE down"]:
		if not cure_names.has(expected):
			failures.append("Panacea preview should include %s in %s" % [expected, str(cure_names)])

	var logs: Array[String] = []
	var feedback: Array[String] = []
	state.log_added.connect(func(message: String) -> void:
		logs.append(message)
	)
	state.combat_feedback_requested.connect(func(unit_id: String, text: String, kind: String) -> void:
		feedback.append("%s|%s|%s" % [unit_id, text, kind])
	)

	if not state.select_unit("cao_cao"):
		failures.append("could not select Cao Cao")
		return
	if not state.try_use_selected_item_on_cell("panacea", cao_cao["pos"]):
		failures.append("Panacea should apply to Cao Cao with poison, seal, and debuffs")
		return

	if int(state.get_inventory_snapshot().get("panacea", 0)) != 0:
		failures.append("Panacea should be consumed after cleansing")
	var summary := state.get_status_effect_summary("cao_cao")
	if not summary.contains("DEF +4"):
		failures.append("Panacea should keep positive buffs: %s" % summary)
	for removed_text in ["ATK -3", "MOVE -1", "Poison", "Seal"]:
		if summary.contains(removed_text):
			failures.append("Panacea should remove %s from summary: %s" % [removed_text, summary])
	_check_log_contains(failures, logs, "Cao Cao is cured of Poison.")
	_check_log_contains(failures, logs, "Cao Cao is cured of Seal.")
	_check_log_contains(failures, logs, "Cao Cao is cleansed of ATK down, MOVE down.")
	if not feedback.has("cao_cao|CLEANSE|support"):
		failures.append("Panacea cleanse feedback missing: %s" % str(feedback))


func _check_no_effect_panacea_is_not_consumed(failures: Array[String]) -> void:
	var state = BattleStateScript.new()
	if not state.load_battle("res://data/scenarios/001_yellow_turbans.json"):
		failures.append("could not load opening battle for no-effect check")
		return

	var cao_cao: Dictionary = state.get_unit("cao_cao")
	cao_cao["status_effects"] = [{
		"source_skill": "guard_order",
		"name": "Guard Order",
		"type": "stat_bonus",
		"stat": "def",
		"amount": 4,
		"remaining_phases": 2
	}]
	state.battle_inventory["panacea"] = 1
	if not state.select_unit("cao_cao"):
		failures.append("could not select Cao Cao for no-effect check")
		return
	if state.try_use_selected_item_on_cell("panacea", cao_cao["pos"]):
		failures.append("Panacea should not apply when only positive buffs are active")
	if int(state.get_inventory_snapshot().get("panacea", 0)) != 1:
		failures.append("No-effect Panacea should not be consumed")


func _check_panacea_menu_text(failures: Array[String]) -> void:
	var scene = BattleSceneScript.new()
	if not scene.state.load_battle("res://data/scenarios/001_yellow_turbans.json"):
		failures.append("could not load battle scene state for menu text")
		scene.free()
		return
	var text := scene._format_item_effect_text(scene.state.get_item_def("panacea"))
	if not text.contains("Cleanse debuffs"):
		failures.append("Panacea menu text should mention debuff cleanse: %s" % text)
	scene.free()


func _mixed_status_effects() -> Array:
	return [
		{
			"source_skill": "disrupt_order",
			"name": "Disrupt Order",
			"type": "stat_bonus",
			"stat": "atk",
			"amount": -3,
			"remaining_phases": 2
		},
		{
			"source_skill": "hamper_order",
			"name": "Hamper Order",
			"type": "stat_bonus",
			"stat": "move",
			"amount": -1,
			"remaining_phases": 2
		},
		{
			"source_skill": "guard_order",
			"name": "Guard Order",
			"type": "stat_bonus",
			"stat": "def",
			"amount": 4,
			"remaining_phases": 2
		},
		{
			"source_skill": "poison_mist",
			"name": "Poison Mist",
			"type": "damage_over_time",
			"status": "poison",
			"amount": 4,
			"remaining_phases": 2
		},
		{
			"source_skill": "seal_tactic",
			"name": "Seal Tactic",
			"type": "action_lock",
			"status": "seal",
			"action": "skill",
			"remaining_phases": 2
		}
	]


func _check_log_contains(failures: Array[String], logs: Array, expected: String) -> void:
	for log_entry in logs:
		if str(log_entry) == expected:
			return
	failures.append("expected log `%s` in `%s`" % [expected, str(logs)])
