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

public class DialogueManager : MonoBehaviour
{
    private Queue<DialogueLine> sentences;
    private Dialogue currentDialogue;
    private DialogueVoice currentDialogueVoice;
    private float maxDialogueWaitTime = 1.0f;

    // use array of audio sources so we don't cut off any of them
    private AudioSource[] voiceSourcePool;
    private int audioSourcePoolIndex = 0;

    public TextMeshProUGUI nameText;
    public TextMeshProUGUI dialogueText;

    public TextMeshProUGUI itemText; // displays name of nearby item
    public TextMeshProUGUI pickupHint; // tells the player to press 'E' to pickup

    public Animator animator;

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        sentences = new Queue<DialogueLine>();
        voiceSourcePool = GetComponentsInChildren<AudioSource>();
    }

    public void ReloadReferences()
    {
        nameText = GameObject.FindWithTag("DialogNameText").GetComponent<TextMeshProUGUI>();
        dialogueText = GameObject.FindWithTag("DialogMessageText").GetComponent<TextMeshProUGUI>();
        itemText = GameObject.FindWithTag("DialogItemText").GetComponent<TextMeshProUGUI>();
        pickupHint = GameObject.FindWithTag("ItemPickupText").GetComponent<TextMeshProUGUI>();
        animator = GameObject.FindWithTag("DialogContainer").GetComponent<Animator>();
    }

    public void StartDialogue(Dialogue dialogue, DialogueVoice dialogueVoice)
    {
        animator.SetBool("IsOpen", true);

        sentences.Clear();
        currentDialogue = dialogue;
        currentDialogueVoice = dialogueVoice;

        foreach (DialogueLine sentence in dialogue.sentences)
        {
            sentences.Enqueue(sentence);
        }

        currentDialogue.isActive = true;
        DisplayNextSentence();
    }

    public void DisplayNextSentence()
    {
        if (sentences.Count == 0)
        {
            EndDialogue();
            return;
        }

        DialogueLine sentence = sentences.Dequeue();
        StopAllCoroutines();
        StopVoices();
        StartCoroutine(TypeSentence(sentence));
    }

    public void EndDialogue()
    {
        animator.SetBool("IsOpen", false);
        StopAllCoroutines();
        StopVoices();

        if (currentDialogue != null)
        {
            currentDialogue.isActive = false;
        }
    } 

    IEnumerator TypeSentence(DialogueLine sentence)
    {
        dialogueText.text = "";

        if (sentence.isDoug)
        {
            nameText.text = "Doug";
        }
        else
        {
            nameText.text = currentDialogue.charName;
        }
            
        char[] sentenceCharArray = sentence.line.ToCharArray();
        for (int i = 0; i < sentenceCharArray.Length; i++)
        {
            dialogueText.text += sentenceCharArray[i];

            if (sentence.isDoug)
            {
                // TODO: Add Doug voice
                yield return new WaitForSeconds(0.03f);
            }
            else
            {
                if (currentDialogueVoice != null && currentDialogueVoice.voice != Voices.None)
                {
                    if (i % currentDialogueVoice.speechInterval == 0)
                    {
                        AudioClip voiceToPlay = currentDialogueVoice.GetClipFromChar(char.ToLower(sentenceCharArray[i]));

                        if (voiceToPlay != null)
                        {
                            PlayNextClip(voiceToPlay);
                        }
                    }

                    yield return new WaitForSeconds(maxDialogueWaitTime - currentDialogueVoice.talkSpeed * maxDialogueWaitTime);
                }
                else
                {
                    // TODO: Add speed variable to non-voices (Talkable.cs)
                    yield return new WaitForSeconds(0.03f);
                }
            }
        }
    }

    public void ShowItemText(string itemName)
    {
        itemText.text = itemName;
        pickupHint.text = "Press \"E\" to pick up";
    }

    public void HideItemText()
    {
        itemText.text = "";
        pickupHint.text = "";
    }

    private void PlayNextClip(AudioClip clip)
    {
        audioSourcePoolIndex = (audioSourcePoolIndex + 1) % voiceSourcePool.Length;
        voiceSourcePool[audioSourcePoolIndex].clip = clip;
        voiceSourcePool[audioSourcePoolIndex].Play();
    }

    private void StopVoices()
    {
        foreach (AudioSource voice in voiceSourcePool)
        {
            voice.Stop();
        }
    }
}
