using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;

namespace UTableView
{
    public class UTableView : MonoBehaviour
    {

        public Vector2 offset = Vector2.zero;//偏移距离
        public Vector2 spacing = new Vector2();//单元格间间距
        public GameObject perfabObj = null;
        public int lineCout = 1;//单行多少个，或者单列多少个
        public bool IsReverseOrder = true;
        private delegate void UpdateTableViewBack();
        private UpdateTableViewBack updateTableViewBack;
        private bool isInit = false;
        private ScrollRect scrollRect = null;
        private bool isHorizontal = true;
        private Rect selfRect = Rect.zero;


        protected void initMembers()
        {
            if (isInit == false)
            {
                isInit = true;
                scrollRect = GetComponent<ScrollRect>();
                if (scrollRect.horizontal)
                {
                    isHorizontal = true;
                    scrollRect.vertical = false;
                } else if (scrollRect.vertical)
                {
                    isHorizontal = false;
                    scrollRect.horizontal = false;
                }
                else
                {
                    scrollRect.vertical = false;
                }
                selfRect = GetComponent<RectTransform>().rect;
                scrollRect.onValueChanged.AddListener(OnScroll);
            }
        }
        private void OnScroll(Vector2 scrollPosition)
        {
            if (updateTableViewBack != null && false)
            {
                updateTableViewBack();
            }
            //if (scrollPosition.y > threshold)
            //{
            //    // 滑动距离超过阈值，表示不再触顶
            //    isScrolledToTop = false;
            //}
            //else if (scrollPosition.y < 1f - threshold)
            //{
            //    // 滑动距离超过阈值，表示不再触底
            //    isScrolledToBottom = false;
            //}

            //// 判断是否触顶
            //if (!isScrolledToTop && scrollPosition.y <= threshold)
            //{
            //    isScrolledToTop = true;
            //    // 触顶事件处理
            //    Debug.Log("Scroll To Top");
            //}

            //// 判断是否触底
            //if (!isScrolledToBottom && scrollPosition.y >= 1f - threshold)
            //{
            //    isScrolledToBottom = true;
            //    // 触底事件处理
            //    Debug.Log("Scroll To Bottom");
            //}
        }
        private Vector2 getContentSize<ViewT>(List<UTableData> datas) where ViewT : UTableItem
        {
            UTableItem uTableItem = this.perfabObj.GetComponent<ViewT>() as UTableItem;
            float width = offset.x;
            float height = offset.y;
            Vector2 ret;
            if (datas.Count > 0)
            {
                if (isHorizontal)
                {
                    for (int i = 0; i < datas.Count; i++)
                    {
                        var data = datas[i];
                        var temp = uTableItem.getSize(i, datas[i]);
                        width += temp.x;
                    }
                    width = width + (datas.Count - 1) * spacing.x;
                    height = selfRect.height;
                    
                }
                else
                {
                    for (int i = 0;i < datas.Count ;i++)
                    {
                        var data = datas[i];
                        var temp = uTableItem.getSize(i, datas[i]);
                        height += temp.y;
                    }
                    height = height + (datas.Count - 1) * spacing.y;
                    width = selfRect.width;
                }
            }
            else
            {
                width = selfRect.width;
                height = selfRect.height;
            }
            ret = new Vector2(width, height);
            return ret;
        }
        private bool getGameObjectCell<ViewT>(int idx,UTableData item,ref ViewT commponent) where ViewT : UTableItem
        {
            string name = "auto_tableViewU_" + idx.ToString();
            var obj = scrollRect.content.Find(name);
            if(obj != null)
            {
                ViewT viewT = obj.GetComponent<ViewT>();
                if(viewT != null)
                {
                    commponent = viewT;
                    return true;
                }
                obj.transform.SetParent(null);
                Destroy(obj);
            }
            var gobj = Instantiate(perfabObj);
            gobj.name = name;
            commponent = gobj.GetComponent<ViewT>();
            return false;
        }
        private bool cellInfoIsVisible(float x,float y,Vector2 size)
        {
            return true;
        }
        private void updateTableContent<ViewT>(List<UTableData> datas,Vector2 size) where ViewT : UTableItem
        {
            ViewT viewT = default;
            GameObject cell = null;
            UTableItem uTableItem = perfabObj.GetComponent<ViewT>() as UTableItem;
            float start = 0;

            int startIdx = 0;
            int endIdx = datas.Count;
            int setp = 1;
            if (IsReverseOrder == false)
            {
                startIdx = datas.Count - 1;
                endIdx = -1;
                setp = -1;
            }

            if (isHorizontal)
            {
                start = 0 - size.x;
                start = start + offset.x + spacing.x / 2;
                for (int i = startIdx; ;)
                {
                    Vector2 temp = uTableItem.getSize(i, datas[i]);
                    start += temp.x/2;
                    if (cellInfoIsVisible(start, 0, temp))
                    {
                        if (getGameObjectCell<ViewT>(i, datas[i], ref viewT) == false)
                        {
                            cell = viewT.GetGameObject();
                            cell.transform.SetParent(scrollRect.content.transform);
                            viewT.initData(i, datas[i]);
                        }
                        else
                        {
                            viewT.updateData(i, datas[i]);
                        }
                        cell.transform.localPosition = new Vector3(start, offset.y);
                    }
                    start =start + temp.x / 2 + spacing.x;
                    i = i + setp;
                    if (i == endIdx) break;
                }
            }
            else
            {
                start = 0 - size.y;
                start = start + offset.y + spacing.y / 2;
                for (int i = startIdx; ;)
                {
                    Vector2 temp = uTableItem.getSize(i, datas[i]);
                    start += temp.y / 2;
                    if (cellInfoIsVisible(start, 0, temp))
                    {
                        if (getGameObjectCell<ViewT>(i, datas[i], ref viewT) == false)
                        {
                            cell = viewT.GetGameObject();
                            cell.transform.SetParent(scrollRect.content.transform);
                            viewT.initData(i, datas[i]);
                        }
                        else
                        {
                            viewT.updateData(i, datas[i]);
                        }
                        cell.transform.localPosition = new Vector3(offset.x,start);
                    }
                    start = start + temp.y / 2 + spacing.y;
                    i = i + setp;
                    if (i == endIdx) break;
                }
            }
            
        }

        //public 
        public void SetData<ViewT>(List<UTableData> datas) where ViewT : UTableItem
        {
            initMembers();
            Vector2 size = getContentSize<ViewT>(datas);
            var contentObject = scrollRect.content.gameObject;
            contentObject.GetComponent<RectTransform>().sizeDelta = size;
            updateTableViewBack = () =>
            {

            };
            updateTableContent<ViewT>(datas,size);
            return;
        }
    }

}
