using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using UnityEngine;
using ZSocket;

public static class SimpleSocketManager
{
    public const int RPC_TIME_OUT_PERIOD = 50_000_000;
    public const int RECV_TIME_OUT_PERIOD = 150_000_000;

    static SocketHandler s_Handler = null;
    static DispatchSystem s_Dispatcher = new DispatchSystem();
    static long s_RpcTimer;
    static long s_LastRecvTime;
    static string s_IpAddress;
    static int s_Port;

    /// <summary>
    /// 保存最近一次发生错误的错误码
    /// </summary>
    public static int ErrorCode { get; private set; }

    /// <summary>
    /// 连接
    /// </summary>
    /// <param name="ipAddress">IP 地址</param>
    /// <param name="port">端口</param>
    public static void Connect(string ipAddress, int port)
    {
        if (s_Handler != null)
        {
            ZLog.Log.Warning("SimpleSocket 存在未断开的会话，断开会话");
            SocketManager.Disconnect(s_Handler);
        }

        s_IpAddress = ipAddress;
        s_Port = port;
        try
        {
            IPEndPoint targetEndPoint = new IPEndPoint(IPAddress.Parse(s_IpAddress), s_Port);

            ErrorCode = ZSocket.ErrorCode.ERR_Success;

            s_Handler = SocketManager.Connect(targetEndPoint);
            s_Handler.RecvCallback = OnReceive;
            s_Handler.ErrCallback = OnError;

            s_LastRecvTime = DateTime.Now.Ticks;
            s_RpcTimer = DateTime.Now.Ticks + RPC_TIME_OUT_PERIOD;
        }
        catch (Exception e)
        {
            ZLog.Log.Error(e.ToString());
        }
    }

    /// <summary>
    /// 断开连接
    /// </summary>
    public static void Disconnect()
    {
        SocketManager.Disconnect(s_Handler);
        s_Handler = null;
        s_Dispatcher.ClearAllRpc(ZSocket.ErrorCode.ERR_PeerDisconnect);
    }

    /// <summary>
    /// 更新，发送缓冲的信息，解析接受到的信息
    /// </summary>
    /// <returns>true为正常连接， false为已断开连接</returns>
    public static int Update()
    {
        if (s_IpAddress == null)
        {
            ZLog.Log.Debug("SimpleSocket 会话未开始");
            return ErrorCode = ZSocket.ErrorCode.ERR_ConnectionNotStarted;
        }
        else if (s_Handler == null || s_Handler.Disposed)
        {
            ZLog.Log.Debug("SimpleSocket 会话已销毁");
            return ErrorCode = ZSocket.ErrorCode.ERR_ConnectionDisposed;
        }

        long nowTime = DateTime.Now.Ticks;

        if (nowTime - s_LastRecvTime > RECV_TIME_OUT_PERIOD)
        {
            ZLog.Log.Debug("SimpleSocket 会话超时断开连接");
            Disconnect();
            return ErrorCode = ZSocket.ErrorCode.ERR_RecvTimeout;
        }

        SocketManager.Tick();

        if (nowTime > s_RpcTimer)
        {
            s_Dispatcher.TimeOutClean();
            s_RpcTimer = DateTime.Now.Ticks + RPC_TIME_OUT_PERIOD;
        }

        return ZSocket.ErrorCode.ERR_Success;
    }

    /// <summary>
    /// 发送信息, 不需要回复
    /// </summary>
    /// <param name="msgType">信息类型</param>
    /// <param name="msg">信息正文内容</param>
    /// <returns>false发送过程中发生错误，对方不会接收到信息。true为未检测到错误，但不能肯定对方成功接收</returns>
    public static void Send(string msgType, string msg)
    {
        if (s_IpAddress == null)
        {
            ZLog.Log.Debug("SimpleSocket 会话未开始");
            return;
        }
        else if (s_Handler == null || s_Handler.Disposed)
        {
            ZLog.Log.Debug("SimpleSocket 会话已销毁");
            return;
        }

        try
        {
            byte[] bytes = Encoding.UTF8.GetBytes(msg);
            s_Dispatcher.Send(s_Handler, msgType, bytes, 0, bytes.Length);
        }
        catch (Exception e)
        {
            ZLog.Log.Error(e.ToString());
        }
    }

    /// <summary>
    /// 发送RPC信息, 需要回复
    /// </summary>
    /// <param name="msgType">信息类型</param>
    /// <param name="msg">信息正文内容</param>
    /// <param name="callback">回复回调</param>
    /// <returns>false发送过程中发生错误，对方不会接收到信息。true为未检测到错误，但不能肯定对方成功接收</returns>
    public static void Call(string msgType, string msg, Action<int, string> callback)
    {
        if (s_IpAddress == null)
        {
            ZLog.Log.Debug("SimpleSocket 会话未开始");
            try
            {
                callback.Invoke(ZSocket.ErrorCode.ERR_ConnectionNotStarted, null);
            }
            catch (Exception e)
            {
                ZLog.Log.Error(e.ToString());
            }
            return;
        }
        else if (s_Handler == null || s_Handler.Disposed)
        {
            ZLog.Log.Debug("SimpleSocket 会话已销毁");
            try
            {
                callback.Invoke(ZSocket.ErrorCode.ERR_ConnectionDisposed, null);
            }
            catch (Exception e)
            {
                ZLog.Log.Error(e.ToString());
            }
            return;
        }

        try
        {
            byte[] bytes = Encoding.UTF8.GetBytes(msg);
            s_Dispatcher.Call(s_Handler, msgType, bytes, 0, bytes.Length, (int err, MemoryStream stream) =>
            {
                if (stream != null)
                {
                    string result = Encoding.UTF8.GetString(stream.GetBuffer(), (int)stream.Position, (int)(stream.Length - stream.Position));
                    callback?.Invoke(err, result);
                }
                else
                {
                    callback?.Invoke(err, null);
                }
            });
        }
        catch (Exception e)
        {
            ZLog.Log.Error(e.ToString());
        }
    }

    static void OnReceive(byte version, MemoryStream stream)
    {
        s_LastRecvTime = DateTime.Now.Ticks;
        try
        {
            s_Dispatcher.HandleRecvStream(s_Handler, version, stream);
        }
        catch (Exception e)
        {
            ZLog.Log.Error(e.ToString());
        }
    }

    static void OnError(int err)
    {
        ZLog.Log.Error($"SimpleSocket 发生错误 {err}");
        ErrorCode = err;
        s_Handler = null;
        s_Dispatcher.ClearAllRpc(err);
        Disconnect();
    }
}
