﻿using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

#if USING_TMP
using TMPro;
#endif


namespace SimplifyXR
{

    public enum TextType
    {
        Standard
#if USING_TMP
        , TextMeshPro
        , TextMeshProUGUI
#endif
    }

    public class TextAdapter
    {
        public static System.Type GetTextType(TextType textType, bool list = false)
        {
            switch (textType)
            {
                case TextType.Standard:
                    return list ? typeof(List<Text>) : typeof(Text);
#if USING_TMP
                case TextType.TextMeshPro:
                    return list ? typeof(List<TMP_Text>) : typeof(TMP_Text);
                case TextType.TextMeshProUGUI:
                    return list ? typeof(List<TMP_Text>) : typeof(TMP_Text);
#endif
                default:
                    return list ? typeof(List<Text>) : typeof(Text);
            }
        }

        public static System.Type GetFontStyleType(
            TextType textType)
        {
            switch (textType)
            {
                case TextType.Standard:
                    return typeof(FontStyle);
#if USING_TMP
                case TextType.TextMeshPro:
                    return typeof(TMPro.FontStyles);
                case TextType.TextMeshProUGUI:
                    return typeof(TMPro.FontStyles);
#endif
                default:
                    return typeof(FontStyle);
            }
        }
    }

    /// <summary>
    /// Initiates action when a UI Text is selected from canvas.
    /// </summary>
    [DirectiveCategory(DirectiveCategories.Initiator, DirectiveSubCategory.UI, 
        prettyName ="Text Selected",
        directiveInfo="This initiator will start a sequence when a <b>Text</b> or <b>Text Mesh Pro</b> " +
        "object is <b>selected</b>.")]
    public class TextSelected : Initiator
    {

        /// <summary>
        /// The type of text to modify
        /// </summary>
        //#if USING_TMP
        [Tooltip("The type of text to modify.")]
        public TextType textType;
        //#endif

        /// <summary>
        /// The gameObject containing text.
        /// </summary>
#if UNITY_EDITOR
        [Tooltip("The gameObject containing text.")]
#endif
        public GameObject TextParent;
        /// <summary>
        /// A bool that indicates whether the gameObject contains multiple text components.
        /// </summary>
#if UNITY_EDITOR
        [Tooltip("A bool that indicates whether the gameObject contains multiple text components.")]
#endif
        public bool MultipleTexts = false;
        /// <summary>
        /// The text list to listen to
        /// </summary>
        private List<MonoBehaviour> textList = new List<MonoBehaviour>();
        /// <summary>
        /// The text to listen to
        /// </summary>
        /// 
#if USING_TMP
        private TextMeshProUGUI textToPressPro;
#endif
        private MonoBehaviour textToPress;

        public override List<KnobKeywords> ReceiveKeywords()
        {
            return new List<KnobKeywords>();
        }

        public override List<KnobKeywords> SendKeywords()
        {
            return new List<KnobKeywords>(){
                new KnobKeywords("TextGameObject", typeof(GameObject)),
                new KnobKeywords("TextTitle", typeof(string)),
                new KnobKeywords("TextComponent", TextAdapter.GetTextType(textType)),
                new KnobKeywords("ListOfTextFields", TextAdapter.GetTextType(textType,true))
            };
        }

        void Start()
        {
            Debug.Log("Starting to listen!");

            CreateListOfContent();
            Debug.Log(textList.Count);

            for (int i = 0; i < textList.Count; i++)
            {
                if (textList[i] != null)
                {
                    MonoBehaviour textObject = textList[i];
                    Debug.Log(textObject.name);
                    //textObject.gameObject.GetOrAddComponent<EventTrigger>();
                    if (textObject.gameObject.GetComponent<EventTrigger>() == null) textObject.gameObject.AddComponent<EventTrigger>(); EventTrigger trigger = textObject.gameObject.GetComponent<EventTrigger>();
                    EventTrigger.Entry onEntry = new EventTrigger.Entry();
                    onEntry.eventID = EventTriggerType.PointerClick;
                    onEntry.callback.RemoveAllListeners();
                    onEntry.callback.AddListener((eventData) => { AssignText(textObject); });
                    trigger.triggers.Add(onEntry);
                }
                else
                    SimplifyXRDebug.SimplifyXRLog(SimplifyXRDebug.Type.AuthorError, "There is no text on this Directive {0}.", SimplifyXRDebug.Args(this));
            }
        }

        /// <summary>
        /// Assign the passed text to be sent as data.
        /// </summary>
        private void AssignText(MonoBehaviour textHit)
        {
            textToPress = textHit;
            Initiate();
        }

        public override void Initiate()
        {
            switch (textType)
            {
                case TextType.Standard:
                    SendData<Text>();
                    break;
#if USING_TMP
                case TextType.TextMeshPro:
                    SendData<TextMeshProUGUI>();
                    break;
#endif
            }

            base.Initiate();
            SimplifyXRDebug.SimplifyXRLog(SimplifyXRDebug.Type.AuthorDebug, "This text {0} has been pressed.", SimplifyXRDebug.Args(textToPress));
        }

        /// <summary>
        /// Calls the recursive method using the the transform parameter given.
        /// </summary>
        private void CreateListOfContent()
        {
            if (TextParent != null)
                switch (textType)
                {
                    case TextType.Standard:
                        GetAndListAllContentWithinTransform<Text>(TextParent.transform);
                        break;

#if USING_TMP
                    case TextType.TextMeshPro:
                        GetAndListAllContentWithinTransform<TextMeshProUGUI>(TextParent.transform);
                        break;
#endif
                }
            else
                SimplifyXRDebug.SimplifyXRLog(SimplifyXRDebug.Type.AuthorDebug, "There is no ScrollViewParent {0}.", SimplifyXRDebug.Args(this));
        }

        /// <summary>
        /// Get All the Button or Text Components and Add them to a List
        /// </summary>
        private void GetAndListAllContentWithinTransform<T>(Transform transform) where T : MonoBehaviour
        {
            if (transform.GetComponent<T>() != null)
            {
                //transform.GetComponent<T>().raycastTarget = true;
                // Don't Add child Gameobject if it's already in the list
                if (!textList.Contains(transform.GetComponent<T>()))
                    textList.Add(transform.GetComponent<T>());
            }
            // For each child transform in Parent Object
            foreach (Transform child in transform)
            {
                if (child.GetComponent<T>() != null)
                {
                    //transform.GetComponent<T>().raycastTarget = true;
                    // Don't Add child Gameobject if it's already in the list
                    if (!textList.Contains(child.GetComponent<T>()))
                        textList.Add(child.GetComponent<T>());
                }
                GetAndListAllContentWithinTransform<T>(child);
            }
        }

        private void SendData<T>() where T : MonoBehaviour
        {
            string stringText = null;
            T textComponent = null;
            ScrollRect scrollViewComponent = null;
            if (textToPress.gameObject.GetComponent<T>() != null)
            {
                stringText = textToPress.gameObject.GetComponent<T>().name;
                textComponent = textToPress.GetComponent<T>();
            }
            if (textToPress.gameObject.GetComponentInParent<ScrollRect>() != null)
                scrollViewComponent = textToPress.gameObject.GetComponentInParent<ScrollRect>();
            var thisData = new List<object> { textToPress.gameObject, stringText, textComponent, textList, scrollViewComponent };
            var thisKeywords = new List<string> { "TextGameObject", "TextTitle", "TextComponent", "ListOfTextFields", "ScrollViewComponent" };
            AddPassableData(thisKeywords, thisData);
        }
    }
}