using Godot;
using System;
using System.Collections;
using System.Threading.Tasks;

public partial class QuestDisplay : PanelContainer
{
	[Export] private Color DefaultColor = Color.Color8(255, 255, 255);
	[Export] private Color CriticalColor = Color.Color8(255, 0, 0);
	[Export] private Color HighlightColor = Color.Color8(0, 255, 255);
	[Export] private float Frequency = 1.0f;
	[Export] private float Duration = 5.0f;

	[Export] private int MaxQuestContainerSize = 500;
	private VBoxContainer _questContainer;
	private int _fontSize;
	private int _numTreeItems = 0;
	// Called when the node enters the scene tree for the first time.
	public override void _Ready()
	{
		_questContainer = GetNode<VBoxContainer>("MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer");
		_fontSize = _questContainer.GetThemeDefaultFontSize() * 2;
	}
	#region Test
	public void TestInsert1()
	{
		Insert("QUEST 1", "step 1 for quest 1");
	}

	public void TestInsert2()
	{
		Insert("QUEST 2", "step 1 for quest 2", true);
	}

	public void TestInsert3()
	{
		Insert("QUEST 1", "step 2 for quest 1", true);
	}

	public void TestComplete()
	{
		Complete("QUEST 2");
	}
	#endregion

	public void Insert(string questName, string questStep, bool critical = false)
	{
		BlinkingLabel quest;
		if (_questContainer.HasNode(questName))
		{
			quest = _questContainer.GetNode<BlinkingLabel>(questName);
			quest.SetText(questName + "\n  => " + questStep);
			quest.AddThemeColorOverride("font_color", critical ? CriticalColor : DefaultColor);
		}
		else
		{
			quest = new BlinkingLabel();
			_questContainer.AddChild(quest);
			quest.Name = questName;

			quest.SetText(questName + "\n  => " + questStep);
			quest.AddThemeColorOverride("font_color", critical ? CriticalColor : DefaultColor);
			_numTreeItems += 2;
		}
		UpdateTreeSize();

		Blink(quest, critical ? CriticalColor : DefaultColor);
	}

	public void Complete(string questName)
	{
		if (_questContainer.HasNode(questName))
		{
			BlinkingLabel quest = _questContainer.GetNode<BlinkingLabel>(questName);
			quest.EmitSignal(BlinkingLabel.SignalName.CancelAnimation);
			quest.SetText("[COMPLETED] " + questName);
			quest.AddThemeColorOverride("font_color", DefaultColor);
			_numTreeItems--;
			UpdateTreeSize();
		}
		else
		{
			GD.PushWarning(questName + " not found to complete");
		}
	}

	private void UpdateTreeSize()
	{
		int size = _numTreeItems * _fontSize;
		size = size > MaxQuestContainerSize ? MaxQuestContainerSize : size;
		_questContainer.GetParent<ScrollContainer>().CustomMinimumSize = new Vector2(0, size);
	}

	public void Wipe()
	{
		foreach (Node child in _questContainer.GetChildren())
		{
			_questContainer.RemoveChild(child);
		}
		_numTreeItems = 0;
		UpdateTreeSize();
	}

	private async void Blink(BlinkingLabel label, Color originalColor)
	{
		// label theme colors cause weird effects with animation, so the label is first animated to the "current" color and then
		// the color override is removed again for the duration of the animation
		Tween tween = GetTree().CreateTween();
		await ToSignal(tween.TweenProperty(label, "modulate", originalColor, 0.001), Tween.SignalName.Finished);
		tween.Kill();
		label.RemoveThemeColorOverride("font_color");

		// one frequency := animation to highlight color and back
		float frequency = Frequency / 2;

		tween = GetTree().CreateTween().SetLoops((int)(Duration / Frequency));
		tween.TweenProperty(label, "modulate", HighlightColor, frequency);
		tween.TweenProperty(label, "modulate", originalColor, frequency);

		// wait either for animation to finish or for animation to get canceled 
		// (e.g. due to quest getting completed before animation is done (idk if this is realistic but still just to be safe))
		var animationSignal = ToSignal(tween, Tween.SignalName.Finished);
		var cancelSignal = ToSignal(label, BlinkingLabel.SignalName.CancelAnimation);
		await Task.WhenAny(
			Task.Run(async () => await animationSignal),
			Task.Run(async () => await cancelSignal)
		);
		tween.Kill();

		// animate back to the required color of the text, kill animation and add theme override back again
		tween = GetTree().CreateTween();
		label.AddThemeColorOverride("font_color", label.Completed ? DefaultColor : originalColor);
		await ToSignal(tween.TweenProperty(label, "modulate", DefaultColor, 0.001), Tween.SignalName.Finished);
		tween.Kill();
	}

	private partial class BlinkingLabel : Label
	{
		internal bool Completed = false;
		[Signal] public delegate void CancelAnimationEventHandler();
		internal BlinkingLabel()
		{
			CancelAnimation += () => Completed = true;
		}

	}
}
