@tool
class_name PlayerSpawnPoint
extends Marker3D

const _UNIQUE_NAME_GEN_PRE: Array[String] = [
	"Be",
	"Finish",
	"What",
	"Who",
	"Slow",
	"Come",
	"Clean",
	"Leave",
	"I",
	"No",
	"Take",
	"For",
	"Good",
	"Look",
	"Sit",
	"Your",
	"Keep",
	"Join",
	"Dream",
	"Stay",
	"Inform",
	"Eat",
]
const _UNIQUE_NAME_GEN_POST: Array[String] = [
	"Quiet",
	"Quit",
	"Calm",
	"It",
	"Move",
	"Else",
	"Knows",
	"Down",
	"Along",
	"Up",
	"Amazing",
	"Disagree",
	"Problem",
	"Happened",
	"Care",
	"What",
	"Impossible",
	"Bath",
	"Idea",
	"Around",
	"Upright",
	"Doubt",
	"Turn",
	"Say",
	"Fantastic",
	"Me",
	"Nonsense",
	"World",
	"Strong",
	"Well",
	"Slowly",
]

static var spawn_points: Array[PlayerSpawnPoint] = []

@export var spawn_id: StringName = &"": set = set_spawn_id
@export_tool_button("Set unique identifier") var set_unique_identifier: Callable = (
	func() -> void:
		set_spawn_id(generate_unique_identifier())
		update_configuration_warnings()
)

var _idx_label: Label3D
var _config_warnings_hint: Label3D


static func get_spawn_point_by_identifier(identifier: StringName) -> PlayerSpawnPoint:
	for spawn_point: PlayerSpawnPoint in PlayerSpawnPoint.spawn_points:
		if spawn_point.spawn_id == identifier:
			return spawn_point

	return null


func _init() -> void:
	if Engine.is_editor_hint():
		var player_scene: PackedScene = load("uid://clhy3kiceqf2o")
		add_child(player_scene.instantiate(), false, Node.INTERNAL_MODE_FRONT)

		# Setup labels.
		_idx_label = Label3D.new()
		_idx_label.billboard = BaseMaterial3D.BILLBOARD_ENABLED
		_idx_label.shaded = false
		_idx_label.font_size = 64
		add_child(_idx_label, false, Node.INTERNAL_MODE_FRONT)
		_idx_label.position.y = 1.8
		set_spawn_id(spawn_id)

		_config_warnings_hint = Label3D.new()
		_config_warnings_hint.billboard = BaseMaterial3D.BILLBOARD_ENABLED
		_config_warnings_hint.shaded = false
		_config_warnings_hint.no_depth_test = true
		_config_warnings_hint.fixed_size = true
		_config_warnings_hint.text = "!"
		_config_warnings_hint.modulate = Color.RED
		add_child(_config_warnings_hint, false, Node.INTERNAL_MODE_FRONT)
		_config_warnings_hint.position.y = 1.0

		var tween: Tween = create_tween().set_loops()
		tween.tween_property(_config_warnings_hint, ^"scale", Vector3.ONE * 1.5, 0.075)
		tween.tween_property(_config_warnings_hint, ^"scale", Vector3.ONE * 1.0, 0.075)

		update_configuration_warnings()


func _enter_tree() -> void:
	if not spawn_points.has(self):
		spawn_points.append(self)


func _exit_tree() -> void:
	spawn_points.erase(self)


func _get_configuration_warnings() -> PackedStringArray:
	var warnings: PackedStringArray = []

	for spawn_point: PlayerSpawnPoint in spawn_points:
		if spawn_point.spawn_id == spawn_id and spawn_point != self:
			warnings.append(str(spawn_point, " has the same spawn identifier as us."))
			spawn_point._config_warnings_hint.show()

		spawn_point.update_configuration_warnings()

	if warnings.is_empty():
		_config_warnings_hint.hide()

	return warnings


func set_spawn_id(identifier: StringName) -> void:
	spawn_id = identifier
	update_configuration_warnings()

	if is_instance_valid(_idx_label):
		_idx_label.text = str(spawn_id)


func make_current(do_autosave: bool = true) -> void:
	GameGlobals.spawn_id = spawn_id

	if do_autosave:
		SaveManager.save_game()


func generate_unique_identifier() -> StringName:
	var pre: String = _UNIQUE_NAME_GEN_PRE.pick_random()
	var post: String = _UNIQUE_NAME_GEN_POST.pick_random()
	var unique_name: StringName = pre + post

	for spawn_point: PlayerSpawnPoint in spawn_points:
		if spawn_point.spawn_id == unique_name:
			return generate_unique_identifier()

	return unique_name
