namespace RioJoy.Core.Protocol;

/// <summary>
/// The RIO firmware version from a <see cref="RioCommand.VersionReply"/>
/// (port of <c>VersionReply</c>, riovjoy2.cpp#L1484: payload is [major, minor]).
/// </summary>
public readonly struct VersionInfo
{
    public byte Major { get; }
    public byte Minor { get; }

    public VersionInfo(byte major, byte minor)
    {
        Major = major;
        Minor = minor;
    }

    /// <summary>Decode a <see cref="RioCommand.VersionReply"/> payload (2 bytes).</summary>
    public static VersionInfo Parse(byte[] payload)
    {
        Require(payload, RioCommand.VersionReply);
        return new VersionInfo(payload[0], payload[1]);
    }

    public override string ToString() => $"{Major}.{Minor}";

    internal static void Require(byte[] payload, RioCommand command)
    {
        if (payload is null) throw new ArgumentNullException(nameof(payload));
        int expected = RioCommandTable.PayloadLength(command);
        if (payload.Length != expected)
            throw new ArgumentException(
                $"{command} payload must be {expected} bytes.", nameof(payload));
    }
}

/// <summary>
/// A board/lamp status item from a <see cref="RioCommand.CheckReply"/>
/// (port of <c>CheckReply</c>, riovjoy2.cpp#L1303: payload is [statusType, number]).
/// The <see cref="Number"/> is a board number, lamp number, or counter depending
/// on <see cref="Type"/>.
/// </summary>
public readonly struct CheckStatus
{
    public RioStatusType Type { get; }
    public byte Number { get; }

    public CheckStatus(RioStatusType type, byte number)
    {
        Type = type;
        Number = number;
    }

    /// <summary>Decode a <see cref="RioCommand.CheckReply"/> payload (2 bytes).</summary>
    public static CheckStatus Parse(byte[] payload)
    {
        VersionInfo.Require(payload, RioCommand.CheckReply);
        return new CheckStatus((RioStatusType)payload[0], payload[1]);
    }

    public override string ToString() => $"{Type}:{Number}";
}
