using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using PSO2SERVER.Models;
using PSO2SERVER.Zone;

namespace PSO2SERVER.Protocol
{
    public class PacketWriter : BinaryWriter
    {
        public PacketWriter()
            : base(new MemoryStream())
        {
        }

        public PacketWriter(Stream s)
            : base(s)
        {
        }

        public void WriteMagic(uint magic, uint xor, uint sub)
        {
            var encoded = (magic + sub) ^ xor;
            Write(encoded);
        }

        public void WriteMagic(int magic, uint xor, uint sub)
        {
            uint newmagic = (uint)magic;
            WriteMagic(newmagic, xor, sub);
        }

        public void WriteAscii(string str, uint xor, uint sub)
        {
            if((str == null) || (str == "") || (str.Length == 0))
            {

                WriteMagic(0, xor, sub);
                //if (str.Length == 0)
                //{
                //}
            }
            else
            {
                // Magic, followed by string, followed by null terminator,
                // followed by padding characters if needed.
                var charCount = (uint) str.Length;
                var padding = 4 - (charCount & 3);

                WriteMagic(charCount + 1, xor, sub);
                Write(Encoding.ASCII.GetBytes(str));
                for (var i = 0; i < padding; i++)
                    Write((byte) 0);
            }
        }

        //public void WriteAscii(AsciiString str, uint xor, uint sub)
        //{
        //    if (str == null || str.Length == 0)
        //    {
        //        // 如果 AsciiString 为空或长度为 0，写入 magic，长度为 0
        //        WriteMagic(0, xor, sub);
        //    }
        //    else
        //    {
        //        // Magic, followed by string, followed by null terminator,
        //        // followed by padding characters if needed.
        //        var charCount = (uint)str.Length;
        //        var padding = (4 - (charCount + 1) % 4) % 4; // +1 用于计算 null 终结符的空间

        //        // 写入 Magic 值（charCount + 1：包括 null 终结符）
        //        WriteMagic(charCount + 1, xor, sub);

        //        // 写入字符串的字节数据
        //        Write(str.ToBytes());

        //        // 填充 null 字节以保证 4 字节对齐
        //        for (var i = 0; i < padding; i++)
        //        {
        //            Write((byte)0);
        //        }
        //    }
        //}

        public void WriteUtf16(string str, uint xor, uint sub)
        {
            if ((str == null) || (str == "") || (str.Length == 0))
            {
                WriteMagic(0, xor, sub);
            }
            else
            {
                // Magic, followed by string, followed by null terminator,
                // followed by a padding character if needed.
                var charCount = (uint) str.Length + 1;
                var padding = (charCount & 1);

                WriteMagic(charCount, xor, sub);
                Write(Encoding.GetEncoding("UTF-16").GetBytes(str));
                Write((ushort) 0);
                if (padding != 0)
                    Write((ushort) 0);
            }
        }

        public void WriteFixedLengthASCII(string str, int charCount)
        {
            var writeAmount = Math.Min(str.Length, charCount);
            var paddingAmount = charCount - writeAmount;

            if (writeAmount > 0)
            {
                var chopped = writeAmount != str.Length ? str.Substring(0, writeAmount) : str;

                Write(Encoding.GetEncoding("ASCII").GetBytes(chopped));
            }

            if (paddingAmount > 0)
            {
                for (var i = 0; i < paddingAmount; i++)
                    Write((byte) 0);
            }
        }

        public void WriteFixedLengthUtf16(string str, int charCount)
        {
            var writeAmount = Math.Min(str.Length, charCount);
            var paddingAmount = charCount - writeAmount;

            if (writeAmount > 0)
            {
                var chopped = writeAmount != str.Length ? str.Substring(0, writeAmount) : str;

                Write(Encoding.GetEncoding("UTF-16").GetBytes(chopped));
            }

            if (paddingAmount > 0)
            {
                for (var i = 0; i < paddingAmount; i++)
                    Write((ushort) 0);
            }
        }

        internal void WritePosition(PSOLocation location)
        {
            Write(Helper.FloatToHalfPrecision(location.RotX));
            Write(Helper.FloatToHalfPrecision(location.RotY));
            Write(Helper.FloatToHalfPrecision(location.RotZ));
            Write(Helper.FloatToHalfPrecision(location.RotW));
            Write(Helper.FloatToHalfPrecision(location.PosX));
            Write(Helper.FloatToHalfPrecision(location.PosY));
            Write(Helper.FloatToHalfPrecision(location.PosZ));
        }

        public void WriteAccountHeader(uint AccountId)
        {
            Write(AccountId);
            Write((uint) 0);
            Write((ushort)ObjectType.Player);
            Write((ushort) 0);
        }

        public unsafe void WriteStruct<T>(T structure) where T : struct
        {
            try
            {
                // 获取结构体的大小
                int size = Marshal.SizeOf<T>();

                // 可以开启日志记录写入操作
                //Logger.Write($"写入 {size} 字节, 结构体: {structure}");

                // 创建字节数组用于存放结构体数据
                var strArr = new byte[size];

                // 固定字节数组，以便进行结构体转换
                fixed (byte* ptr = strArr)
                {
                    // 将结构体数据写入到字节数组
                    Marshal.StructureToPtr(structure, (IntPtr)ptr, false);
                }

                // 将字节数组写入到目标位置，可能是文件、网络等
                Write(strArr);
            }
            catch (Exception ex)
            {
                // 处理错误，比如结构体转换异常或写入异常
                // Logger.Error($"WriteStruct 处理异常: {ex.Message}");
                throw new InvalidOperationException("结构体写入过程中发生错误", ex);
            }
        }


        // 新增的 WriteStructArray 方法
        public unsafe void WriteStructArray<T>(T[] structures) where T : struct
        {
            int totalSize = Marshal.SizeOf(typeof(T)) * structures.Length;
            var strArr = new byte[totalSize];

            fixed (byte* ptr = strArr)
            {
                for (int i = 0; i < structures.Length; i++)
                {
                    byte* currentPtr = ptr + (i * Marshal.SizeOf(typeof(T)));
                    Marshal.StructureToPtr(structures[i], (IntPtr)currentPtr, false);
                }
            }

            Write(strArr);
        }

        public byte[] ToArray()
        {
            var ms = (MemoryStream) BaseStream;
            return ms.ToArray();
        }

        public void WriteBytes(byte b, uint count)
        {
            for(int i = 0; i < count; i++)
            {
                Write(b);
            }
        }

        public void WriteIntArray(uint[] array)
        {
            foreach (var item in array)
            {
                Write(item);
            }
        }

        public void WriteIntArray(int[] array)
        {
            foreach (var item in array)
            {
                Write(item);
            }
        }

        public void WriteShortArray(ushort[] array)
        {
            foreach (var item in array)
            {
                Write(item);
            }
        }

        public void WriteShortArray(short[] array)
        {
            foreach (var item in array)
            {
                Write(item);
            }
        }

        public void WriteFloatArray(float[] array)
        {
            foreach (var item in array)
            {
                Write(item);
            }
        }

        public void WriteObjectHeader(ObjectHeader obj)
        {
            Write(obj.ID);
            Write(obj.Padding);
            Write((ushort)obj.ObjectType);
            Write(obj.MapID);
        }

        public void WriteObjectHeaderArray(ObjectHeader[] objlist)
        {
            foreach (var obj in objlist)
            {
                WriteObjectHeader(obj);
            }
        }

        public void WriteObjectHeaderList(List<ObjectHeader> objlist)
        {
            foreach (var obj in objlist)
            {
                WriteObjectHeader(obj);  // 直接写入每个 ObjectHeader 对象
            }
        }

        // 支持 Guid 类型
        public void WriteGuid(Guid guid)
        {
            Write(guid.ToByteArray());
        }

        // 支持 DateTime 类型
        public void WriteDateTime(DateTime dateTime)
        {
            var timestamp = new DateTimeOffset(dateTime).ToUnixTimeSeconds();
            Write(timestamp);
        }

        // 支持 List<T>
        public void WriteList<T>(IEnumerable<T> collection) where T : struct
        {
            // 判断集合是否是 FixedList<T>
            if (collection is FixedList<T> fixedList)
            {
                //Logger.Write($"{fixedList.Capacity}");
                // 遍历 FixedList 的整个容量，即使它没有满
                for (int i = 0; i < fixedList.Capacity; i++)
                {
                    WriteStruct(fixedList[i]);
                }
            }
            else
            {
                // 如果是普通的 List<T> 或其他实现了 IEnumerable<T> 的集合，正常迭代
                foreach (var item in collection)
                {
                    WriteStruct(item);
                }
            }
        }

        // 支持 2D 数组
        public void Write2DIntArray(int[,] array)
        {
            for (int i = 0; i < array.GetLength(0); i++)
            {
                for (int j = 0; j < array.GetLength(1); j++)
                {
                    Write(array[i, j]);
                }
            }
        }

        // 支持 2D 数组
        public void Write2DUIntArray(uint[,] array)
        {
            for (int i = 0; i < array.GetLength(0); i++)
            {
                for (int j = 0; j < array.GetLength(1); j++)
                {
                    Write(array[i, j]);
                }
            }
        }

        // 写入 Half 类型（16 位浮动点数）
        public void WriteHalf(Half value)
        {
            Write(Half.GetBytes(value));  // 写入 2 个字节
        }

        // 自动识别并写入枚举类型
        public void WriteEnum(object value)
        {
            // 确保传入的是枚举类型
            if (value is Enum enumValue)
            {
                // 获取枚举的底层类型（byte、int 等）
                Type underlyingType = Enum.GetUnderlyingType(value.GetType());

                // 将枚举值转换为底层类型的数值
                object underlyingValue = Convert.ChangeType(enumValue, underlyingType);

                // 根据底层类型进行写入
                if (underlyingType == typeof(byte))
                {
                    Write((byte)underlyingValue);
                }
                else if (underlyingType == typeof(short) || underlyingType == typeof(ushort))
                {
                    Write((short)underlyingValue);
                }
                else if (underlyingType == typeof(Half) || underlyingType == typeof(Half))
                {
                    WriteHalf((Half)underlyingValue);
                }
                else if (underlyingType == typeof(int) || underlyingType == typeof(uint))
                {
                    Write((int)underlyingValue);
                }
                else if (underlyingType == typeof(float))
                {
                    Write((float)underlyingValue);
                }
                else if (underlyingType == typeof(long) || underlyingType == typeof(ulong))
                {
                    Write((long)underlyingValue);
                }
                else
                {
                    throw new InvalidOperationException("Unsupported enum underlying type.");
                }
            }
            else
            {
                throw new ArgumentException("The value is not an enum type.");
            }
        }
    }
}