using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace ZSocket
{
    public class Utils
    {
        public static void LogMemoryStream(MemoryStream stream)
        {
            StringBuilder sb = new StringBuilder();
            StringBuilder sb2 = new StringBuilder();
            for (int i = (int)stream.Position; i < stream.Length; ++i)
            {
                sb.Append($"{stream.GetBuffer()[i]:x2} ");

                byte b = stream.GetBuffer()[i];
                if ((b >= '!' && b <= '~'))
                {
                    sb2.Append($"{(char)b} ");
                }
                else
                {
                    sb2.Append(". ");
                }
            }
            UnityEngine.Debug.Log(sb.ToString());
            UnityEngine.Debug.Log(sb2.ToString());
        }
    }

    /// <summary>
    /// 雪花算法的UID生成器，暂时弃用
    /// </summary>
    public class SnowFlakeUidGenerator
    {
        const int VALUE_START = 10000;
        long m_Epoch2020 = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000;

        long m_Time = 0;
        uint m_Value = VALUE_START;

        public long TimeSince2020(long time)
        {
            return (time - m_Epoch2020) / 1000;
        }

        public long Generate(byte flag)
        {
            //Debug.Log((DateTime.UtcNow.Ticks / 10000).ToString());

            long time = TimeSince2020(DateTime.UtcNow.Ticks / 10000);

            if (time > m_Time)
            {
                m_Time = time;
                m_Value = VALUE_START;
            }
            else
            {
                m_Value++;
                if (m_Value > ushort.MaxValue)
                {
                    m_Time++;
                    m_Value = VALUE_START;
                }
            }

            ulong result = 0;

            result |= ((ulong)flag & byte.MaxValue) << 56;
            result |= ((ulong)m_Time & 0xFFFFFFFFFF) << 16;
            result |= ((ulong)m_Value & ushort.MaxValue);

            return (long)result;
        }
    }

    /// <summary>
    /// 从1自增的RpcId生成器
    /// </summary>
    public class IncUidGenerator
    {
        int id;
        public int generate()
        {
            return ++id;
        }
    }

    /// <summary>
    /// 循环数组缓存
    /// </summary>
    public class CircularBuffer
    {
        public int ChunkSize { get; private set; }

        public int FirstIndex { get; private set; }
        public int LastIndex { get; private set; }

        Queue<byte[]> bufferCache = new Queue<byte[]>();
        Queue<byte[]> bufferQueue = new Queue<byte[]>();

        byte[] lastBuffer;

        object writeLock = new object();
        object readLock = new object();

        public CircularBuffer(int chunkSize = 2048)
        {
            ChunkSize = chunkSize;

            AddLast();
        }

        public int Length
        {
            get
            {
                int c = 0;
                if (bufferQueue.Count == 0)
                {
                    c = 0;
                }
                else
                {
                    c = (bufferQueue.Count - 1) * ChunkSize + LastIndex - FirstIndex;
                }
                if (c < 0)
                {
                    throw new Exception($"CircularBuffer count < 0: BufferCount:{bufferQueue.Count} LastIndex:{LastIndex} FirstIndex{FirstIndex}");
                }
                return c;
            }
        }

        void AddLast()
        {
            lock (writeLock)
            {
                byte[] buffer;
                if (bufferCache.Count > 0)
                {
                    buffer = bufferCache.Dequeue();
                }
                else
                {
                    buffer = new byte[ChunkSize];
                }
                bufferQueue.Enqueue(buffer);
                lastBuffer = buffer;
            }
        }

        void RemoveFirst()
        {
            lock (readLock)
            {
                bufferCache.Enqueue(bufferQueue.Dequeue());
            }
        }

        public byte[] First
        {
            get
            {
                if (bufferQueue.Count == 0)
                {
                    AddLast();
                }
                return bufferQueue.Peek();
            }
        }

        public byte[] Last
        {
            get
            {
                if (this.bufferQueue.Count == 0)
                {
                    this.AddLast();
                }
                return lastBuffer;
            }
        }

        void InternalWriteByte(byte b)
        {
            if (LastIndex == ChunkSize)
            {
                AddLast();
                LastIndex = 0;
            }
            lock (lastBuffer)
            {
                lastBuffer[LastIndex] = b;
                LastIndex++;
            }
        }

        byte InternalReadByte()
        {
            if (FirstIndex == ChunkSize)
            {
                RemoveFirst();
                FirstIndex = 0;
            }
            lock (First)
            {
                byte ret = First[FirstIndex];
                FirstIndex++;
                return ret;
            }
        }

        public void Dump(int count)
        {
            FirstIndex += count;
            while (FirstIndex >= ChunkSize)
            {
                FirstIndex -= ChunkSize;
                RemoveFirst();
            }
        }

        public void Write(byte[] buffer, int offset, int count)
        {
            lock (writeLock)
            {
                int alreadyCopyCount = 0;
                while (alreadyCopyCount < count)
                {
                    if (LastIndex == ChunkSize)
                    {
                        AddLast();
                        LastIndex = 0;
                    }

                    // 需要拷贝总数量
                    int n = count - alreadyCopyCount;

                    lock (lastBuffer)
                    {
                        // 可以拷贝完
                        if (ChunkSize - LastIndex > n)
                        {
                            Array.Copy(buffer, alreadyCopyCount + offset, lastBuffer, LastIndex, n);
                            LastIndex += n;
                            alreadyCopyCount += n;
                        }
                        else
                        {
                            Array.Copy(buffer, alreadyCopyCount + offset, lastBuffer, LastIndex, ChunkSize - LastIndex);
                            alreadyCopyCount += ChunkSize - LastIndex;
                            LastIndex = ChunkSize;
                        }
                    }
                }
            }
        }

        public int Read(MemoryStream memoryStream, int count)
        {
            lock (readLock)
            {
                int length = Length;
                if (length < count)
                {
                    count = length;
                }

                int alreadyCopyCount = 0;
                while (alreadyCopyCount < count)
                {
                    // 需要拷贝总数量
                    int n = count - alreadyCopyCount;

                    lock (First)
                    {
                        // 可以拷贝完
                        if (ChunkSize - FirstIndex > n)
                        {
                            memoryStream.Write(First, FirstIndex, n);
                            FirstIndex += n;
                            alreadyCopyCount += n;
                        }

                        // 需要继续拷贝
                        else
                        {
                            memoryStream.Write(First, FirstIndex, ChunkSize - FirstIndex);
                            alreadyCopyCount += ChunkSize - FirstIndex;
                            FirstIndex = 0;
                            RemoveFirst();
                        }
                    }
                }
                return count;
            }
        }

        public int Read(byte[] buffer, int offset, int count)
        {
            lock (readLock)
            {
                if (buffer.Length < offset + count)
                {
                    throw new Exception($"buffer length , count, lenght{buffer.Length} offset{offset} count{count}");
                }

                int length = Length;
                if (length < count)
                {
                    count = length;
                }

                int alreadyCopyCount = 0;
                while (alreadyCopyCount < count)
                {
                    // 需要拷贝总数量
                    int n = count - alreadyCopyCount;

                    lock (First)
                    {
                        // 可以拷贝完
                        if (ChunkSize - FirstIndex > n)
                        {
                            Array.Copy(First, FirstIndex, buffer, alreadyCopyCount + offset, n);
                            FirstIndex += n;
                            alreadyCopyCount += n;
                        }

                        // 需要继续拷贝
                        else
                        {
                            Array.Copy(First, FirstIndex, buffer, alreadyCopyCount + offset, ChunkSize - FirstIndex);
                            alreadyCopyCount += ChunkSize - FirstIndex;
                            FirstIndex = 0;
                            RemoveFirst();
                        }
                    }
                }

                return count;
            }
        }

        public void WriteByte(byte b)
        {
            lock (writeLock)
            {
                InternalWriteByte(b);
            }
        }

        public byte ReadByte()
        {
            lock (readLock)
            {
                return InternalReadByte();
            }
        }

        public void WriteInt(int i)
        {
            lock (writeLock)
            {
                InternalWriteByte((byte)((i & 0xff000000) >> 24));
                InternalWriteByte((byte)((i & 0xff0000) >> 16));
                InternalWriteByte((byte)((i & 0xff00) >> 8));
                InternalWriteByte((byte)((i & 0xff)));
            }
        }

        public int ReadInt()
        {
            lock (readLock)
            {
                int ret = 0;
                ret += (int)InternalReadByte() << 24;
                ret += (int)InternalReadByte() << 16;
                ret += (int)InternalReadByte() << 8;
                ret += (int)InternalReadByte();
                return ret;
            }
        }
    }

    /// <summary>
    /// 版本1 的头构造器
    /// </summary>
    public class HeaderBuilderVersion1
    {
        public byte[] Content { get; } = new byte[512];
        public int Size { get; private set; }

        string messageType;
        Dictionary<string, string> header = new Dictionary<string, string>();

        public HeaderBuilderVersion1 SetSerializationFlag(byte flag)
        {
            Content[0] = flag;
            return this;
        }

        public HeaderBuilderVersion1 SetCompressionFlag(byte flag)
        {
            Content[1] = flag;
            return this;
        }

        public HeaderBuilderVersion1 SetReqNumber(int num)
        {
            FillInt(num, 2);
            return this;
        }

        public HeaderBuilderVersion1 SetFlag(byte flag)
        {
            Content[6] = flag;
            return this;
        }

        public HeaderBuilderVersion1 SetMessageType(string type)
        {
            messageType = type;
            return this;
        }

        public HeaderBuilderVersion1 SetHeader(string key, string value)
        {
            header.Add(key, value);
            return this;
        }

        public void Build()
        {
            int offset = 7;

            int typeLen = 0;
            if (!string.IsNullOrEmpty(messageType))
            {
                typeLen = Encoding.ASCII.GetBytes(messageType, 0, messageType.Length, Content, offset + 1);
            }
            if (typeLen > byte.MaxValue)
            {
                throw new FormatException("msg type too long");
            }
            Content[offset] = (byte)typeLen;

            offset += typeLen + 1;

            int headerLen = 0;
            if (header.Count > 0)
            {
                throw new NotImplementedException();
            }
            if (headerLen > ushort.MaxValue)
            {
                throw new FormatException("header too long");
            }
            Content[offset] = (byte)((headerLen & 0xff00) >> 8);
            Content[offset + 1] = (byte)(headerLen >> 8);

            offset += headerLen + 2;

            Size = offset;

            messageType = null;
            header.Clear();
        }

        void FillInt(int num, int offset)
        {
            Content[offset] = (byte)((num & 0xFF000000) >> 24);
            Content[offset + 1] = (byte)((num & 0xFF0000) >> 16);
            Content[offset + 2] = (byte)((num & 0xFF00) >> 8);
            Content[offset + 3] = (byte)(num & 0xFF);
        }
    }

    /// <summary>
    /// 版本1 的头解析器
    /// </summary>
    class ParserVersion1
    {
        public byte serializationFlag = 0;
        public byte compressionFlag = 0;
        public int requestNumber = 0;
        public byte flags = 0;
        public string msgType = null;
        public string header = null;
        public int contentSize;

        const int RPC_ID_SIZE = 4;
        const int MSG_TYPE_BUFF_SIZE = 256;
        const int HEADER_SIZE_SIZE = 2;
        const int HEADER_BUFF_SIZE = 256;
        const int CONTENT_SIZE_SIZE = 4;
        byte[] rpcIdBuffer = new byte[RPC_ID_SIZE];
        byte[] msgTypeBuffer = new byte[MSG_TYPE_BUFF_SIZE];
        byte[] headerSizeBuffer = new byte[HEADER_SIZE_SIZE];
        byte[] headerBuffer = new byte[HEADER_BUFF_SIZE];
        byte[] contentSizeBuffer = new byte[CONTENT_SIZE_SIZE];

        /// <summary>
        /// 解析头部
        /// </summary>
        /// <param name="stream">需要解析的字节流</param>
        public void Parse(MemoryStream stream)
        {
            serializationFlag = (byte)stream.ReadByte();
            compressionFlag = (byte)stream.ReadByte();

            stream.Read(rpcIdBuffer, 0, RPC_ID_SIZE);
            requestNumber = (rpcIdBuffer[0]) << 24 | (rpcIdBuffer[1]) << 16 | (rpcIdBuffer[2] << 8) | rpcIdBuffer[3];
            flags = (byte)stream.ReadByte();

            int typeLen = stream.ReadByte();
            stream.Read(msgTypeBuffer, 0, typeLen);
            msgType = Encoding.UTF8.GetString(msgTypeBuffer, 0, typeLen);

            stream.Read(headerSizeBuffer, 0, HEADER_SIZE_SIZE);
            int headerLen = headerSizeBuffer[0] << 8 | headerSizeBuffer[1];
            stream.Read(headerBuffer, 0, headerLen);
            header = Encoding.UTF8.GetString(headerBuffer, 0, headerLen);

            stream.Read(contentSizeBuffer, 0, CONTENT_SIZE_SIZE);
            contentSize = (contentSizeBuffer[0] << 24) | (contentSizeBuffer[1] << 16) | (contentSizeBuffer[2] << 8) | contentSizeBuffer[3];

            stream.SetLength(stream.Position + contentSize);
        }
    }
}