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

namespace SFramework
{
    [XLua.LuaCallCSharp]
    public class SLuaComponent : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
    {
        public TextAsset luaScript;
        private XLua.LuaTable _luaTable;

        private XLua.LuaFunction _luaAwake;
        private XLua.LuaFunction _luaStart;
        private XLua.LuaFunction _luaUpdate;
        private XLua.LuaFunction _luaFixedUpdate;
        private XLua.LuaFunction _luaLateUpdate;
        private XLua.LuaFunction _luaOnDestroy;
        private XLua.LuaFunction _luaOnEnable;
        private XLua.LuaFunction _luaOnDisable;
        private XLua.LuaFunction _luaOnApplicationFocus;
        private XLua.LuaFunction _luaOnApplicationPause;
        private XLua.LuaFunction _luaOnApplicationQuit;
        private XLua.LuaFunction _luaOnCollisionEnter;
        private XLua.LuaFunction _luaOnCollisionEnter2D;
        private XLua.LuaFunction _luaOnCollisionExit;
        private XLua.LuaFunction _luaOnCollisionExit2D;
        private XLua.LuaFunction _luaOnCollisionStay;
        private XLua.LuaFunction _luaOnCollisionStay2D;
        private XLua.LuaFunction _luaOnMouseDown;
        private XLua.LuaFunction _luaOnMouseDrag;
        private XLua.LuaFunction _luaOnMouseEnter;
        private XLua.LuaFunction _luaOnMouseExit;
        private XLua.LuaFunction _luaOnMouseOver;
        private XLua.LuaFunction _luaOnMouseUp;
        private XLua.LuaFunction _luaOnMouseUpAsButton;
        private XLua.LuaFunction _luaOnTriggerEnter;
        private XLua.LuaFunction _luaOnTriggerEnter2D;
        private XLua.LuaFunction _luaOnTriggerExit;
        private XLua.LuaFunction _luaOnTriggerExit2D;
        private XLua.LuaFunction _luaOnTriggerStay;
        private XLua.LuaFunction _luaOnTriggerStay2D;
        private XLua.LuaFunction _luaOnBeginDrag;
        private XLua.LuaFunction _luaOnEndDrag;
        private XLua.LuaFunction _luaOnDrag;

        internal static XLua.LuaEnv luaEnv = SLuaEnv.Instance;
        internal static float lastGCTime = 0;
        internal const float GCInterval = 1;

        public static void Add(GameObject targetGameObject, XLua.LuaTable luaTable, string luaFileName)
        {
            SLuaComponent luaComponent = targetGameObject.AddComponent<SLuaComponent>();
            luaComponent.luaScript = new UnityEngine.TextAsset("print('The lua script add dynamic.')");
            luaComponent.luaScript.name = luaFileName;
            if (null == luaFileName) { Debug.LogWarning("SLuaComponent Add Script Dynamic But Do Not Set Script Name!"); }
            luaComponent.SetLuaTable(luaTable);
        }

        public void SetLuaTable(XLua.LuaTable luaTable)
        {
            Debug.Assert(null != luaTable, "SLuaComponent SetLuaTable Failed luaTable == null");
            Debug.Assert(null == _luaTable, "SLuaComponent SetLuaTable Failed _luaTable != null");

            _luaTable = luaTable;
            InitLuaFunction();

            // Try Call Awake Function();
            if (null != _luaAwake)
                _luaAwake.Call(gameObject);
        }

        private void InitLuaFunction()
        {
            if (null == _luaTable)
            {
                Debug.LogError("SLuaComponent InitLuaFunction Failed Because _luaTable == null");
                return;
            }

            _luaAwake = _luaTable.Get<XLua.LuaFunction>("Awake");
            _luaStart = _luaTable.Get<XLua.LuaFunction>("Start");
            _luaUpdate = _luaTable.Get<XLua.LuaFunction>("Update");
            _luaFixedUpdate = _luaTable.Get<XLua.LuaFunction>("FixedUpdate");
            _luaLateUpdate = _luaTable.Get<XLua.LuaFunction>("LateUpdate");
            _luaOnDestroy = _luaTable.Get<XLua.LuaFunction>("OnDestroy");
            _luaOnEnable = _luaTable.Get<XLua.LuaFunction>("OnEnable");
            _luaOnDisable = _luaTable.Get<XLua.LuaFunction>("OnDisable");
            _luaOnApplicationFocus = _luaTable.Get<XLua.LuaFunction>("OnApplicationFocus");
            _luaOnApplicationPause = _luaTable.Get<XLua.LuaFunction>("OnApplicationPause");
            _luaOnApplicationQuit = _luaTable.Get<XLua.LuaFunction>("OnApplicationQuit");
            _luaOnCollisionEnter = _luaTable.Get<XLua.LuaFunction>("OnCollisionEnter");
            _luaOnCollisionEnter2D = _luaTable.Get<XLua.LuaFunction>("OnCollisionEnter2D");
            _luaOnCollisionExit = _luaTable.Get<XLua.LuaFunction>("OnCollisionExit");
            _luaOnCollisionExit2D = _luaTable.Get<XLua.LuaFunction>("OnCollisionExit2D");
            _luaOnCollisionStay = _luaTable.Get<XLua.LuaFunction>("OnCollisionStay");
            _luaOnCollisionStay2D = _luaTable.Get<XLua.LuaFunction>("OnCollisionStay2D");
            _luaOnMouseDown = _luaTable.Get<XLua.LuaFunction>("OnMouseDown");
            _luaOnMouseDrag = _luaTable.Get<XLua.LuaFunction>("OnMouseDrag");
            _luaOnMouseEnter = _luaTable.Get<XLua.LuaFunction>("OnMouseEnter");
            _luaOnMouseExit = _luaTable.Get<XLua.LuaFunction>("OnMouseExit");
            _luaOnMouseOver = _luaTable.Get<XLua.LuaFunction>("OnMouseOver");
            _luaOnMouseUp = _luaTable.Get<XLua.LuaFunction>("OnMouseUp");
            _luaOnMouseUpAsButton = _luaTable.Get<XLua.LuaFunction>("OnMouseUpAsButton");
            _luaOnTriggerEnter = _luaTable.Get<XLua.LuaFunction>("OnTriggerEnter");
            _luaOnTriggerEnter2D = _luaTable.Get<XLua.LuaFunction>("OnTriggerEnter2D");
            _luaOnTriggerExit = _luaTable.Get<XLua.LuaFunction>("OnTriggerExit");
            _luaOnTriggerExit2D = _luaTable.Get<XLua.LuaFunction>("OnTriggerExit2D");
            _luaOnTriggerStay = _luaTable.Get<XLua.LuaFunction>("OnTriggerStay");
            _luaOnTriggerStay2D = _luaTable.Get<XLua.LuaFunction>("OnTriggerStay2D");
            _luaOnBeginDrag = _luaTable.Get<XLua.LuaFunction>("OnBeginDrag");
            _luaOnEndDrag = _luaTable.Get<XLua.LuaFunction>("OnEndDrag");
            _luaOnDrag = _luaTable.Get<XLua.LuaFunction>("OnDrag");
        }

        private void Awake()
        {
            if (null == luaScript)
                return;

            System.Object[] retValues = luaEnv.DoString(luaScript.text, "LuaComponent");
            if (null == retValues || retValues.Length != 1)
            {
                Debug.LogWarning("SLuaCompnent Need A Lua That Return A LuaTable.");
                Debug.LogError("SLuaComponent Load LuaScript Failed When Awake, ScriptName: " + luaScript.name);
                return;
            }

            _luaTable = retValues[0] as XLua.LuaTable;

            InitLuaFunction();

            if (null != _luaAwake)
                _luaAwake.Call(gameObject);
        }

        private void Start()
        {
            if (null != _luaStart)
                _luaStart.Call(gameObject);
        }

        private void Update()
        {
            if (Time.time - SLuaComponent.lastGCTime > GCInterval)
            {
                luaEnv.Tick();
                SLuaComponent.lastGCTime = Time.time;
            }

            if (null != _luaUpdate)
                _luaUpdate.Call();
        }

        private void FixedUpdate()
        {
            if (null != _luaFixedUpdate)
                _luaFixedUpdate.Call();
        }

        private void LateUpdate()
        {
            if (null != _luaLateUpdate)
                _luaLateUpdate.Call();
        }

        private void OnDestroy()
        {
            if (null != _luaOnDestroy)
                _luaOnDestroy.Call();

            if (null != _luaAwake)
            {
                _luaAwake.Dispose();
                _luaAwake = null;
            }
            
            if (null != _luaStart)
            {
                _luaStart.Dispose();
                _luaStart = null;
            }

            if (null != _luaUpdate)
            {
                _luaUpdate.Dispose();
                _luaUpdate = null;
            }

            if (null != _luaFixedUpdate)
            {
                _luaFixedUpdate.Dispose();
                _luaFixedUpdate = null;
            }

            if (null != _luaLateUpdate)
            {
                _luaLateUpdate.Dispose();
                _luaLateUpdate = null;
            }

            if (null != _luaOnDestroy)
            {
                _luaOnDestroy.Dispose();
                _luaOnDestroy = null;  
            }

            if (null != _luaOnEnable)
            {
                _luaOnEnable.Dispose();
                _luaOnEnable = null;
            }

            if (null != _luaOnDisable)
            {
                _luaOnDisable.Dispose();
                _luaOnDisable = null;
            }

            if (null != _luaOnApplicationFocus)
            {
                _luaOnApplicationFocus.Dispose();
                _luaOnApplicationFocus = null;
            }

            if (null != _luaOnApplicationPause)
            {
                _luaOnApplicationPause.Dispose();
                _luaOnApplicationPause = null;
            }

            if (null != _luaOnApplicationQuit)
            {
                _luaOnApplicationQuit.Dispose();
                _luaOnApplicationQuit = null;  
            }

            if (null != _luaOnCollisionEnter)
            {
                _luaOnCollisionEnter.Dispose();
                _luaOnCollisionEnter = null;
            }

            if (null != _luaOnCollisionEnter2D)
            {
                _luaOnCollisionEnter2D.Dispose();
                _luaOnCollisionEnter2D = null;
            }

            if (null != _luaOnCollisionExit)
            {
                _luaOnCollisionExit.Dispose();
                _luaOnCollisionExit = null;
            }

            if (null != _luaOnCollisionExit2D)
            {
                _luaOnCollisionExit2D.Dispose();
                _luaOnCollisionExit2D = null;
            }

            if (null != _luaOnCollisionStay)
            {
                _luaOnCollisionStay.Dispose();
                _luaOnCollisionStay = null;
            }

            if (null != _luaOnCollisionStay2D)
            {
                _luaOnCollisionStay2D.Dispose();
                _luaOnCollisionStay2D = null;
            }

            if (null != _luaOnMouseDown)
            {
                _luaOnMouseDown.Dispose();
                _luaOnMouseDown = null;
            }

            if (null != _luaOnMouseDrag)
            {
                _luaOnMouseDrag.Dispose();
                _luaOnMouseDrag = null;
            }

            if (null != _luaOnMouseEnter)
            {
                _luaOnMouseEnter.Dispose();
                _luaOnMouseEnter = null;
            }

            if (null != _luaOnMouseExit)
            {
                _luaOnMouseExit.Dispose();
                _luaOnMouseExit = null;
            }

            if (null != _luaOnMouseOver)
            {
                _luaOnMouseOver.Dispose();
                _luaOnMouseOver = null;
            }

            if (null != _luaOnMouseUp)
            {
                _luaOnMouseUp.Dispose();
                _luaOnMouseUp = null;
            }

            if (null != _luaOnMouseUpAsButton)
            {
                _luaOnMouseUpAsButton.Dispose();
                _luaOnMouseUpAsButton = null;
            }

            if (null != _luaOnTriggerEnter)
            {
                _luaOnTriggerEnter.Dispose();
                _luaOnTriggerEnter = null;  
            }

            if (null != _luaOnTriggerEnter2D)
            {
                _luaOnTriggerEnter2D.Dispose();
                _luaOnTriggerEnter2D = null;
            }

            if (null != _luaOnTriggerExit)
            {
                _luaOnTriggerExit.Dispose();
                _luaOnTriggerExit = null;
            }

            if (null != _luaOnTriggerExit2D)
            {
                _luaOnTriggerExit2D.Dispose();
                _luaOnTriggerExit2D = null;
            }

            if (null != _luaOnTriggerStay)
            {
                _luaOnTriggerStay.Dispose();
                _luaOnTriggerStay = null;
            }

            if (null != _luaOnTriggerStay2D)
            {
                _luaOnTriggerStay2D.Dispose();
                _luaOnTriggerStay2D = null;
            }

            if (null != _luaOnBeginDrag)
            {
                _luaOnBeginDrag.Dispose();
                _luaOnBeginDrag = null;
            }

            if (null != _luaOnEndDrag)
            {
                _luaOnEndDrag.Dispose();
                _luaOnEndDrag = null;
            }

            if (null != _luaOnDrag)
            {
                _luaOnDrag.Dispose();
                _luaOnDrag = null;
            }
        }

        private void OnEnable()
        {
            if (null != _luaOnEnable)
                _luaOnEnable.Call();
        }

        private void OnDisable()
        {
            if (null != _luaOnDisable)
                _luaOnDisable.Call();
        }

        private void OnApplicationFocus(bool focus)
        {
            if (null != _luaOnApplicationFocus)
                _luaOnApplicationFocus.Call(focus);
        }

        private void OnApplicationPause(bool pause)
        {
            if (null != _luaOnApplicationPause)
                _luaOnApplicationPause.Call(pause);
        }

        private void OnApplicationQuit()
        {
            if (null != _luaOnApplicationQuit)
                _luaOnApplicationQuit.Call();
        }

        private void OnCollisionEnter(Collision collision)
        {
            if (null != _luaOnCollisionEnter)
                _luaOnCollisionEnter.Call(collision);
        }

        private void OnCollisionEnter2D(Collision2D collision)
        {
            if (null != _luaOnCollisionEnter2D)
                _luaOnCollisionEnter2D.Call(collision);
        }

        private void OnCollisionExit(Collision collision)
        {
            if (null != _luaOnCollisionExit)
                _luaOnCollisionExit.Call(collision);
        }

        private void OnCollisionExit2D(Collision2D collision)
        {
            if (null != _luaOnCollisionExit2D)
                _luaOnCollisionExit2D.Call(collision);
        }

        private void OnCollisionStay(Collision collision)
        {
            if (null != _luaOnCollisionStay)
                _luaOnCollisionStay.Call(collision);
        }
        
        private void OnCollisionStay2D(Collision2D collision)
        {
            if (null != _luaOnCollisionStay2D)
                _luaOnCollisionStay2D.Call(collision);
        }
        
        private void OnMouseDown()
        {
            if (null != _luaOnMouseDown)
                _luaOnMouseDown.Call();
        }

        private void OnMouseDrag()
        {
            if (null != _luaOnMouseDrag)
                _luaOnMouseDrag.Call();
        }

        private void OnMouseEnter()
        {
            if (null != _luaOnMouseEnter)
                _luaOnMouseEnter.Call();
        }

        private void OnMouseExit()
        {
            if (null != _luaOnMouseExit)
                _luaOnMouseExit.Call();
        }

        private void OnMouseOver()
        {
            if (null != _luaOnMouseOver)
                _luaOnMouseOver.Call();
        }

        private void OnMouseUp()
        {
            if (null != _luaOnMouseUp)
                _luaOnMouseUp.Call();
        }

        private void OnMouseUpAsButton()
        {
            if (null != _luaOnMouseUpAsButton)
                _luaOnMouseUpAsButton.Call();
        }

        private void OnTriggerEnter(Collider other)
        {
            if (null != _luaOnTriggerEnter)
                _luaOnTriggerEnter.Call(other);
        }

        private void OnTriggerEnter2D(Collider2D other)
        {
            if (null != _luaOnTriggerEnter2D)
                _luaOnTriggerEnter2D.Call(other);
        }

        private void OnTriggerExit(Collider other)
        {
            if (null != _luaOnTriggerExit)
                _luaOnTriggerExit.Call(other);
        }

        private void OnTriggerExit2D(Collider2D other)
        {
            if (null != _luaOnTriggerExit2D)   
                _luaOnTriggerExit2D.Call(other);
        }

        private void OnTriggerStay(Collider other)
        {
            if (null != _luaOnTriggerStay)
                _luaOnTriggerStay.Call(other);
        }

        private void OnTriggerStay2D(Collider2D other)
        {
            if (null != _luaOnTriggerStay2D)
                _luaOnTriggerStay2D.Call(other);
        }

        public void OnBeginDrag(PointerEventData eventData)
        {
            if (null != _luaOnBeginDrag)
                _luaOnBeginDrag.Call(eventData);
        }

        public void OnEndDrag(PointerEventData eventData)
        {
            if (null != _luaOnEndDrag)
                _luaOnEndDrag.Call(eventData);
        }

        public void OnDrag(PointerEventData eventData)
        {
            if (null != _luaOnDrag)
                _luaOnDrag.Call(eventData);
        }
    }
}
