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

namespace PSO2SERVER.Protocol
{
    public class PacketReader : BinaryReader
    {
        private byte[] _data;    // 存储数据的字节数组
        private int _position;    // 当前读取位置
        private int _size;        // 数据的总大小

        public int Position => _position;

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

        public PacketReader(byte[] bytes) : base(new MemoryStream(bytes))
        {
        }

        public PacketReader(byte[] bytes, uint position, uint size)
            : base(new MemoryStream(bytes, (int) position, (int) size))
        {
            _data = bytes;
            _position = 0;
            _size = (int)(size);
        }

        public uint ReadMagic(uint xor, uint sub)
        {
            return (ReadUInt32() ^ xor) - sub;
        }

        public string ReadAscii(uint xor, uint sub)
        {
            var magic = ReadMagic(xor, sub);

            if (magic == 0)
            {
                return string.Empty;
            }
            var charCount = magic - 1;
            var padding = 4 - (charCount & 3);
            //Logger.Write("charCount = " + charCount + " padding = " + padding);

            var data = ReadBytes((int) charCount);
            for (var i = 0; i < padding; i++)
                ReadByte();

            return Encoding.ASCII.GetString(data);
        }

        public string ReadFixedLengthAscii(uint charCount)
        {
            var data = ReadBytes((int) charCount);
            var str = Encoding.ASCII.GetString(data);

            var endAt = str.IndexOf('\0');
            if (endAt == -1)
                return str;
            return str.Substring(0, endAt);
        }

        public string ReadUtf16(uint xor, uint sub)
        {
            var magic = ReadMagic(xor, sub);

            if (magic == 0)
            {
                return "";
            }
            var charCount = magic - 1;
            var padding = (magic & 1);

            var data = ReadBytes((int) (charCount*2));
            ReadUInt16();
            if (padding != 0)
                ReadUInt16();

            return Encoding.GetEncoding("UTF-16").GetString(data);
        }

        public string ReadFixedLengthUtf16(int charCount)
        {
            var data = ReadBytes(charCount*2);
            var str = Encoding.GetEncoding("UTF-16").GetString(data);

            var endAt = str.IndexOf('\0');
            if (endAt == -1)
                return str;
            return str.Substring(0, endAt);
        }

        public T ReadStruct<T>() where T : struct
        {
            var structBytes = new byte[Marshal.SizeOf(typeof (T))];
            Read(structBytes, 0, structBytes.Length);

            return Helper.ByteArrayToStructure<T>(structBytes);
        }

        public List<T> ReadList<T>() where T : struct
        {
            var count = ReadUInt32();
            var list = new List<T>();
            for (int i = 0; i < count; i++)
            {
                list.Add(ReadStruct<T>());
            }
            return list;
        }
        public string ReadNullableString(uint xor, uint sub)
        {
            var magic = ReadMagic(xor, sub);
            if (magic == 0)
            {
                return null;
            }

            var charCount = magic - 1;
            var data = ReadBytes((int)charCount);
            return data?.Length > 0 ? Encoding.ASCII.GetString(data) : null;
        }

        public PSOLocation ReadEntityPosition()
        {
            PSOLocation pos = new PSOLocation()
            {
                RotX = Helper.FloatFromHalfPrecision(ReadUInt16()),
                RotY = Helper.FloatFromHalfPrecision(ReadUInt16()),
                RotZ = Helper.FloatFromHalfPrecision(ReadUInt16()),
                RotW = Helper.FloatFromHalfPrecision(ReadUInt16()),
                PosX = Helper.FloatFromHalfPrecision(ReadUInt16()),
                PosY = Helper.FloatFromHalfPrecision(ReadUInt16()),
                PosZ = Helper.FloatFromHalfPrecision(ReadUInt16()),
            };

            return pos;
        }

        // 读取 Half 类型（16 位浮动点数）
        public Half ReadHalf()
        {
            // 读取 2 个字节
            byte[] bytes = ReadBytes(2);

            // 使用 System.Half 来转换字节为 Half 类型
            if (bytes.Length < 2)
            {
                throw new EndOfStreamException("Not enough data to read Half value.");
            }

            // 返回 Half 类型
            return BitConverter.ToUInt16(bytes, 0).ToHalf();
        }
    }

    // Extension method to convert UInt16 to Half
    public static class HalfExtensions
    {
        public static Half ToHalf(this ushort value)
        {
            return new Half(value);
        }
    }
}