using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using UnityEngine;
using ZSocket;

public static class LuaSocketManager
{
    public class MsgPacket
    {
        public int requestNumber;
        public byte flags;
        public string msgType;
        public string msgData;
    }

    public const int MAX_DATA_SIZE = 2 * 1024 * 1024;

    static SnowFlakeUidGenerator uidGenerator = new SnowFlakeUidGenerator();
    static SocketHandler handler = null;
    static Queue<MsgPacket> msgBuffer = new Queue<MsgPacket>();

    static IncUidGenerator rpcIdGenerator = new IncUidGenerator();
    static HeaderBuilderVersion1 headerBuilder = new HeaderBuilderVersion1();
    static ParserVersion1 parser = new ParserVersion1();

    static byte[] dataBuffer = new byte[MAX_DATA_SIZE];

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

    public static void Connect(string ipAddress, int port)
    {
        if (handler != null)
        {
            Debug.LogWarning("LuaSocket 存在未断开的会话，断开会话");
            SocketManager.Disconnect(handler);
        }

        ErrorCode = 0;

        IPEndPoint targetEndPoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
        handler = SocketManager.Connect(targetEndPoint);
        handler.RecvCallback = OnReceive;
        handler.ErrCallback = OnError;
    }

    public static void Disconnect()
    {
        SocketManager.Disconnect(handler);
        handler = null;
    }

    /// <summary>
    /// 更新，发送缓冲的信息，解析接受到的信息
    /// </summary>
    /// <returns>错误码 0为正常连接， 非0为发生了错误，并断开了连接</returns>
    public static int Update()
    {
        if (ErrorCode != ZSocket.ErrorCode.ERR_Success)
        {
            return ErrorCode;
        }

        if (handler == null || handler.Disposed)
        {
            Debug.Log("LuaSocket 会话已中断或未开始");
            return ErrorCode = ZSocket.ErrorCode.ERR_ConnectionDisposed;
        }

        SocketManager.Tick();
        return ZSocket.ErrorCode.ERR_Success;
    }

    /// <summary>
    /// 发送信息
    /// </summary>
    /// <param name="msg">内容</param>
    /// <returns>rpcId 0:发送过程中发生错误，对方不会接收到信息。非0为未检测到错误，但不能肯定对方成功接收</returns>
    public static int Send(string msgType, string msg)
    {
        if (handler == null)
        {
            Debug.LogWarning("LuaSocket 会话不存在，确保发送信息前先调用Connect方法");
            return 0;
        }

        if (handler.Disposed)
        {
            Debug.LogWarning("LuaSocket 会话已弃用，请重新连接");
            return 0;
        }

        if (msgType == null || string.IsNullOrEmpty(msgType) || msg == null)
        {
            Debug.LogWarning("LuaSocket 参数不正确");
            return 0;
        }

        try
        {
            byte[] data = Encoding.UTF8.GetBytes(msg);
            int size = data.Length;

            int rpcId = rpcIdGenerator.generate();
            if (rpcId == 0)
            {
                rpcId = rpcIdGenerator.generate();
            }

            headerBuilder.SetReqNumber(rpcId)
                .SetFlag(0x00)
                .SetMessageType(msgType)
                .Build();

            int pos = 0;
            Array.Copy(headerBuilder.Content, 0, dataBuffer, pos, headerBuilder.Size);
            pos += headerBuilder.Size;

            dataBuffer[pos] = (byte)((size & 0xff000000) >> 24);
            dataBuffer[pos + 1] = (byte)((size & 0xff0000) >> 16);
            dataBuffer[pos + 2] = (byte)((size & 0xff00) >> 8);
            dataBuffer[pos + 3] = (byte)(size & 0xff);
            pos += 4;

            if (pos + size > MAX_DATA_SIZE)
            {
                throw new Exception($"data too long {msgType}");
            }

            Array.Copy(data, 0, dataBuffer, pos, size);
            pos += size;

            handler.Send(dataBuffer, 0, pos);
            return rpcId;
        }
        catch (Exception ex)
        {
            Debug.LogError($"LuaSocket {ex}");
            return 0;
        }
    }

    public static MsgPacket RecvMessage()
    {
        if (msgBuffer.Count == 0)
        {
            return null;
        }

        return msgBuffer.Dequeue();
    }
    
    static void OnReceive(byte version, MemoryStream stream)
    {
        if (version != 0x01)
        {
            throw new NotImplementedException();
        }

        MsgPacket msgPacket;
        try
        {
            parser.Parse(stream);
            msgPacket = new MsgPacket
            {
                requestNumber = parser.requestNumber,
                flags = parser.flags,
                msgType = parser.msgType,
                msgData = Encoding.UTF8.GetString(stream.GetBuffer(), (int)stream.Position, (int)(stream.Length - stream.Position))
            };
        }
        catch (Exception ex)
        {
            Debug.LogError($"LuaSocket {ex}");
            return;
        }
        msgBuffer.Enqueue(msgPacket);
    }

    static void OnError(int err)
    {
        Debug.LogError($"LuaSocket 发生错误 {err}");
        ErrorCode = err;
        handler = null;
        Disconnect();
    }
}
