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


public class ChatExample : MonoBehaviour {
    [SerializeField]
    private GameObject messagePrefab;

    [SerializeField]
    private GameObject panel;

    [SerializeField]
    private InputField channelInput;

    [SerializeField]
    private GameObject joinButton;

    [SerializeField]
    private GameObject departButton;

    [SerializeField]
    private InputField sendInput;

    [SerializeField]
    private Button sendButton;

    [SerializeField]
    private Transform channelScrollViewContent;

    private Chat chat;
    private Chat.Channel channel;
    private Queue<GameObject> messages = new Queue<GameObject>(32);

    public GameObject Panel { get { return panel; } }

    private void Awake() {
        chat = GetComponent<Chat>();
    }

    private void OnDisable() {
        SignOut();
    }

    #region Sign In Sign Out

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

    public void SignOut() {
        chat.SignOut();
        channel = null;
        joinButton.SetActive(true);
        departButton.SetActive(false);
        channelInput.interactable = true;
        channelInput.GetComponent<InputField>().text = "";
        sendInput.interactable = false;
        sendButton.interactable = false;
        while (messages.Count > 0) {
            var message = messages.Dequeue();
            Destroy(message);
        }
    }

    private IEnumerator InternalSignIn() {
        var coroutine = chat.SignIn(TwitchSettings.clientId, TwitchSettings.Token);
        yield return coroutine;
        if (coroutine.Exception == null)
            Debug.Log("[TwitchInGames] Signed in IRC.");
        else 
            Debug.LogErrorFormat("[TwitchInGames] ChatExample.SignIn error: {0}", coroutine.Exception);
    }

    #endregion Sign In Sign Out

    #region Join

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

    public IEnumerator InternalJoin() {
        if (String.IsNullOrEmpty(channelInput.text)) {
            throw new System.ArgumentNullException("Channel Name", "[TwitchInGames] Please input channel name.");
        }
        var coroutine = chat.JoinChannel(channelInput.text,
            (Chat.Channel channel, string userName, string message) => LogMessage(userName, message));
        yield return coroutine;
        try {
            channel = coroutine.Value;
            joinButton.SetActive(false);
            departButton.SetActive(true);
            channelInput.interactable = false;
            sendInput.interactable = true;
            sendButton.interactable = true;
        }
        catch (Exception ex) {
            Debug.LogErrorFormat("[TwitchInGames] ChatExample.Join error: {0}", ex);
        }
    }

    #endregion Join

    #region Depart

    public void Depart() {
        StartCoroutine(InternalDepart());
    }

    public IEnumerator InternalDepart() {
        var coroutine = chat.Channels[channel.Name].Depart();
        yield return coroutine;
        if (coroutine.Exception == null) {
            channel = null;
            joinButton.SetActive(true);
            departButton.SetActive(false);
            channelInput.interactable = true;
            sendInput.interactable = false;
            sendButton.interactable = false;
        }
        else {
            Debug.LogErrorFormat("[TwitchInGames] ChatExample.Depart error: {0}", coroutine.Exception);
        }
    }

    #endregion Depart

    #region Send

    public void Send() {
        StartCoroutine(InternalSend());
    }

    public IEnumerator InternalSend() {
        var coroutine = chat.Channels[channel.Name].SendLine(sendInput.text);
        yield return coroutine;
        if (coroutine.Exception != null) {
            Debug.LogErrorFormat("[TwitchInGames] ChatExample.Send error: {0}", coroutine.Exception);
        }
        LogMessage(chat.Login, sendInput.text);
        sendInput.Select();
        sendInput.text = "";
    }

    #endregion Send

    private void LogMessage(string username, string message) {
        GameObject gameobject;
        if (messages.Count >= 32) {
            gameobject = messages.Dequeue();
        }
        else {
            gameobject = Instantiate(messagePrefab, channelScrollViewContent);
        }
        Text[] text = gameobject.GetComponentsInChildren<Text>();
        text[0].text = username;
        text[1].text = message;

        gameobject.transform.SetAsFirstSibling();
        messages.Enqueue(gameobject);
    }
}
