using Godot;
using System;

public partial class TextLabelSize : RichTextLabel
{
    [Export] public float MaxWidth = 300;
	[Export] public float MaxHeight = 500;
	[Export] public float lineHeight = 23;

	[Signal] public delegate void FittedHeightEventHandler(float finalHeight);

	public async void FitHeight()
	{
		// don't send signals every time the text is re-rendered
		SetBlockSignals(true);

		// move label out of player view to avoid flashing
		var globalPosition = GlobalPosition;
		GlobalPosition += new Vector2(1000, 0);

		// set initial size to maxwidth and minheight
		Size = new Vector2(MaxWidth, CustomMinimumSize.Y);

		// wait for next frame to render text and get current visible lines
		// visible lines are only known *after* rendering text (unfortunately)
		await ToSignal(GetTree(), SceneTree.SignalName.ProcessFrame);
		int visibleLines = GetVisibleLineCount();
		int tmp;
		float finalHeight = CustomMinimumSize.Y;

		// loop until maximum height, continuously checking if more lines visible than before.
		// looping over whole possible height for the case of "empty" lines between paragraphs.
		while (true)
		{
			// if upsizing by whole line would overshoot maxHeight, break off looping
			if (Size.Y + lineHeight >= MaxHeight)
			{
				// if last considered finalHeight close enough to maxHeight, just round up
				if (MaxHeight - finalHeight <= lineHeight)
				{
					finalHeight = MaxHeight;
				}
				break;
			}

			// upsize & check if more lines visible than before. if yes, set new finalHeight
			Size += new Vector2(0, lineHeight);
			await ToSignal(GetTree(), SceneTree.SignalName.ProcessFrame);
			tmp = GetVisibleLineCount();
			if (visibleLines != tmp)
			{
				visibleLines = tmp;
				finalHeight = Size.Y;
			}
		}

		// set final size, emit signal so button position can be adjusted
		Size = new Vector2(MaxWidth, finalHeight);
		GlobalPosition = globalPosition;
		SetBlockSignals(false);
		EmitSignal(SignalName.FittedHeight, finalHeight);
	}
}
