extends CanvasLayer

enum ErrTypes { NORMAL, NORMAL_RICH, WARNING, ERROR }

const DEFAULT_DURATION: float = 5.0

@export_range(0, 1000, 1) var log_limit: int = 120

var msg_list: PackedStringArray = []
var msg_uid: PackedInt32Array = []

@onready var log_label: RichTextLabel = $LogLabel


func _ready() -> void:
	if OS.has_feature("standalone"):
		hide()


func print_msg(text: String, duration: float = DEFAULT_DURATION, type: ErrTypes = ErrTypes.NORMAL, color := Color.AQUA) -> void:
	if not OS.is_debug_build():
		return
	
	if msg_list.size() + 1 > log_limit:
		if msg_list.is_empty(): # Don't do anything if the [param log_limit] is set to 0.
			return
		else: # Remove the first messages until we have a free slot.
			msg_list.remove_at(0)
			msg_uid.remove_at(0)
			print_msg(text, duration, type, color)
			return
	
	var prefix: String = ""
	match type:
		ErrTypes.NORMAL_RICH:
			print_rich(text)
		ErrTypes.WARNING:
			push_warning(text)
			prefix = str("[color=orange][b]WARNING: [/b][/color]")
		ErrTypes.ERROR:
			push_error(text)
			printerr(text)
			prefix = str("[color=red][b]ERROR: [/b][/color]")
	
	# print messages into the log first before stoppingQ.
	if OS.has_feature("standalone"):
		return
	
	text = str("%s[color=%s]%s[/color]" %[prefix, color.to_html(), text])
	msg_list.append(text)
	
	var timer := Timer.new()
	timer.one_shot = true
	
	msg_uid.append(absi(timer.get_instance_id()))
	
	timer.timeout.connect(func() -> void:
		var uid: int = msg_uid.find(absi(timer.get_instance_id()))
		if uid >= 0:
			msg_list.remove_at(uid)
			msg_uid.remove_at(uid)
		_update_hud()
		timer.queue_free()
	)
	add_child(timer)
	timer.start(duration if duration >= 0.0 else DEFAULT_DURATION)
	
	_update_hud()


func clear_log() -> void:
	msg_list.clear()
	msg_uid.clear()
	_update_hud()
	# Remove the timers.
	for i: Node in get_children():
		if not i == log_label:
			i.queue_free()


func _update_hud() -> void:
	if not self.is_node_ready():
		await self.ready
	
	var text: String = "\n".join(msg_list) if not msg_list.is_empty() else ""
	log_label.set_text(text)
	if msg_list.is_empty():
		log_label.clear()
