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

public class TextManager : MonoBehaviour
{
    public static TextManager Instance { get; private set; }

    [Header("Text Settings")]
    public float defaultTypeSpeed = 0.01f;
    public Color defaultTextColor = Color.white;

    private Coroutine currentTextCoroutine;
    private StringBuilder currentTextBuilder;
    private Vector2 currentTextPosition;
    private bool isTyping = false;
    private ScriptCommand currentCommand;

    void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
        }
        else
        {
            Destroy(gameObject);
        }

    }

    public void ShowText(List<TextToken> tokens, ScriptCommand cmd)
    {
        currentCommand = cmd;

        // Останавливаем предыдущую корутину, если она активна
        if (currentTextCoroutine != null)
        {
            StopCoroutine(currentTextCoroutine);
        }

        currentTextCoroutine = StartCoroutine(ProcessTokensCoroutine(tokens));
    }

    private IEnumerator ProcessTokensCoroutine(List<TextToken> tokens)
    {
        isTyping = true;
        currentTextBuilder = new StringBuilder();
        App.UI.ClearText();

        for (int a = 0; a < tokens.Count - 1; a++)
        {
            TextToken token = tokens[a];
            switch(token.Key)
            {
                case "text":
                    yield return StartCoroutine(TypeText(token.Value));
                    break;
                case "cmd":
                    yield return StartCoroutine(ProcessCommand(token.Value));
                    break;
                case "color":
                    SetTextColor(token.Value);
                    break;
                case "pause":
                    yield return new WaitForSeconds(float.Parse(token.Value) / 60);
                    break;
                case "user_selection":
                    byte varCount = byte.Parse(token.Value);            //preparing selection strings
                    List<string> selectionList = new List<string>();
                    for (byte x = 1; x <= varCount * 2; x += 2) //string and \n
                    {
                        selectionList.Add(tokens[a+x].Value);
                    }
                    
                    a += varCount * 2; //jump over selection strings (text + \n)
                    App.UI.ShowSelection(selectionList);
                    break;
            }
        }

        isTyping = false;
    }

    private IEnumerator TypeText(string text)
    {
        foreach (char c in text)
        {
            currentTextBuilder.Append(c);
            App.UI.SetText(currentTextBuilder.ToString());

            // Обновляем тень, если она есть
            if (App.UI.shadowText != null)
            {
                App.UI.shadowText.text = currentTextBuilder.ToString();
            }

            yield return new WaitForSeconds(defaultTypeSpeed);
        }
    }

    private IEnumerator ProcessCommand(string command)
    {
        switch (command)
        {
            case "newline":
                currentTextBuilder.Append("\n");
                App.UI.AppendText("\n");
                break;

            case "tab":
                currentTextBuilder.Append("   ");
                App.UI.AppendText("   ");
                break;

            case "wait_input":
                App.UI.ShowCursor(true);
                yield return WaitForInput();
                App.UI.ShowCursor(false);
                break;

            case "wait_selection":

                yield return WaitForSelectionInput();
                App.VM.SetSelectionVariable(App.UI.userSelectionVariant);             //TODO: 
                App.UI.WipeSelection();
                break;

            case "wipe":
                currentTextBuilder.Clear();
                App.UI.ClearText();
                break;

            case "end":
                yield break;
        }
    }

    private IEnumerator WaitForInput()
    {
        bool inputReceived = false;

        while (!inputReceived)
        {
            if (Input.GetButtonDown("Submit"))
            {
                inputReceived = true;
            }
            yield return null;
        }

        if (currentCommand != null)
        {
            App.VM.MarkCommandCompleted(currentCommand);
        }
    }    

    private IEnumerator WaitForSelectionInput()
    {
        bool acceptReceived = false;

        while (!acceptReceived)
        {
            if (Input.GetKeyDown(KeyCode.DownArrow) || Input.GetKeyDown(KeyCode.UpArrow))
            {
                //recieve input for
            }

            if (Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.Space) || Input.GetKeyDown(KeyCode.Return))
            {
                acceptReceived = true;
            }

            yield return null;

         
        }

        if (currentCommand != null)
        {

            App.VM.MarkCommandCompleted(currentCommand);
        }
    }

    private void SetTextColor(string colorCode)
    {
        int colorIndex;
        if (int.TryParse(colorCode, out colorIndex))
        {
            string colorTag = $"</color><color={GetColorByIndex(colorIndex)}>";
            currentTextBuilder.Append(colorTag);
            App.UI.AppendText(colorTag);
        }
    }

    private string GetColorByIndex(int index)
    {
        switch (index)
        {
            case 1: return "white";
            case 3: return "gray";
            case 5: return "#D327F5"; //pink!
            case 7: return "#27F5D3"; //blue
            case 9: return "#27F56C"; //green
            case 11: return "yellow";
            case 13: return "#F56C27"; //orange
            default: return "white";
        }
    }

    public void SkipTyping()
    {
        if (isTyping && currentTextCoroutine != null)
        {
            StopCoroutine(currentTextCoroutine);
            isTyping = false;
        }
    }

    public bool IsTyping()
    {
        return isTyping;
    }
}