using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Library.Common.Event;
using Milimoe.FunGame.Core.Library.Constant;
using Milimoe.FunGame.Core.Library.Exception;
using Milimoe.FunGame.Desktop.Controller;
using Milimoe.FunGame.Desktop.Library;
using Milimoe.FunGame.Desktop.Library.Component;
using Milimoe.FunGame.Desktop.Library.Interface;
using Milimoe.FunGame.Desktop.UI;

namespace Milimoe.FunGame.Desktop.Model
{
    public class MainModel : IMain
    {
        public bool Connected => Socket != null && Socket.Connected;

        private readonly Main Main;
        private Task? ReceivingTask;
        private Core.Library.Common.Network.Socket? Socket;

        public MainModel(Main main)
        {
            Main = main;
        }

        public bool Logout()
        {
            try
            {
                //Socket?.Send(SocketMessageType.Logout, "");
            }
            catch (Exception e)
            {
                Main.GetMessage(e.GetErrorInfo());
            }
            return false;
        }

        public void Disconnect()
        {
            try
            {
                if (Socket?.Send(SocketMessageType.Disconnect, "") == SocketResult.Success)
                {
                    Main.OnSucceedDisconnectEvent(new GeneralEventArgs());
                }
            }
            catch (Exception e)
            {
                Main.GetMessage(e.GetErrorInfo());
                Main.OnFailedDisconnectEvent(new GeneralEventArgs());
            }
        }

        public void Disconnected()
        {
            Disconnect();
        }

        public bool GetServerConnection()
        {
            try
            {
                // 获取服务器IP
                string? ipaddress = (string?)Implement.GetFunGameImplValue(InterfaceType.IClient, InterfaceMethod.RemoteServerIP);
                if (ipaddress != null)
                {
                    string[] s = ipaddress.Split(':');
                    if (s != null && s.Length > 1)
                    {
                        Constant.Server_Address = s[0];
                        Constant.Server_Port = Convert.ToInt32(s[1]);
                        if (Connect() == ConnectResult.Success) return true; // 连接服务器
                    }
                }
                else
                {
                    ShowMessage.ErrorMessage("查找可用的服务器失败！");
                    Config.FunGame_isRetrying = false;
                    throw new FindServerFailedException();
                }
            }
            catch (Exception e)
            {
                Main.GetMessage(e.GetErrorInfo(), TimeType.None);
            }

            return false;
        }

        public ConnectResult Connect()
        {
            if (Constant.Server_Address == "" || Constant.Server_Port <= 0)
            {
                ShowMessage.ErrorMessage("查找可用的服务器失败！");
                return ConnectResult.FindServerFailed;
            }
            try
            {
                if (Config.FunGame_isRetrying)
                {
                    Main.GetMessage("正在连接服务器，请耐心等待。");
                    Config.FunGame_isRetrying = false;
                    return ConnectResult.CanNotConnect;
                }
                if (!Config.FunGame_isConnected)
                {
                    Main.CurrentRetryTimes++;
                    if (Main.CurrentRetryTimes == 0) Main.GetMessage("开始连接服务器...", TimeType.General);
                    else Main.GetMessage("第" + Main.CurrentRetryTimes + "次重试连接服务器...");
                    // 超过重连次数上限
                    if (Main.CurrentRetryTimes + 1 > Main.MaxRetryTimes)
                    {
                        throw new CanNotConnectException();
                    }
                    // 与服务器建立连接
                    Socket?.Close();
                    Config.FunGame_isRetrying = true;
                    Socket = Core.Library.Common.Network.Socket.Connect(Constant.Server_Address, Constant.Server_Port);
                    if (Socket != null && Socket.Connected)
                    {
                        // 设置可复用Socket
                        RunTime.Socket = Socket;
                        // 发送连接请求
                        if (Socket.Send(SocketMessageType.Connect) == SocketResult.Success)
                        {
                            Task t = Task.Factory.StartNew(() =>
                            {
                                if (Receiving() == SocketMessageType.Connect)
                                {
                                    Main.GetMessage("连接服务器成功，请登录账号以体验FunGame。");
                                    Main.UpdateUI(MainSet.Connected);
                                    StartReceiving();
                                }
                            });
                            return ConnectResult.Success;
                        }
                        Socket?.Close();
                        Config.FunGame_isRetrying = false;
                        throw new CanNotConnectException();
                    }
                }
                else
                {
                    Main.GetMessage("已连接至服务器，请勿重复连接。");
                    return ConnectResult.CanNotConnect;
                }
            }
            catch (Exception e)
            {
                Main.GetMessage(e.GetErrorInfo(), TimeType.None);
                Main.UpdateUI(MainSet.SetRed);
                Config.FunGame_isRetrying = false;
                return ConnectResult.ConnectFailed;
            }
            return ConnectResult.CanNotConnect;
        }

        public bool Close()
        {
            try
            {
                if (Socket != null)
                {
                    Socket.Close();
                    Socket = null;
                }
                if (ReceivingTask != null && !ReceivingTask.IsCompleted)
                {
                    ReceivingTask.Wait(1);
                    ReceivingTask = null;
                }
            }
            catch (Exception e)
            {
                Main.GetMessage(e.GetErrorInfo(), TimeType.None);
                return false;
            }
            return true;
        }

        public void SetWaitConnectAndSetYellow()
        {
            throw new NotImplementedException();
        }

        public void SetWaitLoginAndSetYellow()
        {
            throw new NotImplementedException();
        }

        public void SetGreenAndPing()
        {
            throw new NotImplementedException();
        }

        public void SetGreen()
        {
            throw new NotImplementedException();
        }

        public void SetYellow()
        {
            throw new NotImplementedException();
        }

        public void SetRed()
        {
            throw new NotImplementedException();
        }

        public void SetUser()
        {
            throw new NotImplementedException();
        }

        public bool LogOut()
        {
            throw new NotImplementedException();
        }

        private void StartReceiving()
        {
            ReceivingTask = Task.Factory.StartNew(() =>
            {
                Thread.Sleep(100);
                while (Socket != null && Socket.Connected)
                {
                    Receiving();
                }
            });
            Socket?.StartReceiving(ReceivingTask);
        }

        private object[] GetServerMessage()
        {
            if (Socket != null && Socket.Connected)
            {
                return Socket.Receive();
            }
            return new object[2] { SocketMessageType.Unknown, Array.Empty<object>() };
        }

        private SocketMessageType Receiving()
        {
            if (Socket is null) return SocketMessageType.Unknown;
            SocketMessageType result = SocketMessageType.Unknown;
            try
            {
                object[] ServerMessage = GetServerMessage();
                SocketMessageType type = (SocketMessageType)ServerMessage[0];
                object[] objs = (object[])ServerMessage[1];

                result = type;
                switch (type)
                {
                    case SocketMessageType.Connect:
                        SocketHandler_Connect(objs);
                        break;

                    case SocketMessageType.GetNotice:
                        SocketHandler_GetNotice(objs);
                        break;

                    case SocketMessageType.Login:
                        SocketHandler_Login(objs);
                        break;

                    case SocketMessageType.CheckLogin:
                        SocketHandler_CheckLogin(objs);
                        break;

                    case SocketMessageType.Logout:
                        break;

                    case SocketMessageType.Disconnect:
                        SocketHandler_Disconnect(objs);
                        break;

                    case SocketMessageType.HeartBeat:
                        if (Socket.Connected && Usercfg.LoginUser != null)
                            Main.UpdateUI(MainSet.SetGreenAndPing);
                        break;

                    case SocketMessageType.Unknown:
                    default:
                        break;
                }
            }
            catch (Exception e)
            {
                // 报错中断服务器连接
                Main.GetMessage(e.GetErrorInfo(), TimeType.None);
                Main.UpdateUI(MainSet.Disconnected);
                Main.OnFailedConnectEvent(new GeneralEventArgs());
                Close();
            }

            return result;
        }

        private void SocketHandler_Connect(object[] objs)
        {
            string msg = "";
            if (objs.Length > 0) msg = NetworkUtility.ConvertJsonObject<string>(objs[0])!;
            string[] strings = msg.Split(';');
            string ServerName = strings[0];
            string ServerNotice = strings[1];
            Config.FunGame_ServerName = ServerName;
            Config.FunGame_Notice = ServerNotice;
            if (objs.Length > 1) msg = NetworkUtility.ConvertJsonObject<string>(objs[1])!;
            Socket!.Token = msg;
            Main.GetMessage($"已连接服务器：{ServerName}。\n\n********** 服务器公告 **********\n\n{ServerNotice}\n\n");
            // 设置等待登录的黄灯
            Main.UpdateUI(MainSet.WaitLoginAndSetYellow);
        }

        private void SocketHandler_GetNotice(object[] objs)
        {
            if (objs.Length > 0) Config.FunGame_Notice = NetworkUtility.ConvertJsonObject<string>(objs[0])!;
        }

        private void SocketHandler_Login(object[] objs)
        {
            Guid key = Guid.Empty;
            // 返回一个Key，再发回去给服务器就行了
            if (objs.Length > 0) key = NetworkUtility.ConvertJsonObject<Guid>(objs[0])!;
            LoginController.CheckLogin(key);
        }
        
        private void SocketHandler_CheckLogin(object[] objs)
        {
            string msg = "";
            // 返回的objs是该Login的User对象的各个属性
            if (objs.Length > 0) msg = NetworkUtility.ConvertJsonObject<string>(objs[0])!;
            Main.GetMessage(msg);
            Main.UpdateUI(MainSet.SetUser, new object[] { Factory.New<User>(msg) });
        }

        private void SocketHandler_Disconnect(object[] objs)
        {
            string msg = "";
            if (objs.Length > 0) msg = NetworkUtility.ConvertJsonObject<string>(objs[0])!;
            Main.GetMessage(msg);
            Main.UpdateUI(MainSet.Disconnect);
            Close();
        }
    }
}
