using System;

namespace OkonaPad.Networking.Binary
{
    public enum MessageType : byte
    {
        Button = 0,
        Dpad = 1,
        Joystick = 2,
        Join = 3,
        Pong = 4,
        Rumble = 5
    }

    public enum ButtonCode : byte
    {
        A = 0,
        B = 1,
        X = 2,
        Y = 3,
        Start = 4,
        Select = 5
    }

    public enum DpadDirection : byte
    {
        Up = 0,
        Down = 1,
        Left = 2,
        Right = 3
    }

    public static class BinaryProtocolHelper
    {
        private const float JoystickScale = 32767f;

        // Convert big-endian bytes to host order
        public static ushort ReadUInt16BigEndian(byte[] buffer, int offset)
        {
            if (buffer == null || offset + 2 > buffer.Length)
                throw new ArgumentException("Buffer too small for UInt16");

            return (ushort)((buffer[offset] << 8) | buffer[offset + 1]);
        }

        public static short ReadInt16BigEndian(byte[] buffer, int offset)
        {
            if (buffer == null || offset + 2 > buffer.Length)
                throw new ArgumentException("Buffer too small for Int16");

            return (short)((buffer[offset] << 8) | buffer[offset + 1]);
        }

        // Convert host order to big-endian bytes
        public static void WriteUInt16BigEndian(byte[] buffer, int offset, ushort value)
        {
            if (buffer == null || offset + 2 > buffer.Length)
                throw new ArgumentException("Buffer too small for UInt16");

            buffer[offset] = (byte)(value >> 8);
            buffer[offset + 1] = (byte)(value & 0xFF);
        }

        public static float JoystickInt16ToFloat(short value)
        {
            return value / JoystickScale;
        }

        public static byte[] CreateJoinMessage()
        {
            var buffer = new byte[3]; // 2 (length) + 1 (type)
            WriteUInt16BigEndian(buffer, 0, 1); // Length = type(1) only
            buffer[2] = (byte)MessageType.Join;
            return buffer;
        }

        public static byte[] CreateRumbleMessage(int durationMs)
        {
            var buffer = new byte[5]; // 2 (length) + 1 (type) + 2 (payload)
            WriteUInt16BigEndian(buffer, 0, 3); // Length = type(1) + payload(2)
            buffer[2] = (byte)MessageType.Rumble;
            WriteUInt16BigEndian(buffer, 3, (ushort)Math.Min(durationMs, ushort.MaxValue));
            return buffer;
        }
    }
}