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

public class LogicTrayUI : LogicElementHolder
{

    //[SerializeField]
    //protected List<LogicBlock> list;
    [SerializeField]
    protected LogicElementUI Prefab;
    [SerializeField]
    protected int insertIndex = -1;
    [SerializeField]
    private Transform content;

    [SerializeField]
    private GameObject playButton;
    [SerializeField]
    private GameObject returnButton;
    [SerializeField]
    private Image border;

    [SerializeField]
    private int maxLength = 6;

    [SerializeField]
    public BlockReader reader;

    [SerializeField]
    private List<QueueData> readerQueue = new List<QueueData>();

    #region Unity Functions
    public void Start()
    {

        readerQueue.Add(new QueueData(reader, border.color));

        UpdateDisplay();

        
    }

    protected override void OnEnable()
    {
        base.OnEnable();

        if (reader != null)
            reader.OnUpdate += UpdateDisplay;
    }

    protected override void OnDisable()
    {
        base.OnDisable();
        if (reader != null)
            reader.OnUpdate -= UpdateDisplay;
    }
    #endregion Unity Functions

    public void SetBlockReader(BlockReader newBlockReader)
    {
        if (reader != null)
            reader.OnUpdate -= UpdateDisplay;

        reader = newBlockReader;
        reader.OnUpdate += UpdateDisplay;
        UpdateDisplay();
    }

    public void OnClick_Return()
    {
        if (readerQueue.Count <= 1)
            return;

        QueueData lastData = readerQueue[readerQueue.Count - 1];
        readerQueue.RemoveAt(readerQueue.Count - 1);

        //lastData.block.blockReader.LogicChain = new List<LogicBlock>(lastData.reader.LogicChain);



        border.color = readerQueue[readerQueue.Count - 1].color;
        //  readerQueue[readerQueue.Count - 1].reader.LogicChain = new List<LogicBlock>(reader.LogicChain);
        SetBlockReader(readerQueue[readerQueue.Count - 1].reader);
        
        
        UpdateDisplay();

    }

    [ContextMenu("Update Display")]
    public void UpdateDisplay()
    {
        if (reader == null)
            return;

        //Destroy all children
        int destroyedCount = content.childCount; //we need to know how many were destroyed since unity doesn't actually destroy anything until the end of the frame
        foreach (Transform child in content)
            Destroy(child.gameObject);

        //Instatiate logicElement prefab
        foreach (LogicBlock element in reader.LogicChain)
        {
            LogicElementUI elementUI = Instantiate(Prefab.gameObject, content).GetComponent<LogicElementUI>();
            elementUI.Initialise(element, this,false);
        }

        //Add insertIndex object if needed
        if (insertIndex != -1)
        {
            GameObject elementObject = Instantiate(Prefab.gameObject, content);

            if (reader.Length < maxLength)
            {
                elementObject.GetComponentInChildren<TextMeshProUGUI>().text = "insert";
                elementObject.GetComponentInChildren<Image>().color = new Color(0.5f, 0.5f, 0.5f, 0.25f);
            }
            else
            {
                elementObject.GetComponentInChildren<TextMeshProUGUI>().text = "X";
                elementObject.GetComponentInChildren<Image>().color = new Color(1.0f, 0.25f, 0.25f, 0.5f);
            }

            //Set sibling index to where we want it in list + add destroyedCount since technically they are still here
            elementObject.transform.SetSiblingIndex(destroyedCount + insertIndex);
        }

        playButton.SetActive(readerQueue.Count <= 1);
        returnButton.SetActive(readerQueue.Count > 1);



    }

    #region LogicElementHolder Implementation

    /// <summary>
    /// When a LogicElement has started being dragged from this Tray
    /// </summary>
    /// <param name="element">Element which is being dragged</param>
    public override void OnRemove(LogicElementUI element)
    {
        Vector2 offset = new Vector2(element.rectTransform.rect.width / 2, 0);
        int index = GetInsertIndex(element.rectTransform, offset);

        Debug.Log("Removing at " + index);

        if (index >= reader.LogicChain.Count)
            index = reader.LogicChain.Count - 1;
        reader.LogicChain.RemoveAt(index);
    }

    /// <summary>
    /// When a logicElement needs to be added back to this Tray
    /// </summary>
    /// <param name="element">Element to add</param>
    public override void OnAdd(LogicElementUI element)
    {
        Vector2 offset = new Vector2(element.rectTransform.rect.width / 2, 0);
        int index = GetInsertIndex(element.rectTransform,offset);
        reader.Insert(index, element.logicElement);

        Destroy(element.gameObject);
    }

    /// <summary>
    /// When a logic Element is hovering over this holder
    /// </summary>
    /// <param name="element">Element which is hovering</param>
    public override void OnHover(LogicElementUI element)
    {
        Vector2 offset = new Vector2(element.rectTransform.rect.width / 2, 0);
        insertIndex = GetInsertIndex(element.rectTransform, offset);
        UpdateDisplay();
    }

    /// <summary>
    /// First frame a logic Element is hovering over this holder
    /// </summary>
    /// <param name="element">Element which is hovering</param>
    public override void OnHoverStart(LogicElementUI element)
    {
        Debug.Log("OnHoverStart");
        //Create insert prefab at End
        insertIndex = content.childCount;
        UpdateDisplay();
    }

    /// <summary>
    /// first frame a logic Element is  no longer hovering over this holder
    /// </summary>
    /// <param name="element">Element which is hovering</param>
    public override void OnHoverEnd(LogicElementUI element)
    {
        //Remove insert prefab
        insertIndex = -1;
        UpdateDisplay();
    }

    /// <summary>
    /// Called when an element in this holder is double clicked
    /// </summary>
    /// <param name="element">element which was double clicked</param>
    public override void OnDoubleClick(LogicElementUI element)
    {
        EditableBlock block = element.logicElement as EditableBlock;
        if (block == null)
            return;

        readerQueue.Add(new QueueData(block.blockReader,block.Color));

        border.color = block.Color;
        SetBlockReader(block.blockReader);    
    }

    /// <summary>
    /// Called to check if this holder can hold the provided element;
    /// </summary>
    /// <param name="element">element to check if it can hold</param>
    /// <returns>returns true if this can hold the element </returns>
    public override bool canHold(LogicBlock element)
    {
        return readerQueue[0].reader.Length < maxLength;
    }

    #endregion LogicElementHolder Implementation



    #region Helper Functions

    public int GetInsertIndex(RectTransform rt, Vector2 offset)
    {

        Rect rect = rt.rect;
        rect.center += offset;

        rect = rt.TransformRect(rect);

        DebugExtensions.DrawRect(rect, Color.green);

        foreach (Transform child in content)
        {
            RectTransform childRect = child as RectTransform;

            if (rect.Overlaps(childRect.GlobalRect()))
                return child.GetSiblingIndex();
        }
        Debug.Log("Returning last");
        return reader.LogicChain.Count;
    }

    public int GetInsertIndex(RectTransform rt)
    {
        return GetInsertIndex(rt, Vector2.zero);
    }

    #endregion Helper Functions

    [System.Serializable]
    public class QueueData
    {
        public Color color;
        public BlockReader reader;

        public QueueData(BlockReader reader, Color color)
        {
            this.color = color;
            this.reader = reader;
        }
    }

}
