#nullable enable
using System;
using System.Buffers.Binary;

namespace IGP.Multiplayer.Protocol
{
    internal readonly struct IGPReliableHeartbeatPayload
    {
        public IGPReliableHeartbeatPayload(byte version, uint sequence)
        {
            Version = version;
            Sequence = sequence;
        }

        public byte Version { get; }
        public uint Sequence { get; }
    }

    internal static class IGPReliableHeartbeatPayloadCodec
    {
        public const byte Version1 = 1;
        public const int Version1Size = 5;

        public static byte[] EncodeV1(uint sequence)
        {
            var payload = new byte[Version1Size];
            payload[0] = Version1;
            BinaryPrimitives.WriteUInt32BigEndian(payload.AsSpan(1, 4), sequence);
            return payload;
        }

        public static byte[] Encode(IGPReliableHeartbeatPayload payload)
        {
            if (payload.Version != Version1)
            {
                throw new InvalidOperationException($"Reliable heartbeat payload version {payload.Version} is unsupported.");
            }
            return EncodeV1(payload.Sequence);
        }

        public static IGPReliableHeartbeatPayload Decode(byte[] payload)
        {
            if (payload == null || payload.Length == 0)
            {
                throw new InvalidOperationException("Reliable heartbeat payload version is missing.");
            }
            if (payload[0] != Version1)
            {
                throw new InvalidOperationException($"Reliable heartbeat payload version {payload[0]} is unsupported.");
            }
            if (payload.Length != Version1Size)
            {
                throw new InvalidOperationException($"Reliable heartbeat payload V1 must be {Version1Size} bytes.");
            }
            return new IGPReliableHeartbeatPayload(
                Version1,
                BinaryPrimitives.ReadUInt32BigEndian(payload.AsSpan(1, 4)));
        }
    }
}
