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

namespace SFramework
{
    [XLua.LuaCallCSharp]
    public class SLuaComponent : MonoBehaviour
    {
        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;

        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");
        }

        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;  
            }
        }

        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();
        }
    }
}
