using System;
using UnityEngine;
using mgaia.Utils.Pause;
using mgaia.Utils.Text;

namespace mgaia.Utils.Typing
{
    /// <summary>
    /// Behaviour utilizado para simular o esquema de máquina de escrever em algum elemento que mostra texto
    /// </summary>
    /// <owner>Victor</owner>
    public class TypingBehaviour : PausableBehaviour
    {
        public event Action<bool> FinishedTyping;

        private ITypingMethod mTypingMethod;
        private ITextInterpreter mTextInterpreter;
        private string mTextToType;
        private bool mIsTyping;

        /// <summary>
        /// Interface para realizar a escrita
        /// </summary>
        public ITypingMethod TypingMethod
        {
            get { return mTypingMethod; }
            set
            {
                Assert.AssertTrue(!mIsTyping, "Não se pode alterar o método de escrita enquanto uma escrita está rodando!");

                mTypingMethod = value;
            }
        }

        /// <summary>
        /// Interface do interpretador de texto
        /// </summary>
        public ITextInterpreter TextInterpreter
        {
            get { return mTextInterpreter; }
            set
            {
                Assert.AssertTrue(!mIsTyping, "Não se pode alterar o interpretador de texto enquanto uma escrita está rodando!");

                mTextInterpreter = value;
            }
        }

        /// <summary>
        /// Começa a escrita
        /// </summary>
        public void Begin(string text, float delay)
        {
            Assert.AssertTrue(!mIsTyping, "Uma operação de escrita já está ocorrendo nesse componente!");

            if (!mIsTyping)
            {
                mIsTyping = true;

                mTextToType = text;

                TextInterpreter.Begin(text);

                GameTimeScheduler.Schedule(GameTimeScheduler.ScheduleType.Normal, TypeText, (uint)TextInterpreter.GetTextSize() + 1, delay);
            }
        }

        protected override void OnPauseStateChanged()
        {
            GameTimeScheduler.SetPause(TypeText, IsPaused);
        }

        /// <summary>
        /// Termina a escrita, podendo escrever a string inteira ou não
        /// </summary>
        public void End(bool cancel)
        {
            if (!cancel)
            {
                TypingMethod.TypeAllString(mTextToType);
            }

            InvokeFinishedTyping(cancel);

            GameTimeScheduler.RemoveAll(TypeText);
        }

        /// <summary>
        /// Escreve caractere a caractere
        /// </summary>
        private void TypeText()
        {
            string stringToWrite = TextInterpreter.GetNextFragmentToWrite();

            if (stringToWrite != null)
            {
                foreach (char charToWrite in stringToWrite)
                {
                    TypingMethod.Type(charToWrite);
                }
            }
            else
            {
                InvokeFinishedTyping(false);
            }
        }

        /// <summary>
        /// Invoca o evento de término de escrita
        /// </summary>
        /// <param name="canceled"></param>
        private void InvokeFinishedTyping(bool canceled)
        {
            mIsTyping = false;

            if (FinishedTyping != null)
            {
                FinishedTyping(canceled);
            }
        }

        private void OnDestroy()
        {
            GameTimeScheduler.RemoveAll(TypeText);
        }
    }
}