@tool
class_name AdvancedRichText extends RichTextLabel

@export_multiline var userText:String = "" # The text the user is asking for
@export_multiline var _finalText:String = "" # The final text after processing (translation, wrapping, etc.)

@export var _newLineIndexes:Array[int] = [] # The indexes of where each line starts in finalText
@export var _lines:PackedStringArray = [];

# Hides the original RichTextLabel text property
func _set(property: StringName, value) -> bool:
  if property == "text":
    userText = value
    _recalcText()
    return true
  elif property == "richtextlabel_text":
    text = value
    return true
  return false

func _get(property: StringName):
  if property == "text":
    return userText
  elif property == "richtextlabel_text":
    return text
  return null

@export var translate:bool = true:
  set(value):
    translate = value
    _recalcText()
  get():
    return translate

@export var smartWrap:bool = true:
  set(value):
    smartWrap = value
    _recalcText()
  get():
    return smartWrap

@export var maxLines:int = -1:
  set(value):
    maxLines = value
    _recalcText()
  get():
    return maxLines

@export var startLine:int = 0:
  set(value):
    startLine = value
    _recalcText()
  get():
    return startLine

# Returns count of characters that can be displayed, assuming visible_chars = -1
func getCharactersDisplayedCount() -> int:
  # Count characters
  var count = 0
  var lineCount = min(startLine + maxLines, _lines.size()) - startLine
  for i in range(startLine, startLine + lineCount):
    count += _lines[i].length()
  if lineCount > 1:
    count += lineCount - 1 # Add newlines
  return count

func getFinalText() -> String:
  return _finalText

func getTotalLineCount() -> int:
  return _lines.size()

func _enter_tree() -> void:
  self.threaded = false;

func _recalcText() -> void:
  _lines.clear()

  if userText.is_empty():
    self.richtextlabel_text = ""
    return

  # Translate if needed
  var textTranslated = userText
  if self.translate:
    textTranslated = tr(textTranslated)

  # Replace input bb tags.
  var regex = RegEx.new()
  regex.compile(r"\[input action=(.*?)\](.*?)\[/input\]")
  var inputIconText = textTranslated
  for match in regex.search_all(textTranslated):
    var action = match.get_string(1).to_lower()
    var height:int = get_theme_font_size("normal_font_size")
    var img_tag = "[img height=%d valign=center,center]res://ui/input/%s.tres[/img]" % [ height, action ]
    inputIconText = inputIconText.replace(match.get_string(0), img_tag)

  # Perform smart wrapping
  var wrappedText = inputIconText
  if smartWrap:
    var unwrappedText = wrappedText.strip_edges()

    self.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART;
    self.richtextlabel_text = unwrappedText
    self.visible_characters = -1;
    self.fit_content = false;
    _newLineIndexes = [];

    # Determine where the wrapped newlines are
    var line = 0;
    var wasNewLine = false;
    for i in range(0, self.richtextlabel_text.length()):
      var tLine = self.get_character_line(i);
      if tLine == line:
        wasNewLine = false
        if self.richtextlabel_text[i] == "\n":
          wasNewLine = true
        continue;
      if !wasNewLine:
        _newLineIndexes.append(i);
      line = tLine;

    # Create fake pre-wrapped text.
    wrappedText = "";
    for i in range(0, self.richtextlabel_text.length()):
      if _newLineIndexes.find(i) != -1 and i != 0:
        wrappedText += "\n";
      wrappedText += self.richtextlabel_text[i];

  # Handle max and start line(s)
  var maxText = wrappedText
  if maxLines > 0:
    _lines = maxText.split("\n", true);
    var selectedLines = [];
    for i in range(startLine, min(startLine + maxLines, _lines.size())):
      selectedLines.append(_lines[i]);
    maxText = "\n".join(selectedLines);
    
  _finalText = maxText
  self.richtextlabel_text = maxText
  # print("Updated text")
