using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;

namespace TwitchInGames.Test {
    public class UnitTest_Chat : UnitTest_Auth {
        private static string defaultChannel = "twiggieg";
        private static string msg = "HeyGuys";

        private Chat chatObj;

#pragma warning disable 649 // Field '*' is never assigned to, and will always have its default value *
        [SerializeField]
        private GameObject messagePrefab;

        [SerializeField]
        private GameObject outputPanel;

        [SerializeField]
        private InputField channelInput;

        [SerializeField]
        private InputField msgInput;

        [SerializeField]
        private Dropdown channelDropdown;
#pragma warning restore 649

        private Queue<GameObject> messages = new Queue<GameObject>(32);

        public void SignIn() {
            StartCoroutine(InternalSignIn());
        }

        private IEnumerator InternalSignIn() {
            GetNewUserNext();
            yield return new WaitUntil(() => !String.IsNullOrEmpty(authToken));
            if(chatObj != null) {
                Destroy(chatObj);
            }
            chatObj = (new GameObject("ChatObj(null)")).AddComponent<Chat>();
            var coroutine = chatObj.SignIn(clientId, authToken);
            yield return coroutine;
            if(coroutine.Exception == null) {
                OnSignInSuccess();
            } else {
                Debug.LogErrorFormat("UnitTest_Chat.SignIn error: {0}", coroutine.Exception);
            }
        }

        public void Join() {
            StartCoroutine(InternalJoin());
        }

        public IEnumerator InternalJoin() {
            string channelName = defaultChannel;
            if(!String.IsNullOrEmpty(channelInput.text)) {
                channelName = channelInput.text;
                channelInput.Select();
                channelInput.text = "";
            }
            var coroutine = chatObj.JoinChannel(channelName, OnReceiveMessage);
            yield return coroutine;
            try {
                var channel = coroutine.Value;
                OnJoinSuccess(channel);
            } catch(Exception ex) {
                Debug.LogErrorFormat("UnitTest_Chat.Join error: {0}", ex);
            }
        }

        public void Part() {
            StartCoroutine(InternalPart());
        }

        public IEnumerator InternalPart() {
            string channelName = channelDropdown.captionText.text;
            var coroutine = chatObj.Channels[channelName].Depart();
            yield return coroutine;
            if(coroutine.Exception == null) {
                OnDepartSuccess(channelName);
            } else {
                Debug.LogErrorFormat("UnitTest_Chat.Part error: {0}", coroutine.Exception);
            }
        }

        public void SendChatMsg() {
            StartCoroutine(InternalSendChatMsg());
        }

        public IEnumerator InternalSendChatMsg() {
            string channelName = channelDropdown.captionText.text;
            if(!String.IsNullOrEmpty(msgInput.text)) {
                msg = msgInput.text;
            }
            var coroutine = chatObj.Channels[channelName].SendLine(msg);
            yield return coroutine;
            if(coroutine.Exception != null) {
                Debug.LogErrorFormat("UnitTest_Chat.SendChatMsg error: {0}", coroutine.Exception);
            }
            msgInput.Select();
            msgInput.text = "";
        }

        private void OnSignInSuccess() {
            OutputNewLine("<color=red>[SYSTEM]</color>", chatObj.Login, "SIGNED IN");
            chatObj.gameObject.name = "ChatObj(" + chatObj.Login + ")";
        }

        private void OnJoinSuccess(Chat.Channel channel) {
            OutputNewLine("<color=red>[SYSTEM]</color>", chatObj.Login, "JOINED CHANNEL <b>[" + channel.Name + "]</b>");

            channelDropdown.ClearOptions();
            List<string> channelList = new List<string>(chatObj.Channels.Keys);
            channelDropdown.AddOptions(channelList);
        }

        private void OnDepartSuccess(string channelName) {
            OutputNewLine("<color=red>[SYSTEM]</color>", chatObj.Login, "DEPARTED CHANNEL <b>[" + channelName + "]</b>");

            channelDropdown.ClearOptions();
            List<string> channelList = new List<string>(chatObj.Channels.Keys);
            channelDropdown.AddOptions(channelList);
        }

        private void OnReceiveMessage(Chat.Channel channel, string userName, string message) {
            OutputNewLine("[" + channel.Name + "]", userName, message);
        }

        private void OutputNewLine(string channelname, string username, string message) {
            GameObject gameobject;
            if(messages.Count >= 32) {
                gameobject = messages.Dequeue();
            } else {
                gameobject = Instantiate(messagePrefab, outputPanel.transform);
            }
            gameobject.GetComponent<Message>().Init(new string[] { channelname, username, message });
            gameobject.transform.SetAsFirstSibling();
            messages.Enqueue(gameobject);
        }
    }
}
