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

namespace Stary.Evo
{
    /// <summary>
    /// 架构
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class Architecture<T> : IArchitecture where T : Architecture<T>, new()
    {
        /// <summary>
        /// 是否已经初始化完成
        /// </summary>
        private bool mInited = false;

        /// <summary>
        /// 用于初始化的 Datas 的缓存
        /// </summary>
        private List<IData> mDatas = new List<IData>();

        /// <summary>
        /// 用于初始化的 Systems 的缓存
        /// </summary>
        private List<ISystem> mSystems = new List<ISystem>();


        /// <summary>
        /// IOC
        /// </summary>
        private IOCContainer mContainer = new IOCContainer();

        // 留给子类注册模块
        protected abstract void Init();

        #region 类似单例模式 但是仅在内部访问

        private static T mArchitecture = null;

        public static IArchitecture Interface
        {
            get
            {
                if (mArchitecture == null)
                {
                    MakeSureArchitecture();
                }

                return mArchitecture;
            }
        }

        /// <summary>
        /// 增加注册
        /// </summary>
        public static Action<T> OnRegisterPatch = architecture => { Debug.Log("调用了"); };

        // 确保 Container 是有实例的
        static void MakeSureArchitecture()
        {
            Debug.Log((mArchitecture == null) + "----mArchitecture是否为空");
            if (mArchitecture == null)
            {
                mArchitecture = new T();
                mArchitecture.Init();
                mArchitecture.IOCInitClass();
                // 调用
                OnRegisterPatch?.Invoke(mArchitecture);

                // 初始化 Data
                for (int i = 0; i < mArchitecture.mDatas.Count; i++)
                {
                    mArchitecture.mDatas[i].Init();
                }

                // 清空 Data
                mArchitecture.mDatas.Clear();

                // 初始化 System
                for (int i = 0; i < mArchitecture.mSystems.Count; i++)
                {
                    mArchitecture.mSystems[i].Init();
                }

                // 清空 System
                mArchitecture.mSystems.Clear();
                mArchitecture.mInited = true;
            }
        }

        // // 提供一个释放模块的 API
        public static void Dispose()
        {
            for (int i = 0; i < mArchitecture.mSystems.Count; i++)
            {
                mArchitecture.mSystems[i].Dispose();
            }

            for (int i = 0; i < mArchitecture.mDatas.Count; i++)
            {
                mArchitecture.mDatas[i].Dispose();
            }

            mArchitecture = null;
        }

        #endregion


        #region 组件注册

        // 提供一个注册 System 的 API
        public void RegisterSystem<TSystem>(TSystem system) where TSystem : ISystem
        {
            // 需要给 System 赋值一下
            system.SetArchitecture(this);
            mContainer.Register<TSystem>(system);

            // 如果初始化过了
            if (mInited)
            {
                system.Init();
            }
            else
            {
                // 添加到 System 缓存中，用于初始化
                mSystems.Add(system);
            }
        }

        // 提供一个注册 Data 的 API
        public void RegisterData<TData>(TData data) where TData : IData
        {
            // 需要给 Data 赋值一下
            data.SetArchitecture(this);
            mContainer.Register<TData>(data);
            // 如果初始化过了
            if (mInited)
            {
                data.Init();
            }
            else
            {
                // 添加到 Data 缓存中，用于初始化
                mDatas.Add(data);
            }
        }

        // 提供一个注册工具模块的 API
        public void RegisterUtility<TUtility>(TUtility utility) where TUtility : IUtility
        {
            mContainer.Register<TUtility>(utility);
        }

        // 提供一个获取 Data 的 API
        public TData GetData<TData>() where TData : class, IData
        {
            return mContainer.Get<TData>();
        }

        #endregion

        #region IOC容器注册

        //IOC初始化注册
        private void IOCInitClass()
        {
        }

        // // 提供一个注册模块的 API
        public static void RegisterIOC<TArchitecture>(TArchitecture instance)
        {
            mArchitecture = null;
            MakeSureArchitecture();
            mArchitecture.mContainer.Register<TArchitecture>(instance);
        }

        // 提供一个获取模块的 API
        public static TArchitecture GetIOC<TArchitecture>() where TArchitecture : class
        {
            MakeSureArchitecture();
            return mArchitecture.mContainer.Get<TArchitecture>();
        }

        // 提供一个获取模块的 API
        public static void UnRegisterIOC<TArchitecture>() where TArchitecture : class
        {
            mArchitecture.mContainer.UnRegister<TArchitecture>();
        }

        #endregion

        // 提供一个获取工具模块的 API
        public TUtility GetUtility<TUtility>() where TUtility : class, IUtility
        {
            return mContainer.Get<TUtility>();
        }

        // 提供一个获取系统的 API
        public TSystem GetSystem<TSystem>() where TSystem : class, ISystem
        {
            return mContainer.Get<TSystem>();
        }

        // 提供一个传递Command的 API(不经过对象池)
        public void SendCommand<TCommand>() where TCommand : ICommand, new()
        {
            var command = new TCommand();
            ExecuteCommand(command);
        }

        // 提供一个传递Command的 API
        public void SendCommand<TCommand>(TCommand command) where TCommand : ICommand
        {
            ExecuteCommand(command);
        }

        protected virtual void ExecuteCommand(ICommand command)
        {
            command.SetArchitecture(this);
            command.Execute();
        }

        private EnumEventSystem _mEnumEventSystem = new EnumEventSystem();

        /// <summary>
        /// 事件发送
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void SendEvent<TEvent>(TEvent key) where TEvent : IConvertible
        {
            _mEnumEventSystem.Send<TEvent>(key);
        }

        /// <summary>
        /// 事件发送
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void SendEvent<TEvent, Tvalue1>(TEvent key, Tvalue1 value) where TEvent : IConvertible
        {
            _mEnumEventSystem.Send(key, value);
        }

        /// <summary>
        /// 事件发送
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void SendEvent<TEvent, Tvalue1, Tvalue2>(TEvent key, Tvalue1 value1, Tvalue2 value2)
            where TEvent : IConvertible
        {
            _mEnumEventSystem.Send(key, value1, value2);
        }

        /// <summary>
        /// 事件发送
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void SendEvent<TEvent, Tvlue1, Tvlue2, Tvlue3>(TEvent key, Tvlue1 value1, Tvlue2 vlue2, Tvlue3 vlue3)
            where TEvent : IConvertible
        {
            _mEnumEventSystem.Send(key, value1, vlue2, vlue3);
        }

        /// <summary>
        /// 事件发送
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void SendEvent<TEvent>(TEvent key, object[] values) where TEvent : IConvertible
        {
            _mEnumEventSystem.Send(key, values);
        }

        /// <summary>
        /// 事件监听
        /// </summary>
        /// <param name="onEvent"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IUnRegister RegisterEvent<TEvent>(TEvent key, Action onEvent) where TEvent : IConvertible
        {
            return _mEnumEventSystem.Register(key, onEvent);
        }

        /// <summary>
        /// 事件监听
        /// </summary>
        /// <param name="onEvent"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IUnRegister RegisterEvent<TEvent, Tvalue1>(TEvent key, Action<Tvalue1> onEvent)
            where TEvent : IConvertible
        {
            return _mEnumEventSystem.Register(key, onEvent);
        }

        /// <summary>
        /// 事件监听
        /// </summary>
        /// <param name="onEvent"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IUnRegister RegisterEvent<TEvent, Tvalue1, Tvalue2>(TEvent key, Action<Tvalue1, Tvalue2> onEvent)
            where TEvent : IConvertible
        {
            return _mEnumEventSystem.Register(key, onEvent);
        }

        /// <summary>
        /// 事件监听
        /// </summary>
        /// <param name="onEvent"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IUnRegister RegisterEvent<TEvent, Tvlue1, Tvlue2, Tvlue3>(TEvent key,
            Action<Tvlue1, Tvlue2, Tvlue3> onEvent) where TEvent : IConvertible
        {
            return _mEnumEventSystem.Register(key, onEvent);
        }

        /// <summary>
        /// 事件监听
        /// </summary>
        /// <param name="onEvent"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IUnRegister RegisterEvent<TEvent>(TEvent key, Action<object[]> onEvent) where TEvent : IConvertible
        {
            return _mEnumEventSystem.Register(key, onEvent);
        }

        /// <summary>
        /// 事件销毁
        /// </summary>
        /// <param name="onEvent"></param>
        /// <typeparam name="T"></typeparam>
        public void UnRegisterEvent<TEvent>(TEvent key, Action onEvent)where TEvent : IConvertible
        {
            _mEnumEventSystem.UnRegister(key,onEvent);
        }
        /// <summary>
        /// 事件销毁
        /// </summary>
        /// <param name="onEvent"></param>
        /// <typeparam name="T"></typeparam>
        public void UnRegisterEvent<TEvent, Tvalue1>(TEvent key, Action< Tvalue1> onEvent)where TEvent : IConvertible
        {
            _mEnumEventSystem.UnRegister(key,onEvent);
        }
        /// <summary>
        /// 事件销毁
        /// </summary>
        /// <param name="onEvent"></param>
        /// <typeparam name="T"></typeparam>
        public void UnRegisterEvent<TEvent, Tvalue1, Tvalue2>(TEvent key, Action<Tvalue1, Tvalue2> onEvent)where TEvent : IConvertible
        {
            _mEnumEventSystem.UnRegister(key,onEvent);
        }
        /// <summary>
        /// 事件销毁
        /// </summary>
        /// <param name="onEvent"></param>
        /// <typeparam name="T"></typeparam>
        public void UnRegisterEvent<TEvent, Tvlue1, Tvlue2, Tvlue3>(TEvent key, Action<Tvlue1, Tvlue2, Tvlue3> onEvent)where TEvent : IConvertible
        {
            _mEnumEventSystem.UnRegister(key,onEvent);
        }
        /// <summary>
        /// 事件销毁
        /// </summary>
        /// <param name="onEvent"></param>
        /// <typeparam name="T"></typeparam>
        public void UnRegisterEvent<TEvent>(TEvent key, Action<object[]> onEvent)where TEvent : IConvertible
        {
            _mEnumEventSystem.UnRegister(key,onEvent);
        }
        public TResult SendQuery<TResult>(IQuery<TResult> query)
        {
            return DoQuery<TResult>(query);
        }

        protected virtual TResult DoQuery<TResult>(IQuery<TResult> query)
        {
            query.SetArchitecture(this);
            return query.Do();
        }
    }
}