using Passer.LinearAlgebra;

namespace Passer.Control.Core
{
    public class LowLevelMessages
    {

        public static void SendSpherical(byte[] buffer, ref byte ix, Spherical v)
        {
            SendFloat16(buffer, ref ix, new float16(v.distance));
            SendAngle8(buffer, ref ix, v.direction.horizontal);
            SendAngle8(buffer, ref ix, v.direction.horizontal);
        }

        public static Spherical ReceiveSpherical(byte[] data, ref byte ix)
        {
            float distance = ReceiveFloat16(data, ref ix);
            float horizontal = ReceiveAngle8(data, ref ix);
            float vertical = ReceiveAngle8(data, ref ix);
            Spherical v = new(distance, horizontal, vertical);
            return v;
        }

        public static void SendQuat32(byte[] buffer, ref byte ix, SwingTwist s)
        {
            Quat32 q32 = Quat32.FromSwingTwist(s);
            SendQuat32(buffer, ref ix, q32);

        }
        public static void SendQuat32(byte[] buffer, ref byte ix, Quat32 q)
        {
            int qx = (int)(q.x * 127 + 128);
            int qy = (int)(q.y * 127 + 128);
            int qz = (int)(q.z * 127 + 128);
            int qw = (int)(q.w * 255);
            if (q.w < 0)
            {
                qx = -qx;
                qy = -qy;
                qz = -qz;
                qw = -qw;
            }

            buffer[ix++] = (byte)qx;
            buffer[ix++] = (byte)qy;
            buffer[ix++] = (byte)qz;
            buffer[ix++] = (byte)qw;
        }
        public static Quat32 ReceiveQuat32(byte[] data, ref byte ix)
        {
            Quat32 q = new(
                (data[ix++] - 128.0F) / 127.0F,
                (data[ix++] - 128.0F) / 127.0F,
                (data[ix++] - 128.0F) / 127.0F,
                data[ix++] / 255.0F);
            return q;
        }

        public static SwingTwist ReceiveSwingTwist(byte[] data, ref byte ix)
        {
            Quat32 q32 = ReceiveQuat32(data, ref ix);
            // UnityEngine.Quaternion q = new(q32.x, q32.y, q32.z, q32.w);
            // SwingTwist r = new(q.eulerAngles.y, q.eulerAngles.x, q.eulerAngles.z);

            SwingTwist r = SwingTwist.FromQuat32(q32);
            return r;
        }

        public static void SendAngle8(byte[] buffer, ref byte ix, float angle)
        {
            // Normalize angle
            while (angle >= 180)
                angle -= 360;
            while (angle < -180)
                angle += 360;
            buffer[ix++] = (byte)((angle / 360.0f) * 256.0f);
        }

        public static float ReceiveAngle8(byte[] data, ref byte ix)
        {
            float value = (data[ix++] * 180) / 128.0F;
            return value;
        }

        public static void SendFloat16(byte[] data, ref byte ix, float f)
        {
            float16 f16 = new(f);
            ushort binary = f16.GetBinary();
            data[ix++] = (byte)(binary >> 8);
            data[ix++] = (byte)(binary & 255);
        }
        public static void SendFloat16(byte[] data, ref byte ix, float16 f)
        {
            ushort binary = f.GetBinary();
            data[ix++] = (byte)(binary >> 8);
            data[ix++] = (byte)(binary & 255);
        }

        public static float ReceiveFloat16(byte[] data, ref byte ix)
        {
            ushort value = (ushort)(data[ix++] << 8 | data[ix++]);
            float16 f16 = new();
            f16.SetBinary(value);
            float f = f16.toFloat();
            return f;
        }
    }

}