extends SceneTree

## Test suite for SettingsManager
##
## Tests input validation, file I/O, and error handling.

const TestHelperClass = preload("res://tests/helpers/TestHelper.gd")

var settings_manager: Node
var original_settings: Dictionary
var temp_files: Array[String] = []


func _initialize():
	# Wait for autoloads to initialize
	await process_frame
	await process_frame

	run_tests()

	# Exit after tests complete
	quit()


func run_tests():
	TestHelperClass.print_test_header("SettingsManager")

	# Get reference to SettingsManager
	settings_manager = root.get_node("SettingsManager")
	if not settings_manager:
		TestHelperClass.assert_true(false, "SettingsManager autoload not found")
		TestHelperClass.print_test_footer("SettingsManager")
		return

	# Store original settings for restoration
	original_settings = settings_manager.settings.duplicate(true)

	# Run test suites
	test_basic_functionality()
	test_input_validation_security()
	test_file_io_security()
	test_json_parsing_security()
	test_language_validation()
	test_volume_validation()
	test_error_handling_and_recovery()
	test_reset_functionality()
	test_performance_benchmarks()

	# Cleanup and restore original state
	cleanup_tests()

	TestHelperClass.print_test_footer("SettingsManager")


func test_basic_functionality():
	TestHelperClass.print_step("Basic Functionality")

	# Test that SettingsManager has expected properties
	TestHelperClass.assert_has_properties(
		settings_manager,
		["settings", "default_settings", "languages_data"],
		"SettingsManager properties"
	)

	# Test that SettingsManager has expected methods
	var expected_methods = [
		"get_setting", "set_setting", "save_settings", "load_settings", "reset_settings_to_defaults"
	]
	TestHelperClass.assert_has_methods(settings_manager, expected_methods, "SettingsManager methods")

	# Test default settings structure
	var expected_defaults = ["master_volume", "music_volume", "sfx_volume", "language"]
	for key in expected_defaults:
		TestHelperClass.assert_has_key(
			settings_manager.default_settings, key, "Default setting key: " + key
		)

	# Test getting settings
	var master_volume = settings_manager.get_setting("master_volume")
	TestHelperClass.assert_not_null(master_volume, "Can get master_volume setting")
	TestHelperClass.assert_true(master_volume is float, "master_volume is float type")


func test_input_validation_security():
	TestHelperClass.print_step("Input Validation Security")

	# Test NaN validation
	var nan_result = settings_manager.set_setting("master_volume", NAN)
	TestHelperClass.assert_false(nan_result, "NaN values rejected for volume settings")

	# Test Infinity validation
	var inf_result = settings_manager.set_setting("master_volume", INF)
	TestHelperClass.assert_false(inf_result, "Infinity values rejected for volume settings")

	# Test negative infinity validation
	var neg_inf_result = settings_manager.set_setting("master_volume", -INF)
	TestHelperClass.assert_false(neg_inf_result, "Negative infinity values rejected")

	# Test range validation for volumes
	var negative_volume = settings_manager.set_setting("master_volume", -0.5)
	TestHelperClass.assert_false(negative_volume, "Negative volume values rejected")

	var excessive_volume = settings_manager.set_setting("master_volume", 1.5)
	TestHelperClass.assert_false(excessive_volume, "Volume values > 1.0 rejected")

	# Test valid volume range
	var valid_volume = settings_manager.set_setting("master_volume", 0.5)
	TestHelperClass.assert_true(valid_volume, "Valid volume values accepted")
	TestHelperClass.assert_equal(
		0.5, settings_manager.get_setting("master_volume"), "Volume value set correctly"
	)

	# Test string length validation for language
	var long_language = "a".repeat(20)  # Exceeds MAX_SETTING_STRING_LENGTH
	var long_lang_result = settings_manager.set_setting("language", long_language)
	TestHelperClass.assert_false(long_lang_result, "Excessively long language codes rejected")

	# Test invalid characters in language code
	var invalid_chars = settings_manager.set_setting("language", "en<script>")
	TestHelperClass.assert_false(invalid_chars, "Language codes with invalid characters rejected")

	# Test valid language code
	var valid_lang = settings_manager.set_setting("language", "en")
	TestHelperClass.assert_true(valid_lang, "Valid language codes accepted")


func test_file_io_security():
	TestHelperClass.print_step("File I/O Security")

	# Test file size limits by creating oversized config
	var oversized_config_path = TestHelper.create_temp_file(
		"oversized_settings.cfg", "x".repeat(70000)
	)  # > 64KB
	temp_files.append(oversized_config_path)

	# Test that normal save/load operations work
	var save_result = settings_manager.save_settings()
	TestHelperClass.assert_true(save_result, "Normal settings save succeeds")

	# Test loading with backup scenario
	settings_manager.load_settings()
	TestHelperClass.assert_not_null(settings_manager.settings, "Settings loaded successfully")

	# Test that settings file exists after save
	TestHelperClass.assert_file_exists("user://settings.cfg", "Settings file created after save")


func test_json_parsing_security():
	TestHelperClass.print_step("JSON Parsing Security")

	# Create invalid languages.json for testing
	var invalid_json_path = TestHelper.create_temp_file(
		"invalid_languages.json", TestHelper.create_invalid_json()
	)
	temp_files.append(invalid_json_path)

	# Create oversized JSON file
	var large_json_content = '{"languages": {"' + "x".repeat(70000) + '": "test"}}'
	var oversized_json_path = TestHelper.create_temp_file(
		"oversized_languages.json", large_json_content
	)
	temp_files.append(oversized_json_path)

	# Test that SettingsManager handles invalid JSON gracefully
	# This should fall back to default languages
	TestHelperClass.assert_true(
		settings_manager.languages_data.has("languages"),
		"Default languages loaded on JSON parse failure"
	)


func test_language_validation():
	TestHelperClass.print_step("Language Validation")

	# Test supported languages
	var supported_langs = ["en", "ru"]
	for lang in supported_langs:
		var result = settings_manager.set_setting("language", lang)
		TestHelperClass.assert_true(result, "Supported language accepted: " + lang)

	# Test unsupported language
	var unsupported_result = settings_manager.set_setting("language", "xyz")
	TestHelperClass.assert_false(unsupported_result, "Unsupported language rejected")

	# Test empty language
	var empty_result = settings_manager.set_setting("language", "")
	TestHelperClass.assert_false(empty_result, "Empty language rejected")

	# Test null language
	var null_result = settings_manager.set_setting("language", null)
	TestHelperClass.assert_false(null_result, "Null language rejected")


func test_volume_validation():
	TestHelperClass.print_step("Volume Validation")

	var volume_settings = ["master_volume", "music_volume", "sfx_volume"]

	for setting in volume_settings:
		# Test boundary values
		TestHelperClass.assert_true(
			settings_manager.set_setting(setting, 0.0), "Volume 0.0 accepted for " + setting
		)
		TestHelperClass.assert_true(
			settings_manager.set_setting(setting, 1.0), "Volume 1.0 accepted for " + setting
		)

		# Test out of range values
		TestHelperClass.assert_false(
			settings_manager.set_setting(setting, -0.1), "Negative volume rejected for " + setting
		)
		TestHelperClass.assert_false(
			settings_manager.set_setting(setting, 1.1), "Volume > 1.0 rejected for " + setting
		)

		# Test invalid types
		TestHelperClass.assert_false(
			settings_manager.set_setting(setting, "0.5"), "String volume rejected for " + setting
		)
		TestHelperClass.assert_false(
			settings_manager.set_setting(setting, null), "Null volume rejected for " + setting
		)


func test_error_handling_and_recovery():
	TestHelperClass.print_step("Error Handling and Recovery")

	# Test unknown setting key
	var unknown_result = settings_manager.set_setting("unknown_setting", "value")
	TestHelperClass.assert_false(unknown_result, "Unknown setting keys rejected")

	# Test recovery from corrupted settings
	# Save current state
	var _current_volume = settings_manager.get_setting("master_volume")

	# Reset settings
	settings_manager.reset_settings_to_defaults()

	# Verify defaults are loaded
	var default_volume = settings_manager.default_settings["master_volume"]
	TestHelperClass.assert_equal(
		default_volume,
		settings_manager.get_setting("master_volume"),
		"Reset to defaults works correctly"
	)

	# Test fallback language loading
	TestHelperClass.assert_true(
		settings_manager.languages_data.has("languages"), "Fallback languages loaded"
	)
	TestHelperClass.assert_has_key(
		settings_manager.languages_data["languages"], "en", "English fallback language available"
	)
	TestHelperClass.assert_has_key(
		settings_manager.languages_data["languages"], "ru", "Russian fallback language available"
	)


func test_reset_functionality():
	TestHelperClass.print_step("Reset Functionality")

	# Modify settings
	settings_manager.set_setting("master_volume", 0.8)
	settings_manager.set_setting("language", "ru")

	# Reset to defaults
	settings_manager.reset_settings_to_defaults()

	# Verify reset worked
	TestHelperClass.assert_equal(
		settings_manager.default_settings["master_volume"],
		settings_manager.get_setting("master_volume"),
		"Volume reset to default"
	)
	TestHelperClass.assert_equal(
		settings_manager.default_settings["language"],
		settings_manager.get_setting("language"),
		"Language reset to default"
	)

	# Test that reset saves automatically
	TestHelperClass.assert_file_exists("user://settings.cfg", "Settings file exists after reset")


func test_performance_benchmarks():
	TestHelperClass.print_step("Performance Benchmarks")

	# Test settings load performance
	TestHelperClass.start_performance_test("load_settings")
	settings_manager.load_settings()
	TestHelperClass.end_performance_test("load_settings", 100.0, "Settings load within 100ms")

	# Test settings save performance
	TestHelperClass.start_performance_test("save_settings")
	settings_manager.save_settings()
	TestHelperClass.end_performance_test("save_settings", 50.0, "Settings save within 50ms")

	# Test validation performance
	TestHelperClass.start_performance_test("validation")
	for i in range(100):
		settings_manager.set_setting("master_volume", 0.5)
	TestHelperClass.end_performance_test("validation", 50.0, "100 validations within 50ms")


func cleanup_tests():
	TestHelperClass.print_step("Cleanup")

	# Restore original settings
	if original_settings:
		settings_manager.settings = original_settings.duplicate(true)
		settings_manager.save_settings()

	# Clean up temporary files
	for temp_file in temp_files:
		TestHelperClass.cleanup_temp_file(temp_file)

	TestHelperClass.assert_true(true, "Test cleanup completed")
