using Godot;
using Sfs3.Client.Entities;
using System;
using System.Threading.Tasks;

public partial class ChatPanel : Panel
{
	[Export]
	public ScrollContainer scrollContainer;
	[Export]
	public VBoxContainer messagesContainer;
	[Export]
	public LineEdit messageInput;
	[Export]
	public Button sendButton;
	[Export]
	public Button closeButton;
	[Export]
	public bool showCloseButton = false;
	[Export]
	public Label withNameLabel;
	[Export]
	public bool disabled;

	private Action<string> sendMessageAction;

	private string userName;
	private string displayName;
	private string lastSenderName;

	public override void _Ready()
	{
		closeButton.Visible = showCloseButton;
		Disabled = disabled;
	}

	public Action<string> SendMessageAction
	{
		get => sendMessageAction;
		set => sendMessageAction = value;
	}

	public string UserName => userName;
	public string DisplayName => displayName;
	
	public bool Disabled
	{
		get => disabled;

		set
		{
			messageInput.Editable = !value;
			sendButton.Disabled = value;
		}
	}

	public void SetUser(string name, string nickname = null)
	{
		userName = name;

		// Display name
		displayName = nickname != null && nickname.Length > 0 ? nickname : name;

		if (displayName != null)
			withNameLabel.Text = "with\n" + displayName;
		else
			withNameLabel.Text = "";
	}

	public void SetVisible()
    {
        this.Visible = true;
    }

	public void ResetAndHide()
	{
		// Reset
		Reset();

		// Hide
		this.Visible = false;
	}
	
	public void Reset()
	{
		// Remove all messages
        var children = messagesContainer.GetChildren();
		foreach (var child in children)
			child.Free();

		messageInput.Text = "";
		lastSenderName = null;
		Disabled = false;

		SetUser(null);
    }
	
	public void OnCloseButtonClick()
	{
		ResetAndHide();
    }

    public void OnSendButtonClick()
	{
		SendMessage();
    }

	public void OnChatMsgInputSubmit(string msg)
	{
		SendMessage();
	}

    public void SetFocus()
	{
		messageInput.GrabFocus();
    }

	/**
     * Display a chat message.
     */
	public void PrintChatMessage(string message, string senderName, bool isMe, DateTime? date)
	{
		if (date == null)
			date = DateTime.Now;
		
		string resName = isMe ? "ChatMsgOut.tscn" : "ChatMsgIn.tscn";

		Node msgNode = ResourceLoader.Load<PackedScene>("res://scenes/sub/" + resName).Instantiate();
		messagesContainer.AddChild(msgNode);

		ChatMsg msgInst = msgNode.GetNode<ChatMsg>(".");

		// Print sender name, unless they are the same of the last message
		if (senderName == lastSenderName)
			msgInst.SetUserName("");
		else
		{
			msgInst.SetUserName(senderName);
			lastSenderName = senderName;
		}

        // Print chat message
		msgInst.SetMessage(message);

		// Print time
		msgInst.SetTime(date?.ToString("HH:mm"));
		
		// Scroll view to bottom
		ScrollChatToBottom();
	}

    /**
     * Display a system message.
     */
    public void PrintSystemMessage(string message)
	{
		// Print message
		Label sysMsg = new Label();
		sysMsg.Text = message;
		sysMsg.HorizontalAlignment = HorizontalAlignment.Center;
		sysMsg.AutowrapMode = TextServer.AutowrapMode.Word;

		messagesContainer.AddChild(sysMsg);

        // Scroll view to bottom
		ScrollChatToBottom();
    }

	private void SendMessage()
	{
		if (sendMessageAction != null && messageInput.Text != "")
		{
			sendMessageAction.Invoke(messageInput.Text);

			messageInput.Text = "";

			SetFocus();
		}
	}

	private void ScrollChatToBottom()
	{
		Task.Delay(new TimeSpan(0, 0, 0, 0, 20)).ContinueWith(o => {
			Callable.From(DeferredScrollToBottom).CallDeferred();
		});
	}
	
	private void DeferredScrollToBottom()
    {
        scrollContainer.ScrollVertical = (int)scrollContainer.GetVScrollBar().MaxValue;
    }
}
