/*
 * 由SharpDevelop创建。
 * 用户： Administrator
 * 日期: 2018-09-13
 * 时间: 17:14
 *
 * 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
 */

using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using GameData;
using MrWu.Debug;
using MrWu.RabbitMQ;
using Server.Data.Module;
using Server.DB.Redis;
using Server.DB.Sql;
using Server.MQ;
using Server.Pack;
using Server.Config;
using Server.Core;
using Server.Net;

namespace Server
{
    /// <summary>
    /// 全局管理
    /// </summary>
    public abstract partial class GlobalManager : ITimerProcessor, IServer
    {
        /// <summary>
        /// 是否需要重新加载配置
        /// </summary>
        public bool IsReloadTable;
        
        /// <summary>
        /// 服务器单元工厂
        /// </summary>
        public static ServerUtilFactory Factory;

        private static GlobalManager mInstance;

        /// <summary>
        /// 每个服务器只能管理一个服务,单例模式
        /// </summary>
        public static GlobalManager instance
        {
            get
            {
                if (mInstance == null)
                    mInstance = Factory.GetGlobalManager();
                return mInstance;
            }
        }

        #region 数据

        /// <summary>
        /// 是否自杀
        /// </summary>
        public bool isKill { get; private set; }

        /// <summary>
        /// 是否可以开战，关闭服务器前先禁止，然后再关闭服务器
        /// </summary>
        public bool IsCanWar = true;

        /// <summary>
        /// 客户端要得到的配置
        /// </summary>
        public ConfigHead ClientConfig;

        /// <summary>
        /// 服务器信息
        /// </summary>
        protected ServerInfo m_serverinfo;

        /// <summary>
        /// 服务器信息
        /// </summary>
        public virtual ServerInfo serverinfo
        {
            get
            {
                if (m_serverinfo == null)
                    m_serverinfo = new ServerInfo();
                return m_serverinfo;
            }
        }

        #endregion

        /// <summary>
        /// 获取配置头
        /// </summary>
        /// <returns></returns>
        protected virtual ConfigHead GetConfigHead()
        {
            ConfigHead cfh = new ConfigHead();
            cfh.style = 1;
            cfh.id = ServerConfigManager.Instance.NodeId;
            cfh.num = ServerConfigManager.Instance.NodeNum;
            cfh.maxSVer = ServerConfigManager.Instance.MaxVer;
            cfh.minSVer = ServerConfigManager.Instance.MinVer;
            cfh.maxCver = ServerConfigManager.Instance.MaxCVer;
            cfh.minCver = ServerConfigManager.Instance.MinCVer;
            return cfh;
        }

        /// <summary>
        /// 设置系统时间间隔
        /// </summary>
        /// <param name="t"></param>
        [DllImport("winmm")]
        protected static extern void timeBeginPeriod(int t);

        /// <summary>
        /// 恢复系统时间间隔
        /// </summary>
        /// <param name="t"></param>
        [DllImport("winmm")]
        protected static extern void timeEndPeriod(int t);

        /// <summary>
        /// 定时器管理
        /// </summary>
        private TimerManager timermgr;

        /// <summary>
        /// 更新服务器信息的时间
        /// </summary>
        public int updateServerInfo_time;

        /// <summary>
        /// 更新服务器信息
        /// </summary>
        protected virtual void UpdateServerInfo(bool isStart = false)
        {
            timeBeginPeriod(1);

            serverinfo.moduleId = myUtil.id;
            serverinfo.nodenum = myUtil.nodeNum;
            if (isStart)
                serverinfo.startTime = DateTime.Now;

            serverinfo.serverName = ServerName;
            serverinfo.dopackCnt = 0;
            serverinfo.minfps = minfps;
            serverinfo.fps = Fps;
            serverinfo.maxRuntime = maxruntiming;
            serverinfo.ConnectCnt = UserSessionsInfo.GetAllSessionCount();
            serverinfo.BindConnectCnt = UserSessionsInfo.GetBindSessionCount();

            updateServerInfo_time = ServerConfigManager.Instance.UpdateServerInfoTime;
        }

        /// <summary>
        /// 更新
        /// </summary>
        protected virtual void Update()
        {
            TimeInfo.Instance.Update();
            // long key = Debug.StartTiming();
            GameNetDispatcher.Instance.Update();
            GlobalDispatcher.Instance.Update();
            GameDispatcher.Instance.Update();

            // double runtime = Debug.GetRunTime(key);
            // if (runtime > 200)
            // {
            //     Debug.Error($"Update: 处理慢:{runtime}");
            // }
        }

        /// <summary>
        /// 启动数据
        /// </summary>
        /// <returns></returns>
        protected virtual bool Init()
        {
            return true;
        }


        private void DayChange()
        {
            GameDispatcher.Instance.Dispatch(GameMsgId.DayChange);
        }

        /// <summary>
        /// fps计数
        /// </summary>
        private int fpscount = -1;

        /// <summary>
        /// 帧率
        /// </summary>
        public int Fps { get; protected set; }

        private int m_minfps = -1;

        /// <summary>
        /// 最小fps
        /// </summary>
        public int minfps
        {
            get { return m_minfps; }
            protected set { m_minfps = value; }
        }

        /// <summary>
        /// 最大运行时间
        /// </summary>
        public double maxruntiming { get; protected set; }

        private System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();

        /// <summary>
        /// 发送配置包裹
        /// </summary>
        protected virtual void SendConfigPack()
        {
        }

        /// <summary>
        /// 处理模块死亡信号
        /// </summary>
        /// <param name="node"></param>
        /// <param name="nodenum"></param>
        protected void DoModuleDieSign(object param)
        {
            if (param is ServerNode serverNode)
            {
                Debug.Info("模块死亡包处理!");

                PackHead head = PackHead.Create();
                head.packlx = ServerPackAgreement.ModuleDie;
                Message msg = GlobalMQ.CreateMessage(head, serverNode);
                GlobalMQ.instance.AddMessage(msg);
                head.Dispose();
            }
        }

        /// <summary>
        /// 发送开启节点包
        /// </summary>
        protected virtual void SendOpenNode()
        {
            //注册模块
            PackHead head = PackHead.Create();
            head.packlx = ServerPackAgreement.openNode;
            var data = this.myType != ModuleType.WatchDog ? MonitoringAppInfo : null;
            GlobalMQ.instance.DeliveryAll(GlobalMQ.CreateMessage(head, data), true);
            head.Dispose();
        }

        /// <summary>
        /// 发送关闭节点包
        /// </summary>
        protected void SendCloseNode()
        {
            PackHead head = PackHead.Create();
            head.packlx = ServerPackAgreement.closeNode;
            var data = this.myType != ModuleType.WatchDog ? MonitoringAppInfo : null;

            GlobalMQ.instance.DeliveryAll(GlobalMQ.CreateMessage(head, data), true);
            head.Dispose();
        }

        //自身主机信息应该是不变的。 暂存这个信息
        MonitoringAppInfo MonitoringAppInfo =>
            MonitoringAppInfo.GetCurrentApplicateInfo(this.myUtil.onlyId, this.myUtil.id, this.myUtil.nodeNum);

        /// <summary>
        /// 退出游戏
        /// </summary>
        public virtual void Quit()
        {
            state = ServerState.Stoping;
        }

        #region ITimerProcessor

        /// <summary>
        /// 100毫秒定时器
        /// </summary>
        public virtual void OnTime(int Interval)
        {
            //Debug.Log("秒级定时器:" + "," + System.DateTime.Now.Ticks);
        }


        /// <summary>
        /// 记录天
        /// </summary>
        int Day = 0;

        /// <summary>
        /// 秒级定时器
        /// </summary>
        public virtual void SecondTime()
        {
            updateServerInfo_time--;

            if (updateServerInfo_time == 0)
            {
                UpdateServerInfo();
            }

            DoFps();

            if (Day != DateTime.Now.Day)
            {
                Day = DateTime.Now.Day;
                DayInit();
            }
        }

        #endregion

        /// <summary>
        /// 每一天初始化一次
        /// </summary>
        public virtual void DayInit()
        {
        }

        /// <summary>
        /// 处理Fps的赋值
        /// </summary>
        protected virtual void DoFps()
        {
            if (minfps < 0 || minfps > fpscount)
            {
                minfps = fpscount;
                //Debug.Warning("fps最低记录:" + minfps);
            }

            Fps = fpscount;
            fpscount = 0;
        }


        /// <summary>
        /// 缓存变化
        /// </summary>
        /// <param name="msg"></param>
        protected virtual void CacheChange(WaitBeMsg msg)
        {
            var head = msg.head;
            if (head.otherString == null || head.otherString.Length == 0)
                return;
            Debug.Info("处理缓存更新!" + head.otherString[0]);
            CaCheManager.instance.UpdateKeyAsync(head.otherString[0]);
        }

        /// <summary>
        /// 处理其他
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        protected virtual bool HandleOtherServerPack(WaitBeMsg msg) => false;

        /// <summary>
        /// 处理模块死亡信号——意外死亡
        /// </summary>
        /// <param name="msg"></param>
        protected virtual void ModuleDie(WaitBeMsg msg)
        {
            var data = JsonPack.GetData<ServerNode>(msg.jsondata);
            if (data == null)
                Debug.Error("数据错误！");
            else
                Debug.Warning("模块死亡信号:" + data.id + "," + data.nodeNum);
        }

        /// <summary>
        /// 
        /// </summary>
        protected virtual void Ping(PackHead head, string jsondata)
        {
            ModuleUtile util = JsonPack.GetData<ModuleUtile>(jsondata);
            if (util == null)
                Debug.Error("收到网络监测包数据为空!");
            head.packlx = ServerPackAgreement.Pong;
            GlobalMQ.instance.DeliveryOne(new ServerNode(util.id, util.nodeNum), GlobalMQ.CreateMessage(head, myUtil),
                true);

            Debug.Info("发送探测包:" + myUtil.ToString());
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="head"></param>
        /// <param name="jsondata"></param>
        protected virtual void Pong(PackHead head, string jsondata)
        {
            ModuleUtile util = JsonPack.GetData<ModuleUtile>(jsondata);
            if (util == null)
                Debug.Error("收到网络探测回包数据为空!");
            else
                Debug.Info("Pong : " + util.ToString());
        }

        /// <summary>
        /// 心跳处理包
        /// </summary>
        /// <param name="msg">消息</param>
        protected virtual void Heart(WaitBeMsg msg)
        {
            PackHead head = msg.head;
            ServerNode node = head.sendutil;
            if (node == null)
            {
                Debug.Error("心跳包错误,没有发送者的描述!");
                return;
            }

            if (node.Equals(myUtil)) //自己的包不处理
                return;

            //ServerHeart.instanece.DoHeartAsync(node.id, node.nodeNum);
        }

        /// <summary>
        /// 节点开启信号
        /// </summary>
        /// <param name="msg">消息</param>
        [System.Diagnostics.DebuggerNonUserCode]
        protected virtual void RecvOpenNode(WaitBeMsg msg)
        {
            PackHead head = msg.head;
            ModuleUtile node = head.sendutil;
            if (node == null)
            {
                Debug.Error("节点开启信号包错误,没有发送者的描述!");
                return;
            }

            if (node.Equals(myUtil))
            {
                return;
            }

            //Debug.Info($"接收到模块开启:{node.ToString()}");

            RountingManager.instance.AddModule(node.id, node.name);

            if (node.id == (int)ModuleType.ConfigModule)
            {
                SendConfigPack();
            }

            if (head.otherString == null || head.otherString.Length == 0 || head.otherString[0] != "ok")
            {
                head.packlx = ServerPackAgreement.openNode;
                head.otherString = new string[] { "ok" };
                var data = this.myType != ModuleType.WatchDog ? MonitoringAppInfo : null;
                var sendmsg = GlobalMQ.CreateMessage(head, data, null, -1, -1, null, null);
                GlobalMQ.instance.DeliveryOne(node, sendmsg, true);
            }

            ServerHeart.instanece.AddModule(node.id, node.name, node.nodeNum);
        }

        /// <summary>
        /// 节点关闭信号_正常关闭
        /// </summary>
        /// <param name="msg">消息</param>
        protected virtual void RecvCloseNode(WaitBeMsg msg)
        {
            ModuleUtile node = msg.head.sendutil;

            if (node == null)
            {
                Debug.Error("收到节点关闭信号,没有发送者的描述!");
                return;
            }

            if (node.Equals(myUtil))
            {
                //是本模块
                if (node.onlyId != myUtil.onlyId)
                {
                    return;
                }

                if (state == ServerState.Runing)
                {
                    //检测到已经死了
                    //直接退出
                    Debug.Error("收到死完包!直接退出!");
                    state = ServerState.Error;
                    return;
                }
                else
                    return;
            }

            //模块死亡信号
            ServerHeart.instanece.RemoveDie(node.id, node.nodeNum, true);
            Debug.Warning("收到模块关闭信号:" + node);
        }

        /// <summary>
        /// 处理命令
        /// </summary>
        protected virtual void DoCommand(WaitBeMsg msg)
        {
            string[] cmds = msg.head.otherString;
            if (cmds == null || cmds.Length <= 0)
                return;

            Debug.Info("收到命令" + cmds[0]);

            switch (cmds[0])
            {
                case "exit":
                    Quit();
                    break;
                case "test":
                    break;
                case "onlineModules": //在线的所有模块
                    Debug.Log("所有的在线模块");
                    break;

                case "redislocktest":
                    break;
            }
        }


        /// <summary>
        /// DistributedLock
        /// </summary>
        protected DistributedLock dtl { get; } = new DistributedLock(1000);

        #region IServer

        /// <summary>
        /// 服务器状态
        /// </summary>
        public ServerState state { get; set; } = ServerState.Close;

        /// <summary>
        /// 服务器名称
        /// </summary>
        public string ServerName
        {
            get
            {
                return ServerConfigManager.Instance.ServerName;
            }
        }

        /// <summary>
        /// 我的模块单元
        /// </summary>
        public ModuleUtile myUtil { get; protected set; }

        private ModuleType mMyType;

        /// <summary>
        /// 模块类型
        /// </summary>
        public ModuleType myType
        {
            get { return mMyType; }
        }

        /// <summary>
        /// 消息处理器
        /// </summary>
        public MessageProcessor msgProcessor;
        
        /// <summary>
        /// 其他配置初始化
        /// </summary>
        public virtual void OtherConfigInit()
        {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < 50; i++)
            {
                stringBuilder.Append('0');
            }
            
            if (ServerConfigManager.Instance.GameConfig != null)
            {
                ServerConfigManager.Instance.GameConfig.GameGz = stringBuilder.ToString();

                if (ServerConfigManager.Instance.TingCnt > 0)
                {
                    foreach (var ting in ServerConfigManager.Instance.Tings)
                    {
                        ting.TingGz = stringBuilder.ToString();
                    }
                }
            }
            
        }
        
        
        
        /// <summary>
        /// 检查配置表是否有问题
        /// </summary>
        /// <returns></returns>
        public virtual bool CheckConfig()
        {
            return true;
        }

        /// <summary>
        /// 启动
        /// </summary>
        public bool Start()
        {
            //启动中
            state = ServerState.Starting;

            mMyType = (ModuleType)ServerConfigManager.Instance.NodeId;

            myUtil = new ModuleUtile(ServerConfigManager.Instance.NodeId,
                ServerConfigManager.Instance.NodeNum,
                Enum.GetName(myType.GetType(), myType),
                ServerConfigManager.Instance.MaxVer);

            TimeInfo.Instance.DayChange += DayChange;
            
            //序列化预热
            PreLoadMessagePack();
            
            GlobalDispatcher.Instance.Dispatch(GlobalMsgId.GameNameReadSuccess, ServerConfigManager.Instance.ServerName);
            Debug.Info($"Start ServerName:{ServerConfigManager.Instance.ServerName}");

            //数据库初始化
            GameDB.Instance.Init(SqlConfigCategory.Instance.GetDBSqlConfig());

            //redis启动
            redisManager.Start();

            ClientConfig = GetConfigHead();

            //存储自己的模块信息
            if (!redisManager.db.HashExists(RedisDictionary.moduleNames, ServerConfigManager.Instance.NodeId.ToString()))
                redisManager.db.HashSet(RedisDictionary.moduleNames, ServerConfigManager.Instance.NodeId, myUtil.name);

            //心跳开始,并检查模块是否在线
            if (!ServerHeart.instanece.Start(myType, ServerConfigManager.Instance.NodeNum))
            {
                Debug.ImportantLog("启动失败,模块在线!");
                return false;
            }

            MessagePool.tag = "" + myUtil.id + "-" + myUtil.nodeNum + "-" + myUtil.ver + "-" + myUtil.name;

            //模块死亡事件监听
            GlobalDispatcher.Instance.AddListener(GlobalMsgId.ModuleNodeDie, DoModuleDieSign);

            //创建消息处理
            Factory.CreateGlobalMQFactory().CreateGlobalMQ();

            //启动rabbit
            if (!GlobalMQ.instance.StartModule(RabbitConfigCategory.Instance.GetRabbitMQConfig(), myUtil))
            {
                Debug.Error("启动失败:A71134F4-EA97-44C0-A305-E35966622FEB");
                return false;
            }

            msgProcessor = Factory.CreateMessageProcessor();

            new UserSessionsManager().Register();
            //重要数据启动
            if (!Init())
            {
                return false;
            }

            Debug.ImportantLog("init over!!!");
            //发送开启信号
            SendOpenNode();

            //定时器管理
            timermgr = new TimerManager(ServerConfigManager.Instance.OnTime);
            timermgr.Start();

            //更改状态为运行中
            state = ServerState.Runing;

            //更新服务器信息
            UpdateServerInfo(true);

            //开始发送心跳包
            ServerHeart.instanece.BeginHeart(Factory.CreateHeartPack(myUtil));

            return true;
        }
        
        private StringBuilder logs = new StringBuilder();

        private int GcCount = 0;

        /// <summary>
        /// 预热 MessagePack
        /// </summary>
        protected virtual void PreLoadMessagePack()
        {
            
        }

        private void ReLoadTable()
        {
            TableManager.Instance.ReLoadTableData();

            try
            {
                ReLoadTableInit();
                Debug.ImportantLog("配置重新加载成功！");
            }
            catch (Exception e)
            {
                Debug.Error("重载配置出错!" + e.Message);
                TableManager.Instance.RollBack();
            }
        }

        protected virtual void ReLoadTableInit()
        {
            
        }

        /// <summary>
        /// 主线程
        /// </summary>
        public void Loop()
        {
            if (state == ServerState.Runing)
            {
                try
                {
                    logs.Clear();
                    watch.Restart();
                    //watch.Restart();

                    if (IsReloadTable)
                    {
                        IsReloadTable = false;
                        ReLoadTable();
                    }
                    
                    if (timermgr.GetMillScoend())
                    {
#if DEBUG
                        var key = Debug.StartTiming();
                        logs.AppendLine($"GlobalManager Loop DoTime begin");
#endif
                        OnTime(timermgr.Interval);
#if DEBUG
                        logs.AppendLine($"GlobalManager Loop DoTime end, time: {Debug.GetRunTime(key)}");
#endif
                    }

                    if (timermgr.GetSecoend())
                    {
#if DEBUG
                        var key = Debug.StartTiming();
                        logs.AppendLine($"GlobalManager Loop DoTimeSecond begin");
#endif
                        SecondTime();
#if DEBUG
                        logs.AppendLine($"GlobalManager Loop DoTimeSecond end, time: {Debug.GetRunTime(key)}");
#endif
                    }

                    //消息处理
                    msgProcessor.Run(logs);

#if DEBUG
                    var updateKey = Debug.StartTiming();
#endif
                    fpscount++;
                    Update();
#if DEBUG
                    logs.AppendLine($"Update Loop time:{Debug.GetRunTime(updateKey)}");
#endif
                    watch.Stop();
                    double runtime = watch.ElapsedMilliseconds; //.ElapsedMilliseconds;
                    
                    if (runtime >= 100)
                    {
                        logs.AppendLine(
                            $"GlobalManager Loop end, now: {DateTime.Now}, runtime: {runtime} / {watch.Elapsed.TotalMilliseconds}");
                        
                        Debug.Error($"Loop runtime warning: " + logs.ToString());
                    }

                    if (runtime > maxruntiming)
                        maxruntiming = runtime;
                }
                catch (Exception e)
                {
                    Debug.Error("主线程错误:" + e.ToString());
                }
            }
            else if (state == ServerState.Stoping)
            {
                Close();
            }
        }

        /// <summary>
        /// 阻塞检查，直到正常退出
        /// </summary>
        public virtual void Close()
        {
            UUIDManager.Instance.Close();
            UserSessionsManager.Instance.Dispose();
            timermgr.Stop();

            SendCloseNode();
            ServerHeart.instanece.Close();
            //ServerManager.instance.Close();
            if (GlobalMQ.instance != null)
                GlobalMQ.instance.Close();

            //保存道具日志
            PropManager.Instance.Dispose();
            state = ServerState.Stop;

            Debug.Log("模块正常退出!");
        }

        #endregion

        /// <summary>
        /// 收到获取在线人数的请求
        /// </summary>
        /// <param name="msg"></param>
        protected virtual void ReportPlayerOnLineData(WaitBeMsg msg)
        {
        }
    }
}