extends SceneTree

const BattleStateScript := preload("res://scripts/core/battle_state.gd")
const CampaignStateScript := preload("res://scripts/core/campaign_state.gd")

const CAMPAIGN_PATH := "res://data/campaign/campaign.json"
const SAVE_PATH := "user://campaign_save.json"


func _init() -> void:
	var failures: Array[String] = []
	var save_existed := FileAccess.file_exists(SAVE_PATH)
	var save_text := FileAccess.get_file_as_string(SAVE_PATH) if save_existed else ""

	_check_unequipped_loadout_persists_after_victory(failures)
	_restore_save(save_existed, save_text, failures)

	if failures.is_empty():
		print("equipment campaign persistence smoke ok")
		quit(0)
		return

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


func _check_unequipped_loadout_persists_after_victory(failures: Array[String]) -> void:
	var campaign_state = CampaignStateScript.new()
	if not campaign_state.load_campaign(CAMPAIGN_PATH):
		failures.append("could not load campaign data")
		return
	campaign_state.start_new(campaign_state.get_start_scenario_id())

	var state = BattleStateScript.new()
	if not state.load_battle(
		campaign_state.get_scenario_path("001_yellow_turbans"),
		campaign_state.get_roster_overrides(),
		campaign_state.get_inventory_snapshot(),
		campaign_state.get_flags_snapshot(),
		campaign_state.get_joined_officers_snapshot()
	):
		failures.append("could not load opening battle")
		return

	if not state.try_unequip_item("cao_cao", "weapon"):
		failures.append("Cao Cao should be able to unequip Bronze Sword before victory")
		return
	var battle_inventory: Dictionary = state.get_inventory_snapshot()
	if int(battle_inventory.get("bronze_sword", 0)) != 1:
		failures.append("battle inventory should receive unequipped Bronze Sword")
	var battle_equipment: Dictionary = state.get_equipment_snapshot("cao_cao")
	if battle_equipment.has("weapon"):
		failures.append("battle equipment should keep Cao Cao weapon empty before save")

	state.battle_status = "victory"
	var result: Dictionary = campaign_state.apply_battle_result(state)
	if not bool(result.get("saved", false)):
		failures.append("campaign save should succeed after opening victory")
	if not campaign_state.completed_scenarios.has("001_yellow_turbans"):
		failures.append("opening scenario should be completed after victory")
	if campaign_state.current_scenario_id != "002_sishui_gate":
		failures.append("campaign should advance to Sishui Gate, got %s" % campaign_state.current_scenario_id)

	var campaign_roster: Dictionary = campaign_state.get_roster_overrides()
	var cao_cao_roster: Dictionary = campaign_roster.get("cao_cao", {})
	var saved_equipment: Dictionary = cao_cao_roster.get("equipment", {})
	if saved_equipment.has("weapon"):
		failures.append("campaign roster should persist empty Cao Cao weapon slot: %s" % str(saved_equipment))
	var campaign_inventory: Dictionary = campaign_state.get_inventory_snapshot()
	if int(campaign_inventory.get("bronze_sword", 0)) != 1:
		failures.append("campaign inventory should keep returned Bronze Sword")
	if int(campaign_inventory.get("bean", 0)) != 1:
		failures.append("campaign inventory should include opening victory Bean reward")

	var next_state = BattleStateScript.new()
	if not next_state.load_battle(
		campaign_state.get_scenario_path("002_sishui_gate"),
		campaign_state.get_roster_overrides(),
		campaign_state.get_inventory_snapshot(),
		campaign_state.get_flags_snapshot(),
		campaign_state.get_joined_officers_snapshot()
	):
		failures.append("could not load next battle from saved campaign state")
		return
	var next_equipment: Dictionary = next_state.get_equipment_snapshot("cao_cao_ch2")
	if next_equipment.has("weapon"):
		failures.append("next scenario should rehydrate Cao Cao without weapon: %s" % str(next_equipment))
	if int(next_state.get_inventory_snapshot().get("bronze_sword", 0)) != 1:
		failures.append("next scenario battle inventory should include returned Bronze Sword")

	var before_replay_inventory: Dictionary = campaign_state.get_inventory_snapshot()
	var before_replay_roster: Dictionary = campaign_state.get_roster_overrides()
	var replay_result: Dictionary = campaign_state.apply_battle_result(state)
	if not bool(replay_result.get("already_completed", false)):
		failures.append("second apply should be treated as completed replay")
	if campaign_state.get_inventory_snapshot() != before_replay_inventory:
		failures.append("completed replay should not mutate campaign inventory")
	if campaign_state.get_roster_overrides() != before_replay_roster:
		failures.append("completed replay should not mutate campaign roster")


func _restore_save(save_existed: bool, save_text: String, failures: Array[String]) -> void:
	if save_existed:
		var file := FileAccess.open(SAVE_PATH, FileAccess.WRITE)
		if file == null:
			failures.append("could not restore previous campaign save")
			return
		file.store_string(save_text)
		return

	if FileAccess.file_exists(SAVE_PATH):
		var error := DirAccess.remove_absolute(ProjectSettings.globalize_path(SAVE_PATH))
		if error != OK:
			failures.append("could not remove temporary campaign save")
