class_name GodotGdErrorMonitor
extends GdUnitMonitor

var _godot_log_file :String
var _eof :int
var _report_enabled := false
var _entries: Array[ErrorLogEntry] = []


func _init():
	super("GodotGdErrorMonitor")
	_godot_log_file = GdUnitSettings.get_log_path()
	_report_enabled = _is_reporting_enabled()


func start():
	var file = FileAccess.open(_godot_log_file, FileAccess.READ)
	if file:
		file.seek_end(0)
		_eof = file.get_length()


func stop():
	pass


func to_reports() -> Array[GdUnitReport]:
	var reports_ :Array[GdUnitReport] = []
	if _report_enabled:
		reports_.assign(_entries.map(_to_report))
	return reports_


static func _to_report(errorLog :ErrorLogEntry) -> GdUnitReport:
	var failure := "%s\n\t%s\n%s %s" % [
		GdAssertMessages._error("Godot Runtime Error !"),
		GdAssertMessages._colored_value(errorLog._details),
		GdAssertMessages._error("Error:"),
		GdAssertMessages._colored_value(errorLog._message)]
	return GdUnitReport.new().create(GdUnitReport.ABORT, errorLog._line, failure)


func scan(force_collect_reports := false) -> Array[ErrorLogEntry]:
	await Engine.get_main_loop().process_frame
	await Engine.get_main_loop().physics_frame
	_entries.append_array(_collect_log_entries(force_collect_reports))
	return _entries


func erase_log_entry(entry :ErrorLogEntry) -> void:
	_entries.erase(entry)


func _collect_log_entries(force_collect_reports :bool) -> Array[ErrorLogEntry]:
	var file = FileAccess.open(_godot_log_file, FileAccess.READ)
	file.seek(_eof)
	var records := PackedStringArray()
	while not file.eof_reached():
		records.append(file.get_line())
	file.seek_end(0)
	_eof = file.get_length()
	var log_entries :Array[ErrorLogEntry]= []
	var is_report_errors := force_collect_reports or _is_report_push_errors()
	var is_report_script_errors := force_collect_reports or _is_report_script_errors()
	for index in records.size():
		if force_collect_reports:
			log_entries.append(ErrorLogEntry.extract_push_warning(records, index))
		if is_report_errors:
			log_entries.append(ErrorLogEntry.extract_push_error(records, index))
		if is_report_script_errors:
			log_entries.append(ErrorLogEntry.extract_error(records, index))
	return log_entries.filter(func(value): return value != null )


func _is_reporting_enabled() -> bool:
	return _is_report_script_errors() or _is_report_push_errors()


func _is_report_push_errors() -> bool:
	return GdUnitSettings.is_report_push_errors()


func _is_report_script_errors() -> bool:
	return GdUnitSettings.is_report_script_errors()
