using UnityEngine;

namespace ChillConnect
{
    public abstract class SingletonUnity<T> : MonoBehaviour, ISingleton where T : SingletonUnity<T>
    {
        private static T mInstance;

        public static T Instance
        {
            get
            {
                if (mInstance != null)
                {
                    return mInstance;
                }

                if (ApplicationIsQuitting)
                {
                    return null;
                }

                GameObject instanceGO = new GameObject(typeof(T).Name);
                mInstance = instanceGO.AddComponent<T>();
                SetSelfParentRoot(instanceGO, mInstance.ParentRootName);
                mInstance.OnSingletonInit();
                return mInstance;
            }
        }

        private static bool ApplicationIsQuitting;
        protected virtual string ParentRootName { get; private set; }

        private static void SetSelfParentRoot(GameObject go, string parentRootName)
        {
            if (!AppObjConst.EngineSingletonGo) return;

            if (parentRootName == null)
            {
                go.transform.SetParent(AppObjConst.EngineSingletonGo.transform, false);
            }
            else
            {
                Transform sinleonRoot = AppObjConst.EngineSingletonGo.transform;
                Transform rootTF = sinleonRoot.Find(parentRootName);
                if (rootTF == null)
                {
                    GameObject rootGo = new GameObject(parentRootName);
                    switch (parentRootName)
                    {
                        case AppObjConst.MonoManagerGoName:
                            AppObjConst.MonoManagerGo = rootGo;
                            break;
                        case AppObjConst.DispatcherGoName:
                            AppObjConst.DispatcherGo = rootGo;
                            break;
                        case AppObjConst.LoaderGoName:
                            AppObjConst.LoaderGo = rootGo;
                            break;
                    }

                    rootTF = rootGo.transform;
                    rootTF.transform.SetParent(sinleonRoot, false);
                }

                go.transform.SetParent(rootTF.transform, false);
            }
        }

        protected virtual void New()
        {
        }

        public virtual void Dispose()
        {
            mInstance = null;
        }

        protected virtual void OnDestroy()
        {
            mInstance = null;
        }

        private void OnApplicationQuit()
        {
            ApplicationIsQuitting = true;
            if (mInstance == null)
            {
                return;
            }

            Destroy(mInstance.gameObject);
        }

        public void OnSingletonInit()
        {
            mInstance.New();
        }
    }
}