//**********************************************//
//作者:#AUTHOR#
//日期:#DATE#
//简述:#DESCRIPTION#
//*********************************************//
using Thousandto.Code.Center;
using Thousandto.Core.Base;
using Thousandto.Plugins.Common;
using UnityEngine;

namespace Thousandto.Code.Logic
{
    /// <summary>
    /// 断线重连
    /// </summary>
    public class ReconnectSystem : BaseSystem
    {
        #region//常量定义

        //重连尝试次数
        private const int CN_RECONNECT_TRY_COUNT = 5;

        //Socket连接的等待时间
        private const float CN_SOCKET_CONNECT_WAIT_TIME = 3;

        //等待网络消息的时间
        private const float CN_NET_MESSAGE_WAIT_TIME = 3;

        #endregion

        #region //成员变量
        private string _sign;
        //是否允许断线重连
        private bool _enable = false;
        //当前状态
        private ReconnectStateCode _state = ReconnectStateCode.Idle;

        //尝试次数
        private int _remainCount = 5;

        //等待时间 秒
        private float _waitTime = 3;
        #endregion

        #region //属性

        //断线前的地图id
        public int LastMapId { get; set; }
        //正常切换场景记录切换前的坐标、分线等等,以防万一真的重连,这里能取数据
        public Vector3 LastPlayerPos { get; set; }
        //正在重连的次数
        public int TryCount
        {
            get
            {
                return CN_RECONNECT_TRY_COUNT - _remainCount;
            }
        }

        //剩余次数
        public int RemainCount
        {
            get
            {
                return _remainCount;
            }
        }
        #endregion

        #region//公共接口处理

        #region //初始化
        public void Initialize()
        {
            GameCenter.Networker.OnSocketDisconnect = OnMonitorSocketState;
        }
        #endregion
                    
        #region //公有函数
        public void Reconnect()
        {
            //开始重连的
            LastMapId = -1;
            LastPlayerPos = Vector3.zero;
            _state = ReconnectStateCode.StartReconnect;
        }

     
        //在重连中返回到登陆
        public void ReturnToLogin()
        {
            //当前状态为空闲
            _state = ReconnectStateCode.Idle;
            //现在不是重连状态
            GameGlobalData.IsReconnecting = false;
            //不能重连
            _enable = false;
            //返回到登陆
            GameCenter.GameSceneSystem.ReturnToLogin();
        }

        //设置是否激活
        public void SetEnable(bool value)
        {
            //当前状态为空闲
            _state = ReconnectStateCode.Idle;
            //不能重连
            _enable = value;
        }

        #endregion

        #region//处理网络消息

        //public bool TestRightSign = true;
        //3.发送请求重连的消息
        public void SendReqReconnect()
        {
            Debug.LogError("SendReqReconnect=" + _sign);
            MSG_heart.ReqReconnect req = new MSG_heart.ReqReconnect();
            req.playerId = GameCenter.GameSceneSystem.GetLocalPlayerID();
            //req.sign = TestRightSign ? _sign : "00";
            req.sign = _sign;
            req.Send();
        }

        //发送已经设置了sign成功的消息
        public void SendReqSetReconnectSignSuccess()
        {
            //收到sign就要告诉服务器
            MSG_heart.ReqSetReconnectSignSuccess req = new MSG_heart.ReqSetReconnectSignSuccess();
            req.Send();
        }

        //断线重连需要用到的sign值,每10分钟刷新这个值,随后重连用这个值
        public void GS2U_ResReconnectSign(MSG_heart.ResReconnectSign result)
        {
            //Debug.LogError("接收到:sign=" + result.sign);
            _sign = result.sign;
            SendReqSetReconnectSignSuccess();
        }

        //断线重连失败
        public void GS2U_ResHeartFailed(MSG_heart.ResHeartFailed result)
        {
            //设置全局标志当前不在重连了
            GameGlobalData.IsReconnecting = false;
            //重连成功
            if (result.reason == 0)
            {
                Debug.LogError("3.1 接受到服务器的断线重连成功");
                _state = ReconnectStateCode.ReconnectSuccess;
                //可以心跳
                GameCenter.HeartSystem.EnabelHeartMsg(true);
                //关闭重连界面
                GameCenter.EventManager.PushFixEvent((int)UIEventDefine.UI_RECONNECTFORM_CLOSE);

                if (result.mapModelId == GameCenter.ReconnectSystem.LastMapId ||
                    result.mapModelId == -1)
                {
                    Debug.Log("3.1.1 断线重连成功,最后的地图与重连返回的服务器地图相同,当前地图ID: " + result.mapModelId);
                    //断线重连,如果没有切换地图,需要向服务器发送loadFinish消息
                    NetHandler.SendMessage_ReqLoadFinish();
                }
                else
                {
                    Debug.Log(string.Format("3.1.2 断线重连成功, 最后的地图与重连返回的服务器地图不同, mapModleId={0} my saved mapId={1}", result.mapModelId, GameCenter.ReconnectSystem.LastMapId));
                    //GameCenter.GameSceneSystem.StartChangeToMap(result.mapModelId, result.lineId, new Vector2(LastPlayerPos.x, LastPlayerPos.z));
                }

                GameCenter.PushFixEvent(Global.LogicEventDefine.EID_EVENT_RECONNECT_SUCCESS);
            }
            else
            {
                _state = ReconnectStateCode.ReconnectFail;
                Debug.LogError("3.2 接受到服务器的断线重连失败! reason:" + result.reason.ToString());
            }
        }

        #endregion

        #endregion

        #region//保护类型的方法
        //心跳处理
        protected override bool OnUpdate(float deltaTime)
        {
            if (!_enable) return true;
            switch (_state)
            {
                case ReconnectStateCode.StartReconnect:
                    {
                        //等待判断是否可以进行重连
                        _state = ReconnectStateCode.WaitCheckReconnect;
                        StartupReconnect();
                    }
                    break;
                case ReconnectStateCode.ReconnectSocketCD:
                    {
                        _waitTime -= deltaTime;
                        if (_waitTime <= 0)
                        {
                            _state = ReconnectStateCode.StartConnectSocket;
                        }
                    }
                    break;
                case ReconnectStateCode.StartConnectSocket:
                    {
                        StartConnectSocket();
                    }
                    break;
                case ReconnectStateCode.SocketConnectSuccess:
                    {
                        //等待网络消息,或者直接退出到登陆
                        _state = ReconnectStateCode.WaitNetMessage;
                        ReconnectSocketSuccess();
                        _waitTime = CN_NET_MESSAGE_WAIT_TIME;
                    }
                    break;
                case ReconnectStateCode.WaitNetMessage:
                    {//等待网络消息,如果超时,表示连接失败
                        _waitTime -= deltaTime;
                        if (_waitTime <= 0)
                        {
                            _state = ReconnectStateCode.WaitNetMessageFail;
                        }
                    }
                    break;
                case ReconnectStateCode.WaitNetMessageFail:
                case ReconnectStateCode.SocketConnectFail:
                case ReconnectStateCode.ReconnectFail:
                    {
                        ProcessFail(_state);
                        GameCenter.PushFixEvent(UIEventDefine.UI_RECONNECTFORM_OPEN);

                    }
                    break;
            }
            return true;
        }

        #endregion


        #region //私有函数

        //0.监控网络状态
        private void OnMonitorSocketState(int code)
        {
            //Socket断开,只有在空闲的情况下,才会去重新开始连,其他情况表示正在进行重连操作.所以不做开始处理重连处理.
            if (_enable && (_state == ReconnectStateCode.Idle || _state == ReconnectStateCode.ReconnectSuccess))
            {
                LastMapId = -1;
                LastPlayerPos = Vector3.zero;
                _state = ReconnectStateCode.StartReconnect;
                GameGlobalData.IsReconnecting = true;
            }
            else if (_state == ReconnectStateCode.WaitNetMessage)
            {
                //如果当前是等待网络消息,那么直接重连失败.
                _state = ReconnectStateCode.ReconnectFail;
            }
            else
            {
                Debug.LogError("0.0.不能进行重连,因为当前重连状态:" + _state.ToString()+";;;enable:"+ _enable);
                //如果是创建角色界面,直接打开退出界面
                if (GameCenter.FormStateSystem.FormIsOpenByEventID((int)UIEventDefine.UICREATEPLAYERFORM_OPEN))
                {
                    _state = ReconnectStateCode.WaitExitReconnect;
                    _remainCount = 0;
                    GameCenter.EventManager.PushFixEvent((int)UIEventDefine.UI_RECONNECTFORM_OPEN, null, null, null, false, 0);
                    
                }
            }
        }


        //1开启断线重连
        private void StartupReconnect()
        {
            //1.1.判断是否开启重连
            if (CheckReconnectCondition())
            {//打开重连界面
                //初始化尝试次数
                _remainCount = CN_RECONNECT_TRY_COUNT;
                //1.1.1 记录当前场景ID
                if (GameCenter.GameSceneSystem.ActivedScene != null)
                    LastMapId = GameCenter.GameSceneSystem.ActivedScene.MapId;

                //1.1.2 记录角色的位置
                if (GameCenter.GameSceneSystem.GetLocalPlayer() != null)
                    LastPlayerPos = GameCenter.GameSceneSystem.GetLocalPlayer().Position;

                Debug.Log("1.1 启动断线重连");
                _state = ReconnectStateCode.ReconnectSocketCD;
                _waitTime = CN_SOCKET_CONNECT_WAIT_TIME;
                _remainCount = CN_RECONNECT_TRY_COUNT;
                //GameCenter.EventManager.PushFixEvent((int)UIEventDefine.UI_RECONNECTFORM_OPEN);
            }
            else
            {//重连条件不足,弹出返回登陆的对话框   

                Debug.Log("1.2 断线重连启动失败,打开返回登陆对话框!");
                _remainCount = 0;
                _state = ReconnectStateCode.WaitExitReconnect;
                GameCenter.PushFixEvent(UIEventDefine.UI_RECONNECTFORM_OPEN);
              
            }
        }

        //1.1判断重连条件
        private bool CheckReconnectCondition()
        {
            if (string.IsNullOrEmpty(_sign))
            {
                Debug.LogError("1.0.当前Sign值为空,不能进行重连");
                return false;
            }

            if (GameCenter.GameStateSystem == null || GameCenter.GameStateSystem.GetCurState() == null)
            {
                Debug.LogError("1.0.游戏状态还没有开启,不能进行重连");
                return false;
            }

            if (GameCenter.GameStateSystem.GetCurState().GetStateId() != (int)GameStateId.World)
            {
                Debug.LogError("1.0.游戏状态还没有在World中,不能进行重连.");
                return false;
            }

            if (GameCenter.GameSceneSystem.GetLocalPlayer() == null)
            {
                Debug.LogError("1.0.主角信息没有加载,不能进行重连.");
                return false;
            }
            return true;
        }

        //2.0 进行Socket重连
        private void StartConnectSocket()
        {

            //socket连接成功的状态,直接跳过
            if (GameCenter.Networker.IsConnected)
            {
                //如果当前网络是连接状态,那么就直接发送重连消息
                Debug.Log("2.1.2 当前网络状态是连接状态,直接判断连接socket成功!");
                _state = ReconnectStateCode.SocketConnectSuccess;
                return;
            }
            else
            {
                Debug.Log("2.0 重连Socket");
                _state = ReconnectStateCode.WaitSocketConnecting;
                //断线重连第一步,把Socket先连上,后面才能发送消息
                GameCenter.Networker.Connect(
                    _result =>
                    {

                        if (_result)
                        {
                            UnityEngine.Debug.Log("2.1 重新连接Socket成功!");
                            _state = ReconnectStateCode.SocketConnectSuccess;
                        }
                        else
                        {
                            UnityEngine.Debug.Log("2.2.重新连接Socket失败!");
                            _state = ReconnectStateCode.SocketConnectFail;
                        }
                    });
            }

        }

        //3. 重连Socket尝试完成,发送断线消息
        private void ReconnectSocketSuccess()
        {
            GameCenter.GameSceneSystem.ActivedScene.Entities.RemoveAllRemoteObjects();
            GameCenter.GameSceneSystem.GetLocalPlayer().ClearStrikeBackCharacter();
            Debug.LogError("3.0 往服务器发送断线重连请求.");
            GameCenter.Networker.StartThread();
            //发送断线重连消息
            SendReqReconnect();
        }

        //4.socket连接失败或者
        private void ProcessFail(ReconnectStateCode failCode)
        {
            Debug.LogErrorFormat("4.0上次重连失败,失败原因:{0},重连剩余次数:{1}", failCode.ToString(), _remainCount);
            if (_remainCount > 0)
            {
                //如果失败,就继续进行连接
                _state = ReconnectStateCode.ReconnectSocketCD;
                _waitTime = CN_SOCKET_CONNECT_WAIT_TIME;
                _remainCount--;
                GameCenter.PushFixEvent(UIEventDefine.UI_RECONNECTFORM_OPEN);
            }
            else
            {
                
                Debug.LogError("4.0重连次数使用完毕,返回登陆");
                _state = ReconnectStateCode.WaitExitReconnect;
                Networker.Instance.Disconnect(false);
                GameCenter.PushFixEvent(UIEventDefine.UI_RECONNECTFORM_OPEN);
            }
        }

        #endregion


        #region//私有枚举
        //重连状态
        private enum ReconnectStateCode
        {

            //空闲,没有进行重连过
            Idle,
            //开始重连
            StartReconnect,
            //等待判断是否可以重连
            WaitCheckReconnect,
            //等待Socket的连接的CD
            ReconnectSocketCD,
            //开始Socket的连接
            StartConnectSocket,
            //等待Socket正在连接
            WaitSocketConnecting,
            //Socket连接成功
            SocketConnectSuccess,
            //连接失败
            SocketConnectFail,
            //等待网络消息
            WaitNetMessage,
            //等待网络消息失败
            WaitNetMessageFail,
            //重连成功
            ReconnectSuccess,
            //重连失败
            ReconnectFail,
            //等待退出连接
            WaitExitReconnect,
        }
        #endregion
    }
}